diff --git a/.gitignore b/.gitignore index 4589c9455a..4b9a7a4cd6 100755 --- a/.gitignore +++ b/.gitignore @@ -58,6 +58,7 @@ indra/newview/search_history.txt indra/newview/teleport_history.txt indra/newview/typed_locations.txt indra/newview/vivox-runtime +indra/newview/skins/default/html/common/equirectangular/js indra/server-linux-* indra/temp indra/test/linden_file.dat diff --git a/BuildParams b/BuildParams index c5f96d5ee3..27ae40767a 100644 --- a/BuildParams +++ b/BuildParams @@ -14,7 +14,7 @@ build_docs = true build_Linux_Doxygen = true # Need viewer-build-variables as well as other shared repositories -buildscripts_shared_more_NAMEs="build_secrets build_variables" +buildscripts_shared_more_NAMEs="build_secrets build_variables git_hooks" ################################################################ #### Examples of how to set the viewer_channel #### diff --git a/autobuild.xml b/autobuild.xml index ea8a8c65cb..96fdf09086 100644 --- a/autobuild.xml +++ b/autobuild.xml @@ -378,9 +378,9 @@ archive hash - 9b8bcc3be6dbe40a04c9c81c313f70dc + b6357ef3a0ec37877a5831820f25094e url - http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/68333/658209/apr_suite-1.4.5.548882-darwin64-548882.tar.bz2 + https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/80557/759704/apr_suite-1.4.5.558565-darwin64-558565.tar.bz2 name darwin64 @@ -414,9 +414,9 @@ archive hash - 6bdf460c18ee004b41a46afc80041a92 + cb48ac069440f6dcd564cfa9fd02a4c2 url - http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/68334/658225/apr_suite-1.4.5.548882-windows-548882.tar.bz2 + https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/80556/759710/apr_suite-1.4.5.558565-windows-558565.tar.bz2 name windows @@ -426,16 +426,16 @@ archive hash - 83104bfa4dabb77cd70d185e38a95b49 + 646dc3828d9c39fb1e77c4eec44ed739 url - http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/68332/658215/apr_suite-1.4.5.548882-windows64-548882.tar.bz2 + https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/80555/759709/apr_suite-1.4.5.558565-windows64-558565.tar.bz2 name windows64 version - 1.4.5.548882 + 1.4.5.558565 boost @@ -468,9 +468,9 @@ archive hash - 3cc73623c9a976b4f8346a3837f7a916 + 35cc090d942b85c9126ceac9912d52d6 url - http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/64088/601256/boost-1.72-darwin64-545361.tar.bz2 + https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/78585/744021/boost-1.72-darwin64-557045.tar.bz2 name darwin64 @@ -492,9 +492,9 @@ archive hash - 7d4b2511976449e9a4ec7be41dc8310f + 9aa4ce32df5f5e36124c990e2d77b885 url - http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/64092/601270/boost-1.72-windows-545361.tar.bz2 + https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/78586/743982/boost-1.72-windows-557045.tar.bz2 name windows @@ -504,9 +504,9 @@ archive hash - 4ad8df0700745201cddf6b71d7b0949f + a79511c9d8b956767ebaa405155d4238 url - http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/64091/601265/boost-1.72-windows64-545361.tar.bz2 + https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/78584/743961/boost-1.72-windows64-557045.tar.bz2 name windows64 @@ -598,9 +598,9 @@ archive hash - 02e6a8207dcdaf243dcb6da19b8c3534 + 1d063cf1783e7788f17486c234adb1db url - http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/64099/601302/colladadom-2.3.545362-darwin64-545362.tar.bz2 + https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/78635/744249/colladadom-2.3.557064-darwin64-557064.tar.bz2 name darwin64 @@ -634,9 +634,9 @@ archive hash - 8a02a10fc69c8f504dc5335644db184a + e78ecf919eee01567556787c3a358d15 url - http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/64104/601313/colladadom-2.3.545362-windows-545362.tar.bz2 + https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/78637/744269/colladadom-2.3.557064-windows-557064.tar.bz2 name windows @@ -646,16 +646,80 @@ archive hash - 742180324fca7ab92b6a61a36aab4f9d + 7e63a212c8909a25236138422fe01298 url - http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/64103/601314/colladadom-2.3.545362-windows64-545362.tar.bz2 + https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/78636/744273/colladadom-2.3.557064-windows64-557064.tar.bz2 name windows64 version - 2.3.545362 + 2.3.557064 + + cubemaptoequirectangular + + copyright + Copyright (c) 2017 Jaume Sanchez Elias, http://www.clicktorelease.com + license + MIT + license_file + LICENSES/CUBEMAPTOEQUIRECTANGULAR_LICENSE.txt + name + cubemaptoequirectangular + platforms + + linux64 + + archive + + hash + eb62a7040c7579569e06e5a61a7831d5 + url + http://3p.firestormviewer.org/cubemaptoequirectangular-1.1.0-linux64-213500938.tar.bz2 + + name + darwin64 + + darwin64 + + archive + + hash + 7e4622b497bc465b01ff6d3e7e0b4214 + url + https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/89303/815402/cubemaptoequirectangular-1.1.0-darwin64-564841.tar.bz2 + + name + darwin64 + + windows + + archive + + hash + b5ea7097ae10037024b0c2b3df9812b5 + url + https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/89307/815434/cubemaptoequirectangular-1.1.0-windows-564841.tar.bz2 + + name + windows + + windows64 + + archive + + hash + ac54672e0b38f52726f5c99047c913e4 + url + https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/89306/815431/cubemaptoequirectangular-1.1.0-windows64-564841.tar.bz2 + + name + windows64 + + + version + 1.1.0 curl @@ -688,9 +752,9 @@ archive hash - f5ae57117a6518d11f49ccfbfbe0969d + 13f74f43a6363ec998569f731fd869c5 url - http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/64131/601402/curl-7.54.1.545369-darwin64-545369.tar.bz2 + https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/82637/774617/curl-7.54.1.560191-darwin64-560191.tar.bz2 name darwin64 @@ -712,9 +776,9 @@ archive hash - 51d9ce98279709854b0be5d0f450ba63 + 96dd770f246917589b776300a2d07f9e url - http://3p.firestormviewer.org/curl-7.54.1.180841943-linux64-180841943.tar.bz2 + http://3p.firestormviewer.org/curl-7.54.1.212891029-linux64-212891029.tar.bz2 name linux64 @@ -724,11 +788,11 @@ archive hash - 2796ae7b09e730a55ac03f74ed669520 + 0df99bd685dc3561ca8ea347b2921987 hash_algorithm md5 url - http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/64130/601396/curl-7.54.1.545369-windows-545369.tar.bz2 + https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/82639/774610/curl-7.54.1.560191-windows-560191.tar.bz2 name windows @@ -738,16 +802,16 @@ archive hash - a8f96e5cdb8128b23d49ff4c3f2233a4 + 50db2a9e6b74ec4b0c38b1ea8f135735 url - http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/64129/601382/curl-7.54.1.545369-windows64-545369.tar.bz2 + https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/82638/774608/curl-7.54.1.560191-windows64-560191.tar.bz2 name windows64 version - 7.54.1.545369 + 7.54.1.560191 db @@ -870,9 +934,9 @@ archive hash - 49fff41e17e06cdf9eb0c737d20df52f + 2653c3627fd8687ff9e003425fd14834 url - https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/83411/779825/dullahan-1.12.2.202106220202_91.1.21_g9dd45fe_chromium-91.0.4472.114-darwin64-560751.tar.bz2 + https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/90199/821852/dullahan-1.12.3.202111032211_91.1.21_g9dd45fe_chromium-91.0.4472.114-darwin64-565428.tar.bz2 name darwin64 @@ -882,9 +946,9 @@ archive hash - f51f324d50a2461cda273e84fa65e0ad + b4003772562a5dd40bc112eec7cba5f5 url - https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/83413/779836/dullahan-1.12.2.202106220213_91.1.21_g9dd45fe_chromium-91.0.4472.114-windows-560751.tar.bz2 + https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/90201/821871/dullahan-1.12.3.202111032221_91.1.21_g9dd45fe_chromium-91.0.4472.114-windows-565428.tar.bz2 name windows @@ -894,9 +958,9 @@ archive hash - d3df46f6592715c75df2bf520c1ad68b + d9030d7a7390b3bda7de2adcc27e535a url - https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/83412/779840/dullahan-1.12.2.202106220213_91.1.21_g9dd45fe_chromium-91.0.4472.114-windows64-560751.tar.bz2 + https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/90200/821876/dullahan-1.12.3.202111032221_91.1.21_g9dd45fe_chromium-91.0.4472.114-windows64-565428.tar.bz2 name windows64 @@ -906,16 +970,16 @@ archive hash - 7b8fd7a8ea9850f1cad187059d2da4af + 2f8fdc6950620cee3a526ede27e068aa url - http://3p.firestormviewer.org/dullahan-1.12.2.202109131147_91.1.23_g04c8d56_chromium-91.0.4472.164-linux64-212560947.tar.bz2 + http://3p.firestormviewer.org/dullahan-1.12.2.202109282040_91.1.23_g04c8d56_chromium-91.0.4472.164-linux64-212711840.tar.bz2 name linux64 version - 1.12.2.202106220213_91.1.21_g9dd45fe_chromium-91.0.4472.114 + 1.12.3.202111032221_91.1.21_g9dd45fe_chromium-91.0.4472.114 elfio @@ -972,9 +1036,9 @@ archive hash - 3656b7f7b655cb267fd94f089d2e145c + f4e80e0dfcab713a3da90cd8f7f23e7b url - http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/54860/510198/expat-2.1.1.538990-darwin64-538990.tar.bz2 + https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/76341/727265/expat-2.1.1.555519-darwin64-555519.tar.bz2 name darwin64 @@ -1008,9 +1072,9 @@ archive hash - c509f8afa1e02f4c16232cce7f6855f8 + cd4fe03473076c324d80ae3bd91a85bb url - http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/55056/512080/expat-2.1.1.538990-windows-538990.tar.bz2 + https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/76343/727273/expat-2.1.1.555519-windows-555519.tar.bz2 name windows @@ -1020,16 +1084,16 @@ archive hash - aba97cfdf44c04dbfcac89c7cb472580 + d2d74d73b914150982b1883a3b96e60b url - http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/55054/512068/expat-2.1.1.538990-windows64-538990.tar.bz2 + https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/76344/727279/expat-2.1.1.555519-windows64-555519.tar.bz2 name windows64 version - 2.1.1.538990 + 2.1.1.555519 fmodstudio @@ -1050,11 +1114,11 @@ archive hash - ab6f79c425524500d638807a3aee0115 + bde9eb3e53001584edb1af44e3b265a2 hash_algorithm md5 url - file:///opt/firestorm/fmodstudio-2.02.01-darwin-211941804.tar.bz2 + file:///opt/firestorm/fmodstudio-2.02.04-darwin-213491614.tar.bz2 name darwin @@ -1064,11 +1128,11 @@ archive hash - 1e176ba9a76fe209ce4703db2026ad85 + 225762175d2ed102e270082edc7c2e25 hash_algorithm md5 url - file:///opt/firestorm/fmodstudio-2.02.02-linux64-212130644.tar.bz2 + file:///opt/firestorm/fmodstudio-2.02.04-linux64-213452351.tar.bz2 name linux64 @@ -1078,11 +1142,11 @@ archive hash - 0335fa6ca762097c85b3090ce2614c3c + 6bb2a0ae244a87a5f73b85d938054fb5 hash_algorithm md5 url - file:///c:/cygwin/opt/firestorm/fmodstudio-2.02.02-windows-212102333.tar.bz2 + file:///c:/cygwin/opt/firestorm/fmodstudio-2.02.04-windows-213441411.tar.bz2 name windows @@ -1092,18 +1156,18 @@ archive hash - 793ba69b7a5ea8fa12ec1a86d5ebd9e2 + 82c73a8ee40c39bca782d73cb9e276e9 hash_algorithm md5 url - file:///c:/cygwin/opt/firestorm/fmodstudio-2.02.02-windows64-212102335.tar.bz2 + file:///c:/cygwin/opt/firestorm/fmodstudio-2.02.04-windows64-213441412.tar.bz2 name windows64 version - 2.02.02 + 2.02.04 fontconfig @@ -1178,9 +1242,9 @@ archive hash - 81a2e9aca3e33c4eecf0081854540b07 + 3a478d6c8a10d49d9161ef864394b03c url - http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/56309/526711/freetype-2.4.4.539865-darwin64-539865.tar.bz2 + https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/78592/744013/freetype-2.4.4.557047-darwin64-557047.tar.bz2 name darwin64 @@ -1214,9 +1278,9 @@ archive hash - 0dbb1a9d15bb134096476d657f86ce41 + 4b3b02027ec0b64c479837f57e3d4ec8 url - http://3p.firestormviewer.org/freetype-2.3.9.202022048-windows-202022048.tar.bz2 + http://3p.firestormviewer.org/freetype-2.3.9.210761651-windows-210761651.tar.bz2 name windows @@ -1226,16 +1290,16 @@ archive hash - c000d0c98bded51c7bc7447dc7934e6c + 1b3ace03dcd61fa800a186213477a5fb url - http://3p.firestormviewer.org/freetype-2.3.9.202022049-windows64-202022049.tar.bz2 + http://3p.firestormviewer.org/freetype-2.3.9.210761652-windows64-210761652.tar.bz2 name windows64 version - 2.4.4.539865 + 2.4.4.557047 glext @@ -1439,96 +1503,6 @@ version 1.0pre3.532346 - google_breakpad - - copyright - Copyright (c) 2006, Google Inc. - description - Breakpad is a crossplatform library for capturing crash callstacks and runtime data. - license - bsd - license_file - LICENSES/google_breakpad.txt - name - google_breakpad - platforms - - darwin - - archive - - hash - 171b39db6d0702535b41fad5b476e39d - url - http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/google-breakpad_3p-update-google-breakpad/rev/298033/arch/Darwin/installer/google_breakpad-1413.298033-darwin-298033.tar.bz2 - - name - darwin - - darwin64 - - archive - - hash - ca33f234aae399b9e704e262f7e15d35 - url - http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/56338/526869/google_breakpad-1413.539880-darwin64-539880.tar.bz2 - - name - darwin64 - - linux - - archive - - hash - ca43974302dc3e2019b0838c2c53b8b5 - url - http://3p.firestormviewer.org/google_breakpad-1413.202021450-linux64-202021450.tar.bz2 - - name - linux - - linux64 - - archive - - hash - ae2b368225d5705233284e08b9981a35 - url - http://3p.firestormviewer.org/google_breakpad-1413.202022149-linux64-202022149.tar.bz2 - - name - linux64 - - windows - - archive - - hash - bfee0438617f57f02f7e8515a801cb20 - url - http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/56359/526982/google_breakpad-1413.539880-windows-539880.tar.bz2 - - name - windows - - windows64 - - archive - - hash - 6f983e754bb3046f065806b510b408c5 - url - http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/56358/526975/google_breakpad-1413.539880-windows64-539880.tar.bz2 - - name - windows64 - - - version - 1413.539880 - googlemock copyright @@ -1560,9 +1534,9 @@ archive hash - f9831360ced94943ab9dfb3fbf5256d3 + 19e925604bc1a91efb4b130e1edd8bf2 url - http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/64101/601290/googlemock-1.7.0.545363-darwin64-545363.tar.bz2 + https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/78620/744140/googlemock-1.7.0.557057-darwin64-557057.tar.bz2 name darwin64 @@ -1596,9 +1570,9 @@ archive hash - 8149e46b4f7abb3ac284415cfe1366e1 + eed7b41d0d1f41b24f315349ef78c728 url - http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/64102/601296/googlemock-1.7.0.545363-windows-545363.tar.bz2 + https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/78622/744148/googlemock-1.7.0.557057-windows-557057.tar.bz2 name windows @@ -1608,16 +1582,16 @@ archive hash - f3851eba809ead2810d702041569d36d + a6ad6fe722d2fe4e8137495af3f374c9 url - http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/64100/601284/googlemock-1.7.0.545363-windows64-545363.tar.bz2 + https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/78621/744152/googlemock-1.7.0.557057-windows64-557057.tar.bz2 name windows64 version - 1.7.0.545363 + 1.7.0.557057 gstreamer @@ -1749,6 +1723,70 @@ version 2012.1-2 + jpegencoderbasic + + copyright + Andreas Ritter, www.bytestrom.eu, 11/2009 + license + NONE + license_file + LICENSES/JPEG_ENCODER_BASIC_LICENSE.txt + name + jpegencoderbasic + platforms + + linux64 + + archive + + hash + fd8060aa3c920e0fc63e7ecbea67bc5e + url + http://3p.firestormviewer.org/jpegencoderbasic-1.0-linux64-213500937.tar.bz2 + + name + darwin64 + + darwin64 + + archive + + hash + c3c9e60bdc12b35e0e3d6b67d5635f60 + url + https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/89304/815407/jpegencoderbasic-1.0-darwin64-564842.tar.bz2 + + name + darwin64 + + windows + + archive + + hash + 0a376676dbb43fdd0c81ffdfbc5e6f81 + url + https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/89308/815432/jpegencoderbasic-1.0-windows-564842.tar.bz2 + + name + windows + + windows64 + + archive + + hash + e70898903475d8ac2e81ff33278fc987 + url + https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/89309/815433/jpegencoderbasic-1.0-windows64-564842.tar.bz2 + + name + windows64 + + + version + 1.0 + jpeglib copyright @@ -2026,9 +2064,9 @@ archive hash - c327e6d6573fc0a808677de47f08acd9 + 2021ea3a19b81c82993e733709683303 url - http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/54844/510092/libhunspell-1.3.2.538974-darwin64-538974.tar.bz2 + https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/76371/727419/libhunspell-1.3.2.555528-darwin64-555528.tar.bz2 name darwin64 @@ -2062,9 +2100,9 @@ archive hash - ec22ec25160bcfd2a74f1c7bc8ff6133 + 2253ec09136cc7c208481030d78d9dd7 url - http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/54986/511824/libhunspell-1.3.2.538974-windows-538974.tar.bz2 + https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/76369/727412/libhunspell-1.3.2.555528-windows-555528.tar.bz2 name windows @@ -2074,16 +2112,16 @@ archive hash - f470c6f3f7b0559e95e76467b808de10 + 858d1708f6b3a74738a3d57a5387e20f url - http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/54985/511817/libhunspell-1.3.2.538974-windows64-538974.tar.bz2 + https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/76370/727413/libhunspell-1.3.2.555528-windows64-555528.tar.bz2 name windows64 version - 1.3.2.538974 + 1.3.2.555528 libndofdev @@ -2116,9 +2154,9 @@ archive hash - bf765dfe0b928ef3c531cd9618fee89b + a487fff84208a45844602c4a1f68c974 url - http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/54843/510085/libndofdev-0.1.538973-darwin64-538973.tar.bz2 + https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/76356/727333/libndofdev-0.1.555523-darwin64-555523.tar.bz2 name darwin64 @@ -2128,9 +2166,9 @@ archive hash - 8abb7d216535009f6c0a7e43b0734b1e + 4c839555bf0ed9ae60ffc3f8a7c96f9b url - http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/54984/511810/libndofdev-0.1.538973-windows-538973.tar.bz2 + https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/76354/727340/libndofdev-0.1.555523-windows-555523.tar.bz2 name windows @@ -2140,16 +2178,16 @@ archive hash - 9da7aed5a914174dcb2be12ecd4a656f + cbc033ae3b034b992b59f6de1034247c url - http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/54983/511803/libndofdev-0.1.538973-windows64-538973.tar.bz2 + https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/76355/727341/libndofdev-0.1.555523-windows64-555523.tar.bz2 name windows64 version - 0.1.538973 + 0.1.555523 libpng @@ -2182,9 +2220,9 @@ archive hash - 0932b19bb6a8e2641706afd13d92951d + 2a41acc3116ce19a443873216cb882ad url - http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/56313/526740/libpng-1.6.8.539868-darwin64-539868.tar.bz2 + https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/78587/743948/libpng-1.6.8.557046-darwin64-557046.tar.bz2 name darwin64 @@ -2218,9 +2256,9 @@ archive hash - f498782698428888113b64a7505c8f7f + b935b440947f63c69700bdcf5095a8e1 url - http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/56319/526770/libpng-1.6.8.539868-windows-539868.tar.bz2 + https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/78591/743970/libpng-1.6.8.557046-windows-557046.tar.bz2 name windows @@ -2230,16 +2268,16 @@ archive hash - f8ac4f690a2925418866bccf6eba3cf4 + d1cc8354ac4e877eefedf16b1be3aac6 url - http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/56317/526762/libpng-1.6.8.539868-windows64-539868.tar.bz2 + https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/78589/743991/libpng-1.6.8.557046-windows64-557046.tar.bz2 name windows64 version - 1.6.8.539868 + 1.6.8.557046 libuuid @@ -2314,9 +2352,9 @@ archive hash - 0706b9c3889d767af9f5105d9ffa9b51 + 6677173bbbb0ea32369b5e9b6c9aa641 url - http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/56327/526819/libxml2-2.9.4.539866-darwin64-539866.tar.bz2 + https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/78631/744225/libxml2-2.9.4.557062-darwin64-557062.tar.bz2 name darwin64 @@ -2350,9 +2388,9 @@ archive hash - 1b7b979a8387fbb0f278dc681558b9ef + ad6a596fbf0e83a21d95762da78437bc url - http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/56316/526755/libxml2-2.9.4.539866-windows-539866.tar.bz2 + https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/78633/744239/libxml2-2.9.4.557062-windows-557062.tar.bz2 name windows @@ -2362,16 +2400,16 @@ archive hash - 4f8ff97d6a9ab350306b62eec8adc810 + 6b5bb230684ecf28386d7c91c47bb6e1 url - http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/56314/526748/libxml2-2.9.4.539866-windows64-539866.tar.bz2 + https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/78634/744240/libxml2-2.9.4.557062-windows64-557062.tar.bz2 name windows64 version - 2.9.4.539866 + 2.9.4.557062 llappearance_utility @@ -2421,18 +2459,18 @@ archive hash - 0a6349b11c8e9d34f0c80b8081736e75 + 35f42f538f4dc3abdfc2b2c4a915d004 hash_algorithm md5 url - https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/79438/751815/llca-202104010215.557744-common-557744.tar.bz2 + https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/87228/802959/llca-202109010216.563493-common-563493.tar.bz2 name common version - 202104010215.557744 + 202109010216.563493 llphysicsextensions_source @@ -2648,9 +2686,9 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors archive hash - 937ce1a2158c0cfff37f5989f5b24aba + e4f784d8a035c51921a1562ca7a1bab6 url - http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/64066/601156/nghttp2-1.40.0.545354-darwin64-545354.tar.bz2 + https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/76357/727350/nghttp2-1.40.0.555524-darwin64-555524.tar.bz2 name darwin64 @@ -2684,9 +2722,9 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors archive hash - 138b881bdf37dff4e626e022a50dd11f + af05aa2994c9845308fecd094b7b2d25 url - http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/64069/601181/nghttp2-1.40.0.545354-windows-545354.tar.bz2 + https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/76359/727360/nghttp2-1.40.0.555524-windows-555524.tar.bz2 name windows @@ -2696,9 +2734,9 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors archive hash - c23c6480c7cbea60a2bd26e257adc0a7 + 5a55cede40eef16b9d1e47c418a2b77a url - http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/64068/601177/nghttp2-1.40.0.545354-windows64-545354.tar.bz2 + https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/76358/727359/nghttp2-1.40.0.555524-windows64-555524.tar.bz2 name windows64 @@ -2707,7 +2745,7 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors source_type hg version - 1.40.0.545354 + 1.40.0.555524 nvapi @@ -3050,9 +3088,9 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors archive hash - 18aef0c8fc471b6539addbdc019aea25 + 5503e4928bcdb0a29685b3242c4a409b url - http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/56325/526804/openssl-1.0.2l.539874-darwin64-539874.tar.bz2 + https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/82619/774464/openssl-1.1.1l.560177-darwin64-560177.tar.bz2 name darwin64 @@ -3074,9 +3112,9 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors archive hash - 7920fce93d9addf63a420d86f91c5749 + ea82e634334bccf088daf3d15eab07b7 url - http://3p.firestormviewer.org/openssl-1.0.2l.180841936-linux64-180841936.tar.bz2 + http://3p.firestormviewer.org/openssl-1.1.1l.212872015-linux64-212872015.tar.bz2 name linux64 @@ -3086,9 +3124,9 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors archive hash - 2b2f61313b1cbd2893c1ba5bf15061fa + d2153f20dc2d35c609b876a9f019a748 url - http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/56328/526826/openssl-1.0.2l.539874-windows-539874.tar.bz2 + https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/82623/774521/openssl-1.1.1l.560177-windows-560177.tar.bz2 name windows @@ -3098,16 +3136,16 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors archive hash - 59aae854155bc7119e0dca25e65828c0 + f40b8622ba38084b0962e273988d748f url - http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/56326/526811/openssl-1.0.2l.539874-windows64-539874.tar.bz2 + https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/82624/774520/openssl-1.1.1l.560177-windows64-560177.tar.bz2 name windows64 version - 1.0.2l.539874 + 1.1.1l.560177 pcre @@ -3230,33 +3268,21 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors archive hash - 321a8542e7b693fbe8e44ebface06087 + 6ce3cbaed968a69fb7a2cca80220874d url - http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/55966/524403/slvoice-4.10.0000.32327.5fc3fe7c.539691-darwin64-539691.tar.bz2 + https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/80380/758537/slvoice-4.10.0000.32327.5fc3fe7c.558436-darwin64-558436.tar.bz2 name darwin64 - linux - - archive - - hash - 6e7b0961d6489a1b3c3090eccfd6e80e - url - http://3p.firestormviewer.org/slvoice-3.2.0002.10426.298329-linux-20160717.tar.bz2 - - name - linux - linux64 archive hash - 6e7b0961d6489a1b3c3090eccfd6e80e + 05c4debd4cccfea620fc7e6f9a190924 url - http://3p.firestormviewer.org/slvoice-3.2.0002.10426.298329-linux-20160717.tar.bz2 + http://3p.firestormviewer.org/slvoice-3.2.0002.10426.302004-linux64-212691952.tar.bz2 name linux64 @@ -3266,9 +3292,9 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors archive hash - fb1a57a1cf5e38a3d51b32307b93ffba + 2eb38c5eff4d0f18fbb89d0c30c4f0a4 url - http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/55968/524423/slvoice-4.10.0000.32327.5fc3fe7c.539691-windows-539691.tar.bz2 + https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/80382/758550/slvoice-4.10.0000.32327.5fc3fe7c.558436-windows-558436.tar.bz2 name windows @@ -3278,16 +3304,80 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors archive hash - 81df970eb0c97d415d7bd12049c82042 + 9ee8f3cbc5369c598a998c61961ed16d url - http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/55967/524409/slvoice-4.10.0000.32327.5fc3fe7c.539691-windows64-539691.tar.bz2 + https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/80381/758551/slvoice-4.10.0000.32327.5fc3fe7c.558436-windows64-558436.tar.bz2 name windows64 version - 4.10.0000.32327.5fc3fe7c.539691 + 4.10.0000.32327.5fc3fe7c.558436 + + threejs + + copyright + Copyright © 2010-2021 three.js authors + license + MIT + license_file + LICENSES/THREEJS_LICENSE.txt + name + threejs + platforms + + linux64 + + archive + + hash + d37be064bd851276dab423d723cb9b7d + url + http://3p.firestormviewer.org/threejs-0.132.2-linux64-213500940.tar.bz2 + + name + darwin64 + + darwin64 + + archive + + hash + 24440e8219e59d81423b68d3be381fef + url + https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/89305/815412/threejs-0.132.2-darwin64-564843.tar.bz2 + + name + darwin64 + + windows + + archive + + hash + e1303fb9f2242a79aee5fd9f97726ace + url + https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/89311/815452/threejs-0.132.2-windows-564843.tar.bz2 + + name + windows + + windows64 + + archive + + hash + 46edf0f55417f8ef0d33a5c007bc3644 + url + https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/89310/815451/threejs-0.132.2-windows64-564843.tar.bz2 + + name + windows64 + + + version + 0.132.2 tut @@ -3350,9 +3440,9 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors archive hash - 60f008c5fd31641ad4e61ac751ce15d1 + c42575ac8997de979eadb082c33a578e url - https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/75748/723495/uriparser-0.9.4-darwin64-555117.tar.bz2 + https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/81322/765512/uriparser-0.9.4-darwin64-559132.tar.bz2 name darwin64 @@ -3386,9 +3476,9 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors archive hash - 00aff37a6f5e1fe08456702d28706cf6 + 901b1063556fc6b2575e745eef2bf744 url - https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/75751/723507/uriparser-0.9.4-windows-555117.tar.bz2 + https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/81323/765528/uriparser-0.9.4-windows-559132.tar.bz2 name windows @@ -3398,9 +3488,9 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors archive hash - ff27a91f3941c7bef5e1613a064cb048 + 962c01d553f286c430102998129fb0d6 url - https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/75750/723506/uriparser-0.9.4-windows64-555117.tar.bz2 + https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/81324/765527/uriparser-0.9.4-windows64-559132.tar.bz2 name windows64 @@ -3428,9 +3518,9 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors archive hash - 6989053898b8e81e904e75553e378820 + a3c8357a2f5a62cd7de43181b02553bc url - https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/77523/735051/viewer_manager-2.0.556340-darwin64-556340.tar.bz2 + https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/91396/829032/viewer_manager-2.0.566227-darwin64-566227.tar.bz2 name darwin64 @@ -3464,9 +3554,9 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors archive hash - 3446c1e54bb32542677caad0ec0d42ac + 0654b449d9bdf3507664cf5caa67336f url - https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/77525/735058/viewer_manager-2.0.556340-windows-556340.tar.bz2 + https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/91397/829041/viewer_manager-2.0.566227-windows-566227.tar.bz2 name windows @@ -3477,7 +3567,7 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors source_type hg version - 2.0.556340 + 2.0.566227 vlc-bin @@ -3496,9 +3586,9 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors archive hash - e5635e173c75dc0675b48ab5f5e4868b + 738688816ebd76958e49772712a6b972 url - http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/12143/71451/vlc_bin-2.2.8.511703-darwin64-511703.tar.bz2 + https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/90004/820701/vlc_bin-3.0.16.565299-darwin64-565299.tar.bz2 name darwin64 @@ -3532,9 +3622,9 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors archive hash - ca84b7c5f86e702fb35727eed8f0c8c4 + 6801f91f3f27e626898bab90d40fc1c3 url - http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/54958/511725/vlc_bin-2.2.8.538966-windows-538966.tar.bz2 + https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/90005/820712/vlc_bin-3.0.16.565299-windows-565299.tar.bz2 name windows @@ -3544,9 +3634,9 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors archive hash - 93cd88d90cb8aedbed5cd90ff9262409 + 7f66982d6edf3c38f3493e28826d58e8 url - http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/54954/511718/vlc_bin-2.2.8.538966-windows64-538966.tar.bz2 + https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/90006/820713/vlc_bin-3.0.16.565299-windows64-565299.tar.bz2 name windows64 @@ -3586,9 +3676,9 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors archive hash - 99ea1808ee9f5b55029daa9fdef86776 + 922a0dea32266897ed1911200438e1e1 url - http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/55063/512104/xmlrpc_epi-0.54.1.539072-darwin64-539072.tar.bz2 + https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/76372/727426/xmlrpc_epi-0.54.1.555529-darwin64-555529.tar.bz2 name darwin64 @@ -3622,9 +3712,9 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors archive hash - 94643b7cebb449f049fa9e32ae682bcd + 34b847e6b280048465fe7c6ce67fe05c url - http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/55138/512288/xmlrpc_epi-0.54.1.539072-windows-539072.tar.bz2 + https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/76374/727436/xmlrpc_epi-0.54.1.555529-windows-555529.tar.bz2 name windows @@ -3634,16 +3724,16 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors archive hash - c409de1974a879291ce7daaf52348d85 + 8fbe7c4ea22bb7f23a93c73884ebb34c url - http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/55137/512279/xmlrpc_epi-0.54.1.539072-windows64-539072.tar.bz2 + https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/76373/727435/xmlrpc_epi-0.54.1.555529-windows64-555529.tar.bz2 name windows64 version - 0.54.1.539072 + 0.54.1.555529 zlib @@ -3676,9 +3766,9 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors archive hash - 9785bda5b4d3b41bf391b33d0da78c9e + 9181bc8229f1a8e480d2a40a2744ec28 url - http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/54858/510190/zlib-1.2.8.538988-darwin64-538988.tar.bz2 + https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/78578/743913/zlib-1.2.11.557041-darwin64-557041.tar.bz2 name darwin64 @@ -3714,9 +3804,9 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors archive hash - ebdb07d4aaa5312005a8773f625032a4 + 8308cbd2ea0fe290541698b0f63482e2 url - http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/55048/512031/zlib-1.2.8.538988-windows-538988.tar.bz2 + https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/78579/743926/zlib-1.2.11.557041-windows-557041.tar.bz2 name windows @@ -3726,16 +3816,16 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors archive hash - 0ac95f3dece7d575ba45cf5728f53eea + 36bdc34f67d3ad3c57125dc1b16a3129 url - http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/55047/512024/zlib-1.2.8.538988-windows64-538988.tar.bz2 + https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/78577/743920/zlib-1.2.11.557041-windows64-557041.tar.bz2 name windows64 version - 1.2.8.538988 + 1.2.11.557041 package_description diff --git a/build.sh b/build.sh index 8d49e5a137..bdf36ec4e1 100755 --- a/build.sh +++ b/build.sh @@ -16,6 +16,29 @@ # * The special style in which python is invoked is intentional to permit # use of a native python install on windows - which requires paths in DOS form +retry_cmd() +{ + max_attempts="$1"; shift + initial_wait="$1"; shift + attempt_num=1 + echo "trying" "$@" + until "$@" + do + if ((attempt_num==max_attempts)) + then + echo "Last attempt $attempt_num failed" + return 1 + else + wait_time=$(($attempt_num*$initial_wait)) + echo "Attempt $attempt_num failed. Trying again in $wait_time seconds..." + sleep $wait_time + attempt_num=$(($attempt_num+1)) + fi + done + echo "succeeded" + return 0 +} + build_dir_Darwin() { echo build-darwin-x86_64 @@ -275,6 +298,22 @@ python_cmd "$helpers/codeticket.py" addinput "Viewer Channel" "${viewer_channel} initialize_version # provided by buildscripts build.sh; sets version id +begin_section "coding policy check" +# On our TC Windows build hosts, the GitPython library underlying our +# coding_policy_git.py script fails to run git for reasons we have not tried +# to diagnose. Clearly git works fine on those hosts, or we would never get +# this far. Running coding policy checks on one platform *should* suffice... +if [[ "$arch" == "Darwin" ]] +then + # install the git-hooks dependencies + pip install -r "$(native_path "$git_hooks_checkout/requirements.txt")" || \ + fatal "pip install git-hooks failed" + # validate the branch we're about to build + python_cmd "$git_hooks_checkout/coding_policy_git.py" --all_files || \ + fatal "coding policy check failed" +fi +end_section "coding policy check" + # Now run the build succeeded=true last_built_variant= @@ -444,7 +483,7 @@ then succeeded=$build_coverity else # Upload base package. - python_cmd "$helpers/codeticket.py" addoutput Installer "$package" \ + retry_cmd 4 30 python_cmd "$helpers/codeticket.py" addoutput Installer "$package" \ || fatal "Upload of installer failed" wait_for_codeticket @@ -454,7 +493,7 @@ then package=$(installer_$arch "$package_id") if [ x"$package" != x ] then - python_cmd "$helpers/codeticket.py" addoutput "Installer $package_id" "$package" \ + retry_cmd 4 30 python_cmd "$helpers/codeticket.py" addoutput "Installer $package_id" "$package" \ || fatal "Upload of installer $package_id failed" wait_for_codeticket else @@ -468,7 +507,7 @@ then if [ "${RELEASE_CRASH_REPORTING:-}" != "OFF" ] then # Upload crash reporter file - python_cmd "$helpers/codeticket.py" addoutput "Symbolfile" "$VIEWER_SYMBOL_FILE" \ + retry_cmd 4 30 python_cmd "$helpers/codeticket.py" addoutput "Symbolfile" "$VIEWER_SYMBOL_FILE" \ || fatal "Upload of symbolfile failed" wait_for_codeticket fi @@ -478,10 +517,7 @@ then if [ -r "$build_dir/llphysicsextensions_package" ] then llphysicsextensions_package=$(cat $build_dir/llphysicsextensions_package) - # This next upload is a frequent failure; see if giving the last one some time helps - # JJ is making changes to Codeticket that we hope will eliminate this failure soon - sleep 300 - python_cmd "$helpers/codeticket.py" addoutput "Physics Extensions Package" "$llphysicsextensions_package" --private \ + retry_cmd 4 30 python_cmd "$helpers/codeticket.py" addoutput "Physics Extensions Package" "$llphysicsextensions_package" --private \ || fatal "Upload of physics extensions package failed" fi fi diff --git a/debian/changelog b/debian/changelog deleted file mode 100644 index ce54b54c6f..0000000000 --- a/debian/changelog +++ /dev/null @@ -1,18 +0,0 @@ -secondlife-viewer (0.3) unstable; urgency=low - - * Initial debian configuration - - -- Don Kjer Wed, 04 Jul 2012 00:43:03 +0000 - -secondlife-viewer (0.2) unstable; urgency=low - - * Adding default LSB headers for squeeze - - -- Tyler Kohler Thu, 24 Mar 2011 09:43:36 -0700 - -secondlife-viewer (0.1) unstable; urgency=low - - * Cloned from debian package skeleton. - - -- Lex Linden Mon, 20 Sep 2010 08:01:59 -0700 - diff --git a/debian/compat b/debian/compat deleted file mode 100644 index 7ed6ff82de..0000000000 --- a/debian/compat +++ /dev/null @@ -1 +0,0 @@ -5 diff --git a/debian/control b/debian/control deleted file mode 100644 index 50b9ed9a26..0000000000 --- a/debian/control +++ /dev/null @@ -1,16 +0,0 @@ -Source: secondlife-viewer -Section: unknown -Priority: extra -Maintainer: Don Linden -Build-Depends: debhelper (>= 5) -Homepage: http://secondlife.com -Standards-Version: 3.7.2 - -Package: secondlife-viewer -Architecture: any -Depends: ${shlibs:Depends}, ${misc:Depends}, - ia32-libs, - ia32-libs-gtk -Description: Second Life Viewer - Second Life is an online virtual world developed by Linden Lab. - diff --git a/debian/copyright b/debian/copyright deleted file mode 100644 index 106fa3802f..0000000000 --- a/debian/copyright +++ /dev/null @@ -1,32 +0,0 @@ -Second Life Viewer Copyright: 2000-2012 Linden Research, Inc. - -License: - -3Dconnexion SDK Copyright (C) 1992-2009 3Dconnexion -APR Copyright (C) 2011 The Apache Software Foundation -Collada DOM Copyright 2006 Sony Computer Entertainment Inc. -cURL Copyright (C) 1996-2010, Daniel Stenberg, (daniel@haxx.se) -DBus/dbus-glib Copyright (C) 2002, 2003 CodeFactory AB / Copyright (C) 2003, 2004 Red Hat, Inc. -expat Copyright (C) 1998, 1999, 2000 Thai Open Source Software Center Ltd. -FreeType Copyright (C) 1996-2002, 2006 David Turner, Robert Wilhelm, and Werner Lemberg. -GL Copyright (C) 1999-2004 Brian Paul. -GLOD Copyright (C) 2003-04 Jonathan Cohen, Nat Duca, Chris Niski, Johns Hopkins University and David Luebke, Brenden Schubert, University of Virginia. -google-perftools Copyright (c) 2005, Google Inc. -Havok.com(TM) Copyright (C) 1999-2001, Telekinesys Research Limited. -jpeg2000 Copyright (C) 2001, David Taubman, The University of New South Wales (UNSW) -jpeglib Copyright (C) 1991-1998, Thomas G. Lane. -ogg/vorbis Copyright (C) 2002, Xiphophorus -OpenSSL Copyright (C) 1998-2008 The OpenSSL Project. -PCRE Copyright (c) 1997-2012 University of Cambridge -SDL Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002 Sam Lantinga -SSLeay Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) -xmlrpc-epi Copyright (C) 2000 Epinions, Inc. -zlib Copyright (C) 1995-2012 Jean-loup Gailly and Mark Adler. - -Second Life Viewer uses Havok (TM) Physics. (c)Copyright 1999-2010 Havok.com Inc. (and its Licensors). All Rights Reserved. See www.havok.com for details. - -This software contains source code provided by NVIDIA Corporation. - -All rights reserved. See licenses.txt for details. - -Voice chat Audio coding: Polycom(R) Siren14(TM) (ITU-T Rec. G.722.1 Annex C) diff --git a/debian/postinst b/debian/postinst deleted file mode 100644 index 2c4f8ea858..0000000000 --- a/debian/postinst +++ /dev/null @@ -1,43 +0,0 @@ -#!/bin/sh -# postinst script for secondlife-viewer -# -# Delete this file if you don't need it. -# -# see: dh_installdeb(1) - -set -e - -# summary of how this script can be called: -# * `configure' -# * `abort-upgrade' -# * `abort-remove' `in-favour' -# -# * `abort-remove' -# * `abort-deconfigure' `in-favour' -# `removing' -# -# for details, see http://www.debian.org/doc/debian-policy/ or -# the debian-policy package - - -case "$1" in - configure) - ;; - - abort-upgrade|abort-remove|abort-deconfigure) - ;; - - *) - echo "postinst called with unknown argument \`$1'" >&2 - exit 1 - ;; -esac - -# dh_installdeb will replace this with shell code automatically -# generated by other debhelper scripts. Don't delete this! - -#DEBHELPER# - -exit 0 - - diff --git a/debian/postrm b/debian/postrm deleted file mode 100644 index a575936ab0..0000000000 --- a/debian/postrm +++ /dev/null @@ -1,41 +0,0 @@ -#!/bin/sh -# postrm script for secondlife-viewer -# -# Delete this file if you don't need it. -# -# see: dh_installdeb(1) - -set -e - -# summary of how this script can be called: -# * `remove' -# * `purge' -# * `upgrade' -# * `failed-upgrade' -# * `abort-install' -# * `abort-install' -# * `abort-upgrade' -# * `disappear' -# -# for details, see http://www.debian.org/doc/debian-policy/ or -# the debian-policy package - - -case "$1" in - purge|remove|upgrade|failed-upgrade|abort-install|abort-upgrade|disappear) - ;; - - *) - echo "postrm called with unknown argument \`$1'" >&2 - exit 1 - ;; -esac - -# dh_installdeb will replace this with shell code automatically -# generated by other debhelper scripts. Don't delete this! - -#DEBHELPER# - -exit 0 - - diff --git a/debian/preinst b/debian/preinst deleted file mode 100644 index f62243440f..0000000000 --- a/debian/preinst +++ /dev/null @@ -1,39 +0,0 @@ -#!/bin/sh -# preinst script for secondlife-viewer -# -# Delete this file if you don't need it. -# -# see: dh_installdeb(1) - -set -e - -# summary of how this script can be called: -# * `install' -# * `install' -# * `upgrade' -# * `abort-upgrade' -# for details, see http://www.debian.org/doc/debian-policy/ or -# the debian-policy package - - -case "$1" in - install|upgrade) - ;; - - abort-upgrade) - ;; - - *) - echo "preinst called with unknown argument \`$1'" >&2 - exit 1 - ;; -esac - -# dh_installdeb will replace this with shell code automatically -# generated by other debhelper scripts. Don't delete this! - -#DEBHELPER# - -exit 0 - - diff --git a/debian/prerm b/debian/prerm deleted file mode 100644 index 405b8f9c87..0000000000 --- a/debian/prerm +++ /dev/null @@ -1,42 +0,0 @@ -#!/bin/sh -# prerm script for secondlife-viewer -# -# Delete this file if you don't need it. -# -# see: dh_installdeb(1) - -set -e - -# summary of how this script can be called: -# * `remove' -# * `upgrade' -# * `failed-upgrade' -# * `remove' `in-favour' -# * `deconfigure' `in-favour' -# `removing' -# -# for details, see http://www.debian.org/doc/debian-policy/ or -# the debian-policy package - - -case "$1" in - remove|upgrade|deconfigure) - ;; - - failed-upgrade) - ;; - - *) - echo "prerm called with unknown argument \`$1'" >&2 - exit 1 - ;; -esac - -# dh_installdeb will replace this with shell code automatically -# generated by other debhelper scripts. Don't delete this! - -#DEBHELPER# - -exit 0 - - diff --git a/debian/rules b/debian/rules deleted file mode 100644 index 305fc58bb4..0000000000 --- a/debian/rules +++ /dev/null @@ -1,118 +0,0 @@ -#!/usr/bin/make -f -# -*- makefile -*- -# Sample debian/rules that uses debhelper. -# This file was originally written by Joey Hess and Craig Small. -# As a special exception, when this file is copied by dh-make into a -# dh-make output file, you may use that output file without restriction. -# This special exception was added by Craig Small in version 0.37 of dh-make. - -# Uncomment this to turn on verbose mode. -#export DH_VERBOSE=1 - -BASEDIR=opt/linden - -VIEWER_PKG=secondlife-viewer -VIEWER_PACKAGEDIR=build-linux-i686/newview/packaged -VIEWER_DESTDIR=$(CURDIR)/debian/$(VIEWER_PKG) -VIEWER_VERSION:=$(shell dpkg-parsechangelog | grep ^Version | sed 's/^Version: //') -VIEWER_INSTALLDIR:=$(BASEDIR)/viewer/SecondLife-i686-$(VIEWER_VERSION) - -configure: configure-stamp -configure-stamp: - dh_testdir - # Add here commands to configure the package. - - touch configure-stamp - -build: build-stamp - -build-stamp: configure-stamp - dh_testdir - - # Add here commands to compile the package. - #$(MAKE) - #docbook-to-man debian/secondlife-viewer.sgml > secondlife-viewer.1 - - touch $@ - -clean: - dh_testdir - dh_testroot - rm -f build-stamp configure-stamp - - # Add here commands to clean up after the build process. - #-$(MAKE) clean - - dh_clean - -install: build - dh_testdir - dh_testroot - dh_clean -k - dh_installdirs - - # Add here commands to install the package into debian/secondlife-viewer. - for file in $$(find $(VIEWER_PACKAGEDIR) -type f -o -type l | sed 's~$(VIEWER_PACKAGEDIR)/~~'); do \ - # create containing directory \ - install -v -m 755 -o root -g root -d "$$(dirname "$(VIEWER_DESTDIR)/$(VIEWER_INSTALLDIR)/$$file")"; \ - PERM=644; \ - if [ -x "$(VIEWER_PACKAGEDIR)/$$file" ]; then \ - PERM=755; \ - fi; \ - if [ -L "$(VIEWER_PACKAGEDIR)/$$file" ]; then \ - REAL="$$( readlink -f $(VIEWER_PACKAGEDIR)/$$file )"; \ - RELATIVE="$$( echo $$REAL | sed 's~$(CURDIR)/$(VIEWER_PACKAGEDIR)/~~' )"; \ - echo dh_link -p $(VIEWER_PKG) "$(VIEWER_INSTALLDIR)/$$RELATIVE" "$(VIEWER_INSTALLDIR)/$$file" ; \ - dh_link -p $(VIEWER_PKG) "$(VIEWER_INSTALLDIR)/$$RELATIVE" "$(VIEWER_INSTALLDIR)/$$file" ; \ - else \ - install -v -m $$PERM -o root -g root "$(VIEWER_PACKAGEDIR)/$$file" "$(VIEWER_DESTDIR)/$(VIEWER_INSTALLDIR)/$$file"; \ - fi; \ - done - dh_link -p $(VIEWER_PKG) /$(VIEWER_INSTALLDIR)/secondlife /usr/bin/secondlife - dh_link -p $(VIEWER_PKG) $(BASEDIR)/viewer/SecondLife-i686-$(VIEWER_VERSION) $(BASEDIR)/viewer/SecondLife - - -# Build architecture-independent files here. -binary-indep: build install -# We have nothing to do by default. - -# Build architecture-dependent files here. -binary-arch: build install - dh_testdir - dh_testroot - dh_installchangelogs - dh_installdocs - dh_installexamples -# dh_install -# dh_installmenu -# dh_installdebconf -# dh_installlogrotate -# dh_installemacsen -# dh_installpam -# dh_installmime -# dh_python - -# To add an init script, uncomment this line and edit debian/init.d and -# customize debian/secondlife-viewer.default to suit your needs. -# dh_installinit - -# To add cron jobs, uncomment this line and make a crontab file named -# debian/cron.d, and it will be installed in /etc/cron.d/ -# dh_installcron - -# dh_installinfo - dh_installman - dh_link -# dh_strip - dh_compress -# dh_fixperms -# dh_perl -# dh_makeshlibs - dh_installdeb -# dh_shlibdeps - dh_gencontrol - dh_md5sums - dh_builddeb - -binary: binary-indep binary-arch -.PHONY: build clean binary-indep binary-arch binary install configure diff --git a/debian/source/lintian-overrides b/debian/source/lintian-overrides deleted file mode 100644 index 661c20b572..0000000000 --- a/debian/source/lintian-overrides +++ /dev/null @@ -1,8 +0,0 @@ -# Linden packages install in opt/linden -secondlife-viewer: dir-or-file-in-opt -secondlife-viewer: section-is-dh_make-template -secondlife-viewer: binary-without-manpage -secondlife-viewer: maintainer-script-empty postrm -secondlife-viewer: maintainer-script-empty preinst -secondlife-viewer: maintainer-script-empty prerm -secondlife-viewer: unstripped-binary-or-object diff --git a/doc/contributions.txt b/doc/contributions.txt index 947fe19cfb..7d01ed7dcb 100755 --- a/doc/contributions.txt +++ b/doc/contributions.txt @@ -228,8 +228,15 @@ Ansariel Hiller SL-13364 SL-13858 SL-13697 + SL-14939 + SL-14940 + SL-14941 SL-13395 SL-3136 + SL-15200 + SL-15226 + SL-15227 + SL-15398 Aralara Rajal Arare Chantilly CHUIBUG-191 @@ -272,6 +279,7 @@ Beq Janus SL-13583 SL-14766 SL-14927 + SL-11300 Beth Walcher Bezilon Kasei Biancaluce Robbiani @@ -812,6 +820,7 @@ Jonathan Yap STORM-2142 STORM-2145 SL-10089 + BUG-229818 Kadah Coba STORM-1060 STORM-1843 diff --git a/doc/sl-logo.png b/doc/sl-logo.png new file mode 100644 index 0000000000..b9563c7ac7 Binary files /dev/null and b/doc/sl-logo.png differ diff --git a/indra/CMakeLists.txt b/indra/CMakeLists.txt index 67297ffb48..9d76be92c8 100644 --- a/indra/CMakeLists.txt +++ b/indra/CMakeLists.txt @@ -154,18 +154,6 @@ if (USE_BUGSPLAT) endif (BUGSPLAT_DB) else (USE_BUGSPLAT) message(STATUS "Not building with BugSplat") - if (LINUX) - add_subdirectory(${VIEWER_PREFIX}linux_crash_logger) - # Huh? Where'd that target come from? - #add_dependencies(viewer linux-crash-logger-strip-target) - elseif (DARWIN) - add_subdirectory(${VIEWER_PREFIX}mac_crash_logger) - add_dependencies(viewer mac-crash-logger) - elseif (WINDOWS) - add_subdirectory(${VIEWER_PREFIX}win_crash_logger) - # add_dependencies(viewer windows-setup windows-crash-logger) - add_dependencies(viewer windows-crash-logger) - endif (LINUX) endif (USE_BUGSPLAT) add_subdirectory(${VIEWER_PREFIX}newview) diff --git a/indra/cmake/00-Common.cmake b/indra/cmake/00-Common.cmake index 8e62e95bac..6909a94e4b 100644 --- a/indra/cmake/00-Common.cmake +++ b/indra/cmake/00-Common.cmake @@ -82,7 +82,7 @@ if (WINDOWS) # CP changed to only append the flag for 32bit builds - on 64bit builds, # locally at least, the build output is spammed with 1000s of 'D9002' # warnings about this switch being ignored. - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /MP") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /MP") # Remove this, it's no option to cl.exe and causes a massive amount of warnings. #if( ADDRESS_SIZE EQUAL 32 ) #set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /p:PreferredToolArchitecture=x64") @@ -165,6 +165,11 @@ endif (WINDOWS) if (LINUX) set(CMAKE_SKIP_RPATH TRUE) + + if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 10.0.0 ) + message( FATAL_ERROR "GCC greater 9.4.0 is not supported. Recompile boost for support of GCC 10.0.0 and up." ) + endif() + # # And another hack for FORTIFY_SOURCE. Some distributions (for example Gentoo) define FORTIFY_SOURCE by default. # Check if this is the case, if yes, do not define it again. diff --git a/indra/cmake/CEFPlugin.cmake b/indra/cmake/CEFPlugin.cmake index 9e7ab912f8..3f1318e5f2 100644 --- a/indra/cmake/CEFPlugin.cmake +++ b/indra/cmake/CEFPlugin.cmake @@ -24,7 +24,7 @@ elseif (DARWIN) message(FATAL_ERROR "AppKit not found") endif() - FIND_LIBRARY(CEF_LIBRARY "Chromium Embedded Framework" ${ARCH_PREBUILT_DIRS_RELEASE}) + set(CEF_LIBRARY "'${ARCH_PREBUILT_DIRS_RELEASE}/Chromium\ Embedded\ Framework.framework'") if (NOT CEF_LIBRARY) message(FATAL_ERROR "CEF not found") endif() @@ -33,7 +33,7 @@ elseif (DARWIN) ${ARCH_PREBUILT_DIRS_RELEASE}/libcef_dll_wrapper.a ${ARCH_PREBUILT_DIRS_RELEASE}/libdullahan.a ${APPKIT_LIBRARY} - ${CEF_LIBRARY} + "-F ${CEF_LIBRARY}" ) elseif (LINUX) diff --git a/indra/cmake/CMakeLists.txt b/indra/cmake/CMakeLists.txt index e8dcc56287..74d32defea 100644 --- a/indra/cmake/CMakeLists.txt +++ b/indra/cmake/CMakeLists.txt @@ -30,7 +30,6 @@ set(cmake_SOURCE_FILES FindBerkeleyDB.cmake FindFMODSTUDIO.cmake FindGLH.cmake - FindGoogleBreakpad.cmake FindHUNSPELL.cmake FindJsonCpp.cmake FindNDOF.cmake @@ -45,7 +44,6 @@ set(cmake_SOURCE_FILES GLH.cmake GLOD.cmake ## GStreamer010Plugin.cmake - GoogleBreakpad.cmake GoogleMock.cmake Growl.cmake Havok.cmake diff --git a/indra/cmake/Copy3rdPartyLibs.cmake b/indra/cmake/Copy3rdPartyLibs.cmake index 466a2a4475..519f68b53e 100644 --- a/indra/cmake/Copy3rdPartyLibs.cmake +++ b/indra/cmake/Copy3rdPartyLibs.cmake @@ -56,8 +56,6 @@ if(WINDOWS) libapr-1.dll libaprutil-1.dll libapriconv-1.dll - ssleay32.dll - libeay32.dll nghttp2.dll glod.dll libhunspell.dll @@ -70,6 +68,15 @@ if(WINDOWS) endif (NOT USE_KDU) # + # OpenSSL + if(ADDRESS_SIZE EQUAL 64) + set(release_files ${release_files} libcrypto-1_1-x64.dll) + set(release_files ${release_files} libssl-1_1-x64.dll) + else(ADDRESS_SIZE EQUAL 64) + set(release_files ${release_files} libcrypto-1_1.dll) + set(release_files ${release_files} libssl-1_1.dll) + endif(ADDRESS_SIZE EQUAL 64) + # Filenames are different for 32/64 bit BugSplat file and we don't # have any control over them so need to branch. if (USE_BUGSPLAT) @@ -190,7 +197,6 @@ elseif(DARWIN) libapr-1.dylib libaprutil-1.0.dylib libaprutil-1.dylib - libexception_handler.dylib ${EXPAT_COPY} libGLOD.dylib libhunspell-1.3.0.dylib diff --git a/indra/cmake/CubemapToEquirectangularJS.cmake b/indra/cmake/CubemapToEquirectangularJS.cmake new file mode 100644 index 0000000000..c380b831d3 --- /dev/null +++ b/indra/cmake/CubemapToEquirectangularJS.cmake @@ -0,0 +1,5 @@ +# -*- cmake -*- +use_prebuilt_binary(cubemaptoequirectangular) + +# Main JS file +#configure_file("${AUTOBUILD_INSTALL_DIR}/js/CubemapToEquirectangular.js" "${CMAKE_SOURCE_DIR}/newview/skins/default/html/common/equirectangular/js/CubemapToEquirectangular.js" COPYONLY) diff --git a/indra/cmake/FindGoogleBreakpad.cmake b/indra/cmake/FindGoogleBreakpad.cmake deleted file mode 100644 index e9f67b98c7..0000000000 --- a/indra/cmake/FindGoogleBreakpad.cmake +++ /dev/null @@ -1,44 +0,0 @@ -# -*- cmake -*- - -# - Find Google BreakPad -# Find the Google BreakPad includes and library -# This module defines -# BREAKPAD_EXCEPTION_HANDLER_INCLUDE_DIR, where to find exception_handler.h, etc. -# BREAKPAD_EXCEPTION_HANDLER_LIBRARIES, the libraries needed to use Google BreakPad. -# BREAKPAD_EXCEPTION_HANDLER_FOUND, If false, do not try to use Google BreakPad. -# also defined, but not for general use are -# BREAKPAD_EXCEPTION_HANDLER_LIBRARY, where to find the Google BreakPad library. - -# LL code uses "google_breakpad" path prefix, while google breakpad headers don't use a prefix. Find and add both paths to the correct variable. -FIND_PATH(BREAKPAD_EXCEPTION_HANDLER_INCLUDE_DIR google_breakpad/exception_handler.h) -FIND_PATH(BREAKPAD_EXCEPTION_HANDLER_INCLUDE_DIRS exception_handler.h PATH_SUFFIXES google_breakpad) -SET(BREAKPAD_INCLUDE_DIRECTORIES ${BREAKPAD_EXCEPTION_HANDLER_INCLUDE_DIR} ${BREAKPAD_EXCEPTION_HANDLER_INCLUDE_DIRS}) - -SET(BREAKPAD_EXCEPTION_HANDLER_NAMES ${BREAKPAD_EXCEPTION_HANDLER_NAMES} breakpad_client) -FIND_LIBRARY(BREAKPAD_EXCEPTION_HANDLER_LIBRARY - NAMES ${BREAKPAD_EXCEPTION_HANDLER_NAMES} - ) - -IF (BREAKPAD_EXCEPTION_HANDLER_LIBRARY AND BREAKPAD_EXCEPTION_HANDLER_INCLUDE_DIR) - SET(BREAKPAD_EXCEPTION_HANDLER_LIBRARIES ${BREAKPAD_EXCEPTION_HANDLER_LIBRARY}) - SET(BREAKPAD_EXCEPTION_HANDLER_FOUND "YES") -ELSE (BREAKPAD_EXCEPTION_HANDLER_LIBRARY AND BREAKPAD_EXCEPTION_HANDLER_INCLUDE_DIR) - SET(BREAKPAD_EXCEPTION_HANDLER_FOUND "NO") -ENDIF (BREAKPAD_EXCEPTION_HANDLER_LIBRARY AND BREAKPAD_EXCEPTION_HANDLER_INCLUDE_DIR) - - -IF (BREAKPAD_EXCEPTION_HANDLER_FOUND) - IF (NOT BREAKPAD_EXCEPTION_HANDLER_FIND_QUIETLY) - MESSAGE(STATUS "Found Google BreakPad: ${BREAKPAD_EXCEPTION_HANDLER_LIBRARIES}") - MESSAGE(STATUS "Found Google BreakPad headers in: ${BREAKPAD_INCLUDE_DIRECTORIES}") - ENDIF (NOT BREAKPAD_EXCEPTION_HANDLER_FIND_QUIETLY) -ELSE (BREAKPAD_EXCEPTION_HANDLER_FOUND) - IF (BREAKPAD_EXCEPTION_HANDLER_FIND_REQUIRED) - MESSAGE(FATAL_ERROR "Could not find Google BreakPad library") - ENDIF (BREAKPAD_EXCEPTION_HANDLER_FIND_REQUIRED) -ENDIF (BREAKPAD_EXCEPTION_HANDLER_FOUND) - -MARK_AS_ADVANCED( - BREAKPAD_EXCEPTION_HANDLER_LIBRARY - BREAKPAD_EXCEPTION_HANDLER_INCLUDE_DIR - ) diff --git a/indra/cmake/GoogleBreakpad.cmake b/indra/cmake/GoogleBreakpad.cmake deleted file mode 100644 index 83cf9cb1e7..0000000000 --- a/indra/cmake/GoogleBreakpad.cmake +++ /dev/null @@ -1,22 +0,0 @@ -# -*- cmake -*- -include(Prebuilt) - -#if (USESYSTEMLIBS) -# set(BREAKPAD_EXCEPTION_HANDLER_FIND_REQUIRED ON) -# include(FindGoogleBreakpad) -#else (USESYSTEMLIBS) - use_prebuilt_binary(google_breakpad) - if (DARWIN) - set(BREAKPAD_EXCEPTION_HANDLER_LIBRARIES exception_handler) - endif (DARWIN) - if (LINUX) - set(BREAKPAD_EXCEPTION_HANDLER_LIBRARIES breakpad_client) - endif (LINUX) - if (WINDOWS) - set(BREAKPAD_EXCEPTION_HANDLER_LIBRARIES exception_handler crash_generation_client crash_generation_server common) - endif (WINDOWS) - # yes, this does look dumb, no, it's not incorrect - # - set(BREAKPAD_INCLUDE_DIRECTORIES "${LIBS_PREBUILT_DIR}/include/google_breakpad" "${LIBS_PREBUILT_DIR}/include/google_breakpad/google_breakpad") -#endif (USESYSTEMLIBS) - diff --git a/indra/cmake/JPEGEncoderBasic.cmake b/indra/cmake/JPEGEncoderBasic.cmake new file mode 100644 index 0000000000..42086234b7 --- /dev/null +++ b/indra/cmake/JPEGEncoderBasic.cmake @@ -0,0 +1,5 @@ +# -*- cmake -*- +use_prebuilt_binary(jpegencoderbasic) + +# Main JS file +#configure_file("${AUTOBUILD_INSTALL_DIR}/js/jpeg_encoder_basic.js" "${CMAKE_SOURCE_DIR}/newview/skins/default/html/common/equirectangular/js/jpeg_encoder_basic.js" COPYONLY) diff --git a/indra/cmake/OpenSSL.cmake b/indra/cmake/OpenSSL.cmake index eb548bdcc1..f43ba7c26e 100644 --- a/indra/cmake/OpenSSL.cmake +++ b/indra/cmake/OpenSSL.cmake @@ -9,7 +9,7 @@ if (USESYSTEMLIBS) else (USESYSTEMLIBS) use_prebuilt_binary(openssl) if (WINDOWS) - set(OPENSSL_LIBRARIES ssleay32 libeay32) + set(OPENSSL_LIBRARIES libssl libcrypto) else (WINDOWS) set(OPENSSL_LIBRARIES ssl crypto) endif (WINDOWS) @@ -17,7 +17,7 @@ else (USESYSTEMLIBS) endif (USESYSTEMLIBS) if (LINUX) - set(CRYPTO_LIBRARIES crypto dl) + set(CRYPTO_LIBRARIES crypto dl pthread) elseif (DARWIN) set(CRYPTO_LIBRARIES crypto) endif (LINUX) diff --git a/indra/cmake/ThreeJS.cmake b/indra/cmake/ThreeJS.cmake new file mode 100644 index 0000000000..5c32825de6 --- /dev/null +++ b/indra/cmake/ThreeJS.cmake @@ -0,0 +1,8 @@ +# -*- cmake -*- +use_prebuilt_binary(threejs) + +# Main three.js file +#configure_file("${AUTOBUILD_INSTALL_DIR}/js/three.min.js" "${CMAKE_SOURCE_DIR}/newview/skins/default/html/common/equirectangular/js/three.min.js" COPYONLY) + +# Controls to move around the scene using mouse or keyboard +#configure_file("${AUTOBUILD_INSTALL_DIR}/js/OrbitControls.js" "${CMAKE_SOURCE_DIR}/newview/skins/default/html/common/equirectangular/js/OrbitControls.js" COPYONLY) diff --git a/indra/cmake/Variables.cmake b/indra/cmake/Variables.cmake index abab96ce24..756c3f4f42 100644 --- a/indra/cmake/Variables.cmake +++ b/indra/cmake/Variables.cmake @@ -60,7 +60,7 @@ if (EXISTS ${CMAKE_SOURCE_DIR}/Server.cmake) set(INSTALL_PROPRIETARY ON CACHE BOOL "Install proprietary binaries") endif (EXISTS ${CMAKE_SOURCE_DIR}/Server.cmake) set(TEMPLATE_VERIFIER_OPTIONS "" CACHE STRING "Options for scripts/template_verifier.py") -set(TEMPLATE_VERIFIER_MASTER_URL "https://bitbucket.org/lindenlab/master-message-template-git/raw/HEAD/message_template.msg" CACHE STRING "Location of the master message template") +set(TEMPLATE_VERIFIER_MASTER_URL "https://bitbucket.org/lindenlab/master-message-template-git/raw/master/message_template.msg" CACHE STRING "Location of the master message template") if (NOT CMAKE_BUILD_TYPE) set(CMAKE_BUILD_TYPE RelWithDebInfo CACHE STRING diff --git a/indra/edit-me-to-trigger-new-build.txt b/indra/edit-me-to-trigger-new-build.txt index 5366987cff..ade83202cf 100644 --- a/indra/edit-me-to-trigger-new-build.txt +++ b/indra/edit-me-to-trigger-new-build.txt @@ -1,3 +1,3 @@ euclid 5/29/2020 euclid 7/23/2020 -euclid 4/29/2021 \ No newline at end of file +euclid 4/29/2021 diff --git a/indra/llappearance/llviewervisualparam.cpp b/indra/llappearance/llviewervisualparam.cpp index 5763d5cf73..b9fad8540f 100644 --- a/indra/llappearance/llviewervisualparam.cpp +++ b/indra/llappearance/llviewervisualparam.cpp @@ -70,7 +70,7 @@ BOOL LLViewerVisualParamInfo::parseXml(LLXmlTreeNode *node) static LLStdStringHandle wearable_string = LLXmlTree::addAttributeString("wearable"); if( node->getFastAttributeString( wearable_string, wearable) ) { - mWearableType = LLWearableType::typeNameToType( wearable ); + mWearableType = LLWearableType::getInstance()->typeNameToType( wearable ); } static LLStdStringHandle edit_group_string = LLXmlTree::addAttributeString("edit_group"); diff --git a/indra/llappearance/llwearable.cpp b/indra/llappearance/llwearable.cpp index 1a45cc29c3..4670af4181 100644 --- a/indra/llappearance/llwearable.cpp +++ b/indra/llappearance/llwearable.cpp @@ -76,17 +76,17 @@ LLWearable::~LLWearable() const std::string& LLWearable::getTypeLabel() const { - return LLWearableType::getTypeLabel(mType); + return LLWearableType::getInstance()->getTypeLabel(mType); } const std::string& LLWearable::getTypeName() const { - return LLWearableType::getTypeName(mType); + return LLWearableType::getInstance()->getTypeName(mType); } LLAssetType::EType LLWearable::getAssetType() const { - return LLWearableType::getAssetType(mType); + return LLWearableType::getInstance()->getAssetType(mType); } BOOL LLWearable::exportFile(const std::string& filename) const diff --git a/indra/llappearance/llwearabledata.cpp b/indra/llappearance/llwearabledata.cpp index 0bbae88203..5d23d3a876 100644 --- a/indra/llappearance/llwearabledata.cpp +++ b/indra/llappearance/llwearabledata.cpp @@ -241,10 +241,11 @@ BOOL LLWearableData::getWearableIndex(const LLWearable *wearable, U32& index_fou U32 LLWearableData::getClothingLayerCount() const { U32 count = 0; + LLWearableType *wr_inst = LLWearableType::getInstance(); for (S32 i = 0; i < LLWearableType::WT_COUNT; i++) { LLWearableType::EType type = (LLWearableType::EType)i; - if (LLWearableType::getAssetType(type)==LLAssetType::AT_CLOTHING) + if (wr_inst->getAssetType(type)==LLAssetType::AT_CLOTHING) { count += getWearableCount(type); } @@ -254,7 +255,7 @@ U32 LLWearableData::getClothingLayerCount() const BOOL LLWearableData::canAddWearable(const LLWearableType::EType type) const { - LLAssetType::EType a_type = LLWearableType::getAssetType(type); + LLAssetType::EType a_type = LLWearableType::getInstance()->getAssetType(type); if (a_type==LLAssetType::AT_CLOTHING) { if (type == LLWearableType::WT_PHYSICS) return (getWearableCount(type) < 1); // Don't add physics layer diff --git a/indra/llappearance/llwearabletype.cpp b/indra/llappearance/llwearabletype.cpp index 2640b5a428..1f5054fa65 100644 --- a/indra/llappearance/llwearabletype.cpp +++ b/indra/llappearance/llwearabletype.cpp @@ -30,162 +30,101 @@ #include "llinventorydefines.h" -struct WearableEntry : public LLDictionaryEntry +LLWearableType::LLWearableDictionary::LLWearableDictionary(LLTranslationBridge::ptr_t& trans) { - WearableEntry(LLWearableType& wtype, - const std::string &name, - const std::string& default_new_name, - LLAssetType::EType assetType, - LLInventoryType::EIconName iconName, - BOOL disable_camera_switch = FALSE, - BOOL allow_multiwear = TRUE) : - LLDictionaryEntry(name), - mAssetType(assetType), - mDefaultNewName(default_new_name), - mLabel(wtype.mTrans->getString(name)), - mIconName(iconName), - mDisableCameraSwitch(disable_camera_switch), - mAllowMultiwear(allow_multiwear) - { - - } - const LLAssetType::EType mAssetType; - const std::string mLabel; - const std::string mDefaultNewName; //keep mLabel for backward compatibility - LLInventoryType::EIconName mIconName; - BOOL mDisableCameraSwitch; - BOOL mAllowMultiwear; -}; - -class LLWearableDictionary : public LLParamSingleton, - public LLDictionary -{ - LLSINGLETON(LLWearableDictionary, LLWearableType&); - -// [RLVa:KB] - Checked: 2010-03-03 (RLVa-1.2.0a) | Added: RLVa-1.2.0a -protected: - // The default implementation asserts on 'notFound()' and returns -1 which isn't a valid EWearableType - virtual LLWearableType::EType notFound() const { return LLWearableType::WT_INVALID; } -// [/RLVa:KB] -}; - -LLWearableDictionary::LLWearableDictionary(LLWearableType& wtype) -{ - addEntry(LLWearableType::WT_SHAPE, new WearableEntry(wtype, "shape", "New Shape", LLAssetType::AT_BODYPART, LLInventoryType::ICONNAME_BODYPART_SHAPE, FALSE, FALSE)); - addEntry(LLWearableType::WT_SKIN, new WearableEntry(wtype, "skin", "New Skin", LLAssetType::AT_BODYPART, LLInventoryType::ICONNAME_BODYPART_SKIN, FALSE, FALSE)); - addEntry(LLWearableType::WT_HAIR, new WearableEntry(wtype, "hair", "New Hair", LLAssetType::AT_BODYPART, LLInventoryType::ICONNAME_BODYPART_HAIR, FALSE, FALSE)); - addEntry(LLWearableType::WT_EYES, new WearableEntry(wtype, "eyes", "New Eyes", LLAssetType::AT_BODYPART, LLInventoryType::ICONNAME_BODYPART_EYES, FALSE, FALSE)); - addEntry(LLWearableType::WT_SHIRT, new WearableEntry(wtype, "shirt", "New Shirt", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_SHIRT, FALSE, TRUE)); - addEntry(LLWearableType::WT_PANTS, new WearableEntry(wtype, "pants", "New Pants", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_PANTS, FALSE, TRUE)); - addEntry(LLWearableType::WT_SHOES, new WearableEntry(wtype, "shoes", "New Shoes", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_SHOES, FALSE, TRUE)); - addEntry(LLWearableType::WT_SOCKS, new WearableEntry(wtype, "socks", "New Socks", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_SOCKS, FALSE, TRUE)); - addEntry(LLWearableType::WT_JACKET, new WearableEntry(wtype, "jacket", "New Jacket", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_JACKET, FALSE, TRUE)); - addEntry(LLWearableType::WT_GLOVES, new WearableEntry(wtype, "gloves", "New Gloves", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_GLOVES, FALSE, TRUE)); - addEntry(LLWearableType::WT_UNDERSHIRT, new WearableEntry(wtype, "undershirt", "New Undershirt", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_UNDERSHIRT, FALSE, TRUE)); - addEntry(LLWearableType::WT_UNDERPANTS, new WearableEntry(wtype, "underpants", "New Underpants", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_UNDERPANTS, FALSE, TRUE)); - addEntry(LLWearableType::WT_SKIRT, new WearableEntry(wtype, "skirt", "New Skirt", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_SKIRT, FALSE, TRUE)); - addEntry(LLWearableType::WT_ALPHA, new WearableEntry(wtype, "alpha", "New Alpha", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_ALPHA, FALSE, TRUE)); - addEntry(LLWearableType::WT_TATTOO, new WearableEntry(wtype, "tattoo", "New Tattoo", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_TATTOO, FALSE, TRUE)); - addEntry(LLWearableType::WT_UNIVERSAL, new WearableEntry(wtype, "universal", "New Universal", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_UNIVERSAL, FALSE, TRUE)); + addEntry(LLWearableType::WT_SHAPE, new WearableEntry(trans, "shape", "New Shape", LLAssetType::AT_BODYPART, LLInventoryType::ICONNAME_BODYPART_SHAPE, FALSE, FALSE)); + addEntry(LLWearableType::WT_SKIN, new WearableEntry(trans, "skin", "New Skin", LLAssetType::AT_BODYPART, LLInventoryType::ICONNAME_BODYPART_SKIN, FALSE, FALSE)); + addEntry(LLWearableType::WT_HAIR, new WearableEntry(trans, "hair", "New Hair", LLAssetType::AT_BODYPART, LLInventoryType::ICONNAME_BODYPART_HAIR, FALSE, FALSE)); + addEntry(LLWearableType::WT_EYES, new WearableEntry(trans, "eyes", "New Eyes", LLAssetType::AT_BODYPART, LLInventoryType::ICONNAME_BODYPART_EYES, FALSE, FALSE)); + addEntry(LLWearableType::WT_SHIRT, new WearableEntry(trans, "shirt", "New Shirt", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_SHIRT, FALSE, TRUE)); + addEntry(LLWearableType::WT_PANTS, new WearableEntry(trans, "pants", "New Pants", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_PANTS, FALSE, TRUE)); + addEntry(LLWearableType::WT_SHOES, new WearableEntry(trans, "shoes", "New Shoes", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_SHOES, FALSE, TRUE)); + addEntry(LLWearableType::WT_SOCKS, new WearableEntry(trans, "socks", "New Socks", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_SOCKS, FALSE, TRUE)); + addEntry(LLWearableType::WT_JACKET, new WearableEntry(trans, "jacket", "New Jacket", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_JACKET, FALSE, TRUE)); + addEntry(LLWearableType::WT_GLOVES, new WearableEntry(trans, "gloves", "New Gloves", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_GLOVES, FALSE, TRUE)); + addEntry(LLWearableType::WT_UNDERSHIRT, new WearableEntry(trans, "undershirt", "New Undershirt", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_UNDERSHIRT, FALSE, TRUE)); + addEntry(LLWearableType::WT_UNDERPANTS, new WearableEntry(trans, "underpants", "New Underpants", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_UNDERPANTS, FALSE, TRUE)); + addEntry(LLWearableType::WT_SKIRT, new WearableEntry(trans, "skirt", "New Skirt", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_SKIRT, FALSE, TRUE)); + addEntry(LLWearableType::WT_ALPHA, new WearableEntry(trans, "alpha", "New Alpha", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_ALPHA, FALSE, TRUE)); + addEntry(LLWearableType::WT_TATTOO, new WearableEntry(trans, "tattoo", "New Tattoo", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_TATTOO, FALSE, TRUE)); + addEntry(LLWearableType::WT_UNIVERSAL, new WearableEntry(trans, "universal", "New Universal", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_UNIVERSAL, FALSE, TRUE)); // [SL:KB] - Patch: Appearance-Misc | Checked: 2011-05-29 (Catznip-2.6) - addEntry(LLWearableType::WT_PHYSICS, new WearableEntry(wtype, "physics", "New Physics", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_PHYSICS, TRUE, FALSE)); + addEntry(LLWearableType::WT_PHYSICS, new WearableEntry(trans, "physics", "New Physics", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_PHYSICS, TRUE, FALSE)); // [/SL:KB] -// addEntry(LLWearableType::WT_PHYSICS, new WearableEntry(wtype, "physics", "New Physics", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_PHYSICS, TRUE, TRUE)); +// addEntry(LLWearableType::WT_PHYSICS, new WearableEntry(trans, "physics", "New Physics", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_PHYSICS, TRUE, TRUE)); - addEntry(LLWearableType::WT_INVALID, new WearableEntry(wtype, "invalid", "Invalid Wearable", LLAssetType::AT_NONE, LLInventoryType::ICONNAME_UNKNOWN, FALSE, FALSE)); - addEntry(LLWearableType::WT_NONE, new WearableEntry(wtype, "none", "Invalid Wearable", LLAssetType::AT_NONE, LLInventoryType::ICONNAME_NONE, FALSE, FALSE)); + addEntry(LLWearableType::WT_INVALID, new WearableEntry(trans, "invalid", "Invalid Wearable", LLAssetType::AT_NONE, LLInventoryType::ICONNAME_UNKNOWN, FALSE, FALSE)); + addEntry(LLWearableType::WT_NONE, new WearableEntry(trans, "none", "Invalid Wearable", LLAssetType::AT_NONE, LLInventoryType::ICONNAME_NONE, FALSE, FALSE)); } // class LLWearableType -LLWearableType::LLWearableType(LLTranslationBridge* trans) +LLWearableType::LLWearableType(LLTranslationBridge::ptr_t &trans) +: mDictionary(trans) { - // LLTranslationBridge exists, but is not ready at this point in time since strings.xml is not yet loaded - mTrans = trans; } LLWearableType::~LLWearableType() { - delete mTrans; } void LLWearableType::initSingleton() { - // To make sure all wrapping functions will crash without initing LLWearableType; - LLWearableDictionary::initParamSingleton(*this); - - // Todo: consider merging LLWearableType and LLWearableDictionary } -// static LLWearableType::EType LLWearableType::typeNameToType(const std::string& type_name) { - const LLWearableDictionary *dict = LLWearableDictionary::getInstance(); - const LLWearableType::EType wearable = dict->lookup(type_name); + const LLWearableType::EType wearable = mDictionary.lookup(type_name); return wearable; } -// static const std::string& LLWearableType::getTypeName(LLWearableType::EType type) { - const LLWearableDictionary *dict = LLWearableDictionary::getInstance(); - const WearableEntry *entry = dict->lookup(type); + const WearableEntry *entry = mDictionary.lookup(type); if (!entry) return getTypeName(WT_INVALID); return entry->mName; } -//static const std::string& LLWearableType::getTypeDefaultNewName(LLWearableType::EType type) { - const LLWearableDictionary *dict = LLWearableDictionary::getInstance(); - const WearableEntry *entry = dict->lookup(type); + const WearableEntry *entry = mDictionary.lookup(type); if (!entry) return getTypeDefaultNewName(WT_INVALID); return entry->mDefaultNewName; } -// static const std::string& LLWearableType::getTypeLabel(LLWearableType::EType type) { - const LLWearableDictionary *dict = LLWearableDictionary::getInstance(); - const WearableEntry *entry = dict->lookup(type); + const WearableEntry *entry = mDictionary.lookup(type); if (!entry) return getTypeLabel(WT_INVALID); return entry->mLabel; } -// static LLAssetType::EType LLWearableType::getAssetType(LLWearableType::EType type) { - const LLWearableDictionary *dict = LLWearableDictionary::getInstance(); - const WearableEntry *entry = dict->lookup(type); + const WearableEntry *entry = mDictionary.lookup(type); if (!entry) return getAssetType(WT_INVALID); return entry->mAssetType; } -// static LLInventoryType::EIconName LLWearableType::getIconName(LLWearableType::EType type) { - const LLWearableDictionary *dict = LLWearableDictionary::getInstance(); - const WearableEntry *entry = dict->lookup(type); + const WearableEntry *entry = mDictionary.lookup(type); if (!entry) return getIconName(WT_INVALID); return entry->mIconName; } -// static BOOL LLWearableType::getDisableCameraSwitch(LLWearableType::EType type) { - const LLWearableDictionary *dict = LLWearableDictionary::getInstance(); - const WearableEntry *entry = dict->lookup(type); + const WearableEntry *entry = mDictionary.lookup(type); if (!entry) return FALSE; return entry->mDisableCameraSwitch; } -// static BOOL LLWearableType::getAllowMultiwear(LLWearableType::EType type) { - const LLWearableDictionary *dict = LLWearableDictionary::getInstance(); - const WearableEntry *entry = dict->lookup(type); + const WearableEntry *entry = mDictionary.lookup(type); if (!entry) return FALSE; return entry->mAllowMultiwear; } diff --git a/indra/llappearance/llwearabletype.h b/indra/llappearance/llwearabletype.h index 57f3ef160d..11beda624a 100644 --- a/indra/llappearance/llwearabletype.h +++ b/indra/llappearance/llwearabletype.h @@ -35,10 +35,9 @@ class LLWearableType : public LLParamSingleton { - LLSINGLETON(LLWearableType, LLTranslationBridge* trans); + LLSINGLETON(LLWearableType, LLTranslationBridge::ptr_t &trans); ~LLWearableType(); void initSingleton(); - friend struct WearableEntry; public: enum EType { @@ -67,20 +66,59 @@ public: // Most methods are wrappers for dictionary, but if LLWearableType is not initialized, // they will crash. Whole LLWearableType is just wrapper for convinient calls. - static const std::string& getTypeName(EType type); - static const std::string& getTypeDefaultNewName(EType type); - static const std::string& getTypeLabel(EType type); - static LLAssetType::EType getAssetType(EType type); - static EType typeNameToType(const std::string& type_name); - static LLInventoryType::EIconName getIconName(EType type); - static BOOL getDisableCameraSwitch(EType type); - static BOOL getAllowMultiwear(EType type); + const std::string& getTypeName(EType type); + const std::string& getTypeDefaultNewName(EType type); + const std::string& getTypeLabel(EType type); + LLAssetType::EType getAssetType(EType type); + EType typeNameToType(const std::string& type_name); + LLInventoryType::EIconName getIconName(EType type); + BOOL getDisableCameraSwitch(EType type); + BOOL getAllowMultiwear(EType type); static EType inventoryFlagsToWearableType(U32 flags); -protected: +private: + struct WearableEntry : public LLDictionaryEntry + { + WearableEntry(LLTranslationBridge::ptr_t& trans, + const std::string &name, + const std::string& default_new_name, + LLAssetType::EType assetType, + LLInventoryType::EIconName iconName, + BOOL disable_camera_switch = FALSE, + BOOL allow_multiwear = TRUE) : + LLDictionaryEntry(name), + mAssetType(assetType), + mDefaultNewName(default_new_name), + mLabel(trans->getString(name)), + mIconName(iconName), + mDisableCameraSwitch(disable_camera_switch), + mAllowMultiwear(allow_multiwear) + { - LLTranslationBridge* mTrans; + } + const LLAssetType::EType mAssetType; + const std::string mLabel; + const std::string mDefaultNewName; + LLInventoryType::EIconName mIconName; + BOOL mDisableCameraSwitch; + BOOL mAllowMultiwear; + }; + + class LLWearableDictionary : public LLDictionary + { + public: + LLWearableDictionary(LLTranslationBridge::ptr_t& trans); + ~LLWearableDictionary() {} + +// [RLVa:KB] - Checked: 2010-03-03 (RLVa-1.2.0a) | Added: RLVa-1.2.0a + protected: + // The default implementation asserts on 'notFound()' and returns -1 which isn't a valid EWearableType + virtual LLWearableType::EType notFound() const { return LLWearableType::WT_INVALID; } +// [/RLVa:KB] + }; + + LLWearableDictionary mDictionary; }; #endif // LL_LLWEARABLETYPE_H diff --git a/indra/llaudio/llstreamingaudio_fmodstudio.cpp b/indra/llaudio/llstreamingaudio_fmodstudio.cpp index ff7dcbd995..7ba65c4cec 100644 --- a/indra/llaudio/llstreamingaudio_fmodstudio.cpp +++ b/indra/llaudio/llstreamingaudio_fmodstudio.cpp @@ -72,7 +72,8 @@ mSystem(system), mCurrentInternetStreamp(NULL), mStreamGroup(NULL), mFMODInternetStreamChannelp(NULL), -mGain(1.0f) +mGain(1.0f), +mWasAlreadyPlaying(false) { // Number of milliseconds of audio to buffer for the audio card. // Must be larger than the usual Second Life frame stutter time. @@ -158,18 +159,14 @@ void LLStreamingAudio_FMODSTUDIO::update() if (Check_FMOD_Error(mCurrentInternetStreamp->getOpenState(open_state, &progress, &starving, &diskbusy), "FMOD::Sound::getOpenState")) { LL_WARNS() << "Internet stream openstate error: open_state = " << open_state << " - progress = " << progress << " - starving = " << starving << " - diskbusy = " << diskbusy << LL_ENDL; + bool was_playing = mWasAlreadyPlaying; stop(); - return; - } - else if (open_state == FMOD_OPENSTATE_ERROR) - { - // Actually we might not get into this case at all since according to the - // FMOD API doc, one should check the result of getOpenState for further - // details, which most likely means if open_state is FMOD_OPENSTATE_ERROR, - // calling getOpenState will return anything but FMOD_OK and we end up in - // the if-case above. - LL_WARNS() << "Internet stream openstate error: progress = " << progress << " - starving = " << starving << " - diskbusy = " << diskbusy << LL_ENDL; - stop(); + // Try to restart previously playing stream on socket error + if (open_state == FMOD_OPENSTATE_ERROR && was_playing) + { + LL_WARNS() << "Stream was playing before - trying to restart" << LL_ENDL; + start(mURL); + } return; } else if (open_state == FMOD_OPENSTATE_READY) @@ -183,6 +180,14 @@ void LLStreamingAudio_FMODSTUDIO::update() // Reset volume to previously set volume setGain(getGain()); Check_FMOD_Error(mFMODInternetStreamChannelp->setPaused(false), "FMOD::Channel::setPaused"); + mWasAlreadyPlaying = true; + } + } + else if (open_state == FMOD_OPENSTATE_PLAYING) + { + if (!mWasAlreadyPlaying) + { + mWasAlreadyPlaying = true; } } @@ -317,6 +322,7 @@ void LLStreamingAudio_FMODSTUDIO::update() void LLStreamingAudio_FMODSTUDIO::stop() { mPendingURL.clear(); + mWasAlreadyPlaying = false; if (mFMODInternetStreamChannelp) { diff --git a/indra/llaudio/llstreamingaudio_fmodstudio.h b/indra/llaudio/llstreamingaudio_fmodstudio.h index 7ec5a0dbf4..43e8ef9c81 100644 --- a/indra/llaudio/llstreamingaudio_fmodstudio.h +++ b/indra/llaudio/llstreamingaudio_fmodstudio.h @@ -80,6 +80,8 @@ private: bool mNewMetadata; LLSD mMetadata; // Streamtitle display + + bool mWasAlreadyPlaying; }; diff --git a/indra/llcommon/CMakeLists.txt b/indra/llcommon/CMakeLists.txt index 9664617fa4..02b1d38fa9 100644 --- a/indra/llcommon/CMakeLists.txt +++ b/indra/llcommon/CMakeLists.txt @@ -9,7 +9,6 @@ include(Linking) include(Boost) include(LLSharedLibs) include(JsonCpp) -include(GoogleBreakpad) include(Copy3rdPartyLibs) include(ZLIB) include(URIPARSER) @@ -19,7 +18,6 @@ include_directories( ${LLCOMMON_INCLUDE_DIRS} ${JSONCPP_INCLUDE_DIR} ${ZLIB_INCLUDE_DIRS} - ${BREAKPAD_INCLUDE_DIRECTORIES} ${URIPARSER_INCLUDE_DIRS} ) @@ -210,9 +208,9 @@ set(llcommon_HEADER_FILES llqueuedthread.h llrand.h llrefcount.h + llregex.h llregistry.h llrun.h - llrefcount.h llsafehandle.h llsd.h llsdjson.h @@ -258,13 +256,14 @@ set(llcommon_HEADER_FILES StackWalker.h ) -# Add all nd* files. memory pool, intrinsics, ... -# Tracy Profiler support -list(APPEND llcommon_SOURCE_FILES fstelemetry.cpp) -if (USE_TRACY_PROFILER) - list(APPEND llcommon_SOURCE_FILES fstracyclient.cpp) -endif() - + # Tracy Profiler support + list(APPEND llcommon_SOURCE_FILES fstelemetry.cpp) + if (USE_TRACY_PROFILER) + list(APPEND llcommon_SOURCE_FILES fstracyclient.cpp) + endif() + # Tracy Profiler support + + # Add all nd* files. memory pool, intrinsics, ... SET( llcommon_ND_SOURCE_FILES nd/ndexceptions.cpp nd/ndlogthrottle.cpp @@ -329,7 +328,6 @@ endif(NOT WORD_SIZE EQUAL 32) target_link_libraries( llcommon - ${BREAKPAD_EXCEPTION_HANDLER_LIBRARIES} ${APRUTIL_LIBRARIES} ${APR_LIBRARIES} ${EXPAT_LIBRARIES} diff --git a/indra/llcommon/blockingconcurrentqueue.h b/indra/llcommon/blockingconcurrentqueue.h new file mode 100644 index 0000000000..66579b6caf --- /dev/null +++ b/indra/llcommon/blockingconcurrentqueue.h @@ -0,0 +1,582 @@ +// Provides an efficient blocking version of moodycamel::ConcurrentQueue. +// ©2015-2020 Cameron Desrochers. Distributed under the terms of the simplified +// BSD license, available at the top of concurrentqueue.h. +// Also dual-licensed under the Boost Software License (see LICENSE.md) +// Uses Jeff Preshing's semaphore implementation (under the terms of its +// separate zlib license, see lightweightsemaphore.h). + +#pragma once + +#include "concurrentqueue.h" +#include "lightweightsemaphore.h" + +#include +#include +#include +#include +#include + +namespace moodycamel +{ +// This is a blocking version of the queue. It has an almost identical interface to +// the normal non-blocking version, with the addition of various wait_dequeue() methods +// and the removal of producer-specific dequeue methods. +template +class BlockingConcurrentQueue +{ +private: + typedef ::moodycamel::ConcurrentQueue ConcurrentQueue; + typedef ::moodycamel::LightweightSemaphore LightweightSemaphore; + +public: + typedef typename ConcurrentQueue::producer_token_t producer_token_t; + typedef typename ConcurrentQueue::consumer_token_t consumer_token_t; + + typedef typename ConcurrentQueue::index_t index_t; + typedef typename ConcurrentQueue::size_t size_t; + typedef typename std::make_signed::type ssize_t; + + static const size_t BLOCK_SIZE = ConcurrentQueue::BLOCK_SIZE; + static const size_t EXPLICIT_BLOCK_EMPTY_COUNTER_THRESHOLD = ConcurrentQueue::EXPLICIT_BLOCK_EMPTY_COUNTER_THRESHOLD; + static const size_t EXPLICIT_INITIAL_INDEX_SIZE = ConcurrentQueue::EXPLICIT_INITIAL_INDEX_SIZE; + static const size_t IMPLICIT_INITIAL_INDEX_SIZE = ConcurrentQueue::IMPLICIT_INITIAL_INDEX_SIZE; + static const size_t INITIAL_IMPLICIT_PRODUCER_HASH_SIZE = ConcurrentQueue::INITIAL_IMPLICIT_PRODUCER_HASH_SIZE; + static const std::uint32_t EXPLICIT_CONSUMER_CONSUMPTION_QUOTA_BEFORE_ROTATE = ConcurrentQueue::EXPLICIT_CONSUMER_CONSUMPTION_QUOTA_BEFORE_ROTATE; + static const size_t MAX_SUBQUEUE_SIZE = ConcurrentQueue::MAX_SUBQUEUE_SIZE; + +public: + // Creates a queue with at least `capacity` element slots; note that the + // actual number of elements that can be inserted without additional memory + // allocation depends on the number of producers and the block size (e.g. if + // the block size is equal to `capacity`, only a single block will be allocated + // up-front, which means only a single producer will be able to enqueue elements + // without an extra allocation -- blocks aren't shared between producers). + // This method is not thread safe -- it is up to the user to ensure that the + // queue is fully constructed before it starts being used by other threads (this + // includes making the memory effects of construction visible, possibly with a + // memory barrier). + explicit BlockingConcurrentQueue(size_t capacity = 6 * BLOCK_SIZE) + : inner(capacity), sema(create(0, (int)Traits::MAX_SEMA_SPINS), &BlockingConcurrentQueue::template destroy) + { + assert(reinterpret_cast((BlockingConcurrentQueue*)1) == &((BlockingConcurrentQueue*)1)->inner && "BlockingConcurrentQueue must have ConcurrentQueue as its first member"); + if (!sema) { + MOODYCAMEL_THROW(std::bad_alloc()); + } + } + + BlockingConcurrentQueue(size_t minCapacity, size_t maxExplicitProducers, size_t maxImplicitProducers) + : inner(minCapacity, maxExplicitProducers, maxImplicitProducers), sema(create(0, (int)Traits::MAX_SEMA_SPINS), &BlockingConcurrentQueue::template destroy) + { + assert(reinterpret_cast((BlockingConcurrentQueue*)1) == &((BlockingConcurrentQueue*)1)->inner && "BlockingConcurrentQueue must have ConcurrentQueue as its first member"); + if (!sema) { + MOODYCAMEL_THROW(std::bad_alloc()); + } + } + + // Disable copying and copy assignment + BlockingConcurrentQueue(BlockingConcurrentQueue const&) MOODYCAMEL_DELETE_FUNCTION; + BlockingConcurrentQueue& operator=(BlockingConcurrentQueue const&) MOODYCAMEL_DELETE_FUNCTION; + + // Moving is supported, but note that it is *not* a thread-safe operation. + // Nobody can use the queue while it's being moved, and the memory effects + // of that move must be propagated to other threads before they can use it. + // Note: When a queue is moved, its tokens are still valid but can only be + // used with the destination queue (i.e. semantically they are moved along + // with the queue itself). + BlockingConcurrentQueue(BlockingConcurrentQueue&& other) MOODYCAMEL_NOEXCEPT + : inner(std::move(other.inner)), sema(std::move(other.sema)) + { } + + inline BlockingConcurrentQueue& operator=(BlockingConcurrentQueue&& other) MOODYCAMEL_NOEXCEPT + { + return swap_internal(other); + } + + // Swaps this queue's state with the other's. Not thread-safe. + // Swapping two queues does not invalidate their tokens, however + // the tokens that were created for one queue must be used with + // only the swapped queue (i.e. the tokens are tied to the + // queue's movable state, not the object itself). + inline void swap(BlockingConcurrentQueue& other) MOODYCAMEL_NOEXCEPT + { + swap_internal(other); + } + +private: + BlockingConcurrentQueue& swap_internal(BlockingConcurrentQueue& other) + { + if (this == &other) { + return *this; + } + + inner.swap(other.inner); + sema.swap(other.sema); + return *this; + } + +public: + // Enqueues a single item (by copying it). + // Allocates memory if required. Only fails if memory allocation fails (or implicit + // production is disabled because Traits::INITIAL_IMPLICIT_PRODUCER_HASH_SIZE is 0, + // or Traits::MAX_SUBQUEUE_SIZE has been defined and would be surpassed). + // Thread-safe. + inline bool enqueue(T const& item) + { + if ((details::likely)(inner.enqueue(item))) { + sema->signal(); + return true; + } + return false; + } + + // Enqueues a single item (by moving it, if possible). + // Allocates memory if required. Only fails if memory allocation fails (or implicit + // production is disabled because Traits::INITIAL_IMPLICIT_PRODUCER_HASH_SIZE is 0, + // or Traits::MAX_SUBQUEUE_SIZE has been defined and would be surpassed). + // Thread-safe. + inline bool enqueue(T&& item) + { + if ((details::likely)(inner.enqueue(std::move(item)))) { + sema->signal(); + return true; + } + return false; + } + + // Enqueues a single item (by copying it) using an explicit producer token. + // Allocates memory if required. Only fails if memory allocation fails (or + // Traits::MAX_SUBQUEUE_SIZE has been defined and would be surpassed). + // Thread-safe. + inline bool enqueue(producer_token_t const& token, T const& item) + { + if ((details::likely)(inner.enqueue(token, item))) { + sema->signal(); + return true; + } + return false; + } + + // Enqueues a single item (by moving it, if possible) using an explicit producer token. + // Allocates memory if required. Only fails if memory allocation fails (or + // Traits::MAX_SUBQUEUE_SIZE has been defined and would be surpassed). + // Thread-safe. + inline bool enqueue(producer_token_t const& token, T&& item) + { + if ((details::likely)(inner.enqueue(token, std::move(item)))) { + sema->signal(); + return true; + } + return false; + } + + // Enqueues several items. + // Allocates memory if required. Only fails if memory allocation fails (or + // implicit production is disabled because Traits::INITIAL_IMPLICIT_PRODUCER_HASH_SIZE + // is 0, or Traits::MAX_SUBQUEUE_SIZE has been defined and would be surpassed). + // Note: Use std::make_move_iterator if the elements should be moved instead of copied. + // Thread-safe. + template + inline bool enqueue_bulk(It itemFirst, size_t count) + { + if ((details::likely)(inner.enqueue_bulk(std::forward(itemFirst), count))) { + sema->signal((LightweightSemaphore::ssize_t)(ssize_t)count); + return true; + } + return false; + } + + // Enqueues several items using an explicit producer token. + // Allocates memory if required. Only fails if memory allocation fails + // (or Traits::MAX_SUBQUEUE_SIZE has been defined and would be surpassed). + // Note: Use std::make_move_iterator if the elements should be moved + // instead of copied. + // Thread-safe. + template + inline bool enqueue_bulk(producer_token_t const& token, It itemFirst, size_t count) + { + if ((details::likely)(inner.enqueue_bulk(token, std::forward(itemFirst), count))) { + sema->signal((LightweightSemaphore::ssize_t)(ssize_t)count); + return true; + } + return false; + } + + // Enqueues a single item (by copying it). + // Does not allocate memory. Fails if not enough room to enqueue (or implicit + // production is disabled because Traits::INITIAL_IMPLICIT_PRODUCER_HASH_SIZE + // is 0). + // Thread-safe. + inline bool try_enqueue(T const& item) + { + if (inner.try_enqueue(item)) { + sema->signal(); + return true; + } + return false; + } + + // Enqueues a single item (by moving it, if possible). + // Does not allocate memory (except for one-time implicit producer). + // Fails if not enough room to enqueue (or implicit production is + // disabled because Traits::INITIAL_IMPLICIT_PRODUCER_HASH_SIZE is 0). + // Thread-safe. + inline bool try_enqueue(T&& item) + { + if (inner.try_enqueue(std::move(item))) { + sema->signal(); + return true; + } + return false; + } + + // Enqueues a single item (by copying it) using an explicit producer token. + // Does not allocate memory. Fails if not enough room to enqueue. + // Thread-safe. + inline bool try_enqueue(producer_token_t const& token, T const& item) + { + if (inner.try_enqueue(token, item)) { + sema->signal(); + return true; + } + return false; + } + + // Enqueues a single item (by moving it, if possible) using an explicit producer token. + // Does not allocate memory. Fails if not enough room to enqueue. + // Thread-safe. + inline bool try_enqueue(producer_token_t const& token, T&& item) + { + if (inner.try_enqueue(token, std::move(item))) { + sema->signal(); + return true; + } + return false; + } + + // Enqueues several items. + // Does not allocate memory (except for one-time implicit producer). + // Fails if not enough room to enqueue (or implicit production is + // disabled because Traits::INITIAL_IMPLICIT_PRODUCER_HASH_SIZE is 0). + // Note: Use std::make_move_iterator if the elements should be moved + // instead of copied. + // Thread-safe. + template + inline bool try_enqueue_bulk(It itemFirst, size_t count) + { + if (inner.try_enqueue_bulk(std::forward(itemFirst), count)) { + sema->signal((LightweightSemaphore::ssize_t)(ssize_t)count); + return true; + } + return false; + } + + // Enqueues several items using an explicit producer token. + // Does not allocate memory. Fails if not enough room to enqueue. + // Note: Use std::make_move_iterator if the elements should be moved + // instead of copied. + // Thread-safe. + template + inline bool try_enqueue_bulk(producer_token_t const& token, It itemFirst, size_t count) + { + if (inner.try_enqueue_bulk(token, std::forward(itemFirst), count)) { + sema->signal((LightweightSemaphore::ssize_t)(ssize_t)count); + return true; + } + return false; + } + + + // Attempts to dequeue from the queue. + // Returns false if all producer streams appeared empty at the time they + // were checked (so, the queue is likely but not guaranteed to be empty). + // Never allocates. Thread-safe. + template + inline bool try_dequeue(U& item) + { + if (sema->tryWait()) { + while (!inner.try_dequeue(item)) { + continue; + } + return true; + } + return false; + } + + // Attempts to dequeue from the queue using an explicit consumer token. + // Returns false if all producer streams appeared empty at the time they + // were checked (so, the queue is likely but not guaranteed to be empty). + // Never allocates. Thread-safe. + template + inline bool try_dequeue(consumer_token_t& token, U& item) + { + if (sema->tryWait()) { + while (!inner.try_dequeue(token, item)) { + continue; + } + return true; + } + return false; + } + + // Attempts to dequeue several elements from the queue. + // Returns the number of items actually dequeued. + // Returns 0 if all producer streams appeared empty at the time they + // were checked (so, the queue is likely but not guaranteed to be empty). + // Never allocates. Thread-safe. + template + inline size_t try_dequeue_bulk(It itemFirst, size_t max) + { + size_t count = 0; + max = (size_t)sema->tryWaitMany((LightweightSemaphore::ssize_t)(ssize_t)max); + while (count != max) { + count += inner.template try_dequeue_bulk(itemFirst, max - count); + } + return count; + } + + // Attempts to dequeue several elements from the queue using an explicit consumer token. + // Returns the number of items actually dequeued. + // Returns 0 if all producer streams appeared empty at the time they + // were checked (so, the queue is likely but not guaranteed to be empty). + // Never allocates. Thread-safe. + template + inline size_t try_dequeue_bulk(consumer_token_t& token, It itemFirst, size_t max) + { + size_t count = 0; + max = (size_t)sema->tryWaitMany((LightweightSemaphore::ssize_t)(ssize_t)max); + while (count != max) { + count += inner.template try_dequeue_bulk(token, itemFirst, max - count); + } + return count; + } + + + + // Blocks the current thread until there's something to dequeue, then + // dequeues it. + // Never allocates. Thread-safe. + template + inline void wait_dequeue(U& item) + { + while (!sema->wait()) { + continue; + } + while (!inner.try_dequeue(item)) { + continue; + } + } + + // Blocks the current thread until either there's something to dequeue + // or the timeout (specified in microseconds) expires. Returns false + // without setting `item` if the timeout expires, otherwise assigns + // to `item` and returns true. + // Using a negative timeout indicates an indefinite timeout, + // and is thus functionally equivalent to calling wait_dequeue. + // Never allocates. Thread-safe. + template + inline bool wait_dequeue_timed(U& item, std::int64_t timeout_usecs) + { + if (!sema->wait(timeout_usecs)) { + return false; + } + while (!inner.try_dequeue(item)) { + continue; + } + return true; + } + + // Blocks the current thread until either there's something to dequeue + // or the timeout expires. Returns false without setting `item` if the + // timeout expires, otherwise assigns to `item` and returns true. + // Never allocates. Thread-safe. + template + inline bool wait_dequeue_timed(U& item, std::chrono::duration const& timeout) + { + return wait_dequeue_timed(item, std::chrono::duration_cast(timeout).count()); + } + + // Blocks the current thread until there's something to dequeue, then + // dequeues it using an explicit consumer token. + // Never allocates. Thread-safe. + template + inline void wait_dequeue(consumer_token_t& token, U& item) + { + while (!sema->wait()) { + continue; + } + while (!inner.try_dequeue(token, item)) { + continue; + } + } + + // Blocks the current thread until either there's something to dequeue + // or the timeout (specified in microseconds) expires. Returns false + // without setting `item` if the timeout expires, otherwise assigns + // to `item` and returns true. + // Using a negative timeout indicates an indefinite timeout, + // and is thus functionally equivalent to calling wait_dequeue. + // Never allocates. Thread-safe. + template + inline bool wait_dequeue_timed(consumer_token_t& token, U& item, std::int64_t timeout_usecs) + { + if (!sema->wait(timeout_usecs)) { + return false; + } + while (!inner.try_dequeue(token, item)) { + continue; + } + return true; + } + + // Blocks the current thread until either there's something to dequeue + // or the timeout expires. Returns false without setting `item` if the + // timeout expires, otherwise assigns to `item` and returns true. + // Never allocates. Thread-safe. + template + inline bool wait_dequeue_timed(consumer_token_t& token, U& item, std::chrono::duration const& timeout) + { + return wait_dequeue_timed(token, item, std::chrono::duration_cast(timeout).count()); + } + + // Attempts to dequeue several elements from the queue. + // Returns the number of items actually dequeued, which will + // always be at least one (this method blocks until the queue + // is non-empty) and at most max. + // Never allocates. Thread-safe. + template + inline size_t wait_dequeue_bulk(It itemFirst, size_t max) + { + size_t count = 0; + max = (size_t)sema->waitMany((LightweightSemaphore::ssize_t)(ssize_t)max); + while (count != max) { + count += inner.template try_dequeue_bulk(itemFirst, max - count); + } + return count; + } + + // Attempts to dequeue several elements from the queue. + // Returns the number of items actually dequeued, which can + // be 0 if the timeout expires while waiting for elements, + // and at most max. + // Using a negative timeout indicates an indefinite timeout, + // and is thus functionally equivalent to calling wait_dequeue_bulk. + // Never allocates. Thread-safe. + template + inline size_t wait_dequeue_bulk_timed(It itemFirst, size_t max, std::int64_t timeout_usecs) + { + size_t count = 0; + max = (size_t)sema->waitMany((LightweightSemaphore::ssize_t)(ssize_t)max, timeout_usecs); + while (count != max) { + count += inner.template try_dequeue_bulk(itemFirst, max - count); + } + return count; + } + + // Attempts to dequeue several elements from the queue. + // Returns the number of items actually dequeued, which can + // be 0 if the timeout expires while waiting for elements, + // and at most max. + // Never allocates. Thread-safe. + template + inline size_t wait_dequeue_bulk_timed(It itemFirst, size_t max, std::chrono::duration const& timeout) + { + return wait_dequeue_bulk_timed(itemFirst, max, std::chrono::duration_cast(timeout).count()); + } + + // Attempts to dequeue several elements from the queue using an explicit consumer token. + // Returns the number of items actually dequeued, which will + // always be at least one (this method blocks until the queue + // is non-empty) and at most max. + // Never allocates. Thread-safe. + template + inline size_t wait_dequeue_bulk(consumer_token_t& token, It itemFirst, size_t max) + { + size_t count = 0; + max = (size_t)sema->waitMany((LightweightSemaphore::ssize_t)(ssize_t)max); + while (count != max) { + count += inner.template try_dequeue_bulk(token, itemFirst, max - count); + } + return count; + } + + // Attempts to dequeue several elements from the queue using an explicit consumer token. + // Returns the number of items actually dequeued, which can + // be 0 if the timeout expires while waiting for elements, + // and at most max. + // Using a negative timeout indicates an indefinite timeout, + // and is thus functionally equivalent to calling wait_dequeue_bulk. + // Never allocates. Thread-safe. + template + inline size_t wait_dequeue_bulk_timed(consumer_token_t& token, It itemFirst, size_t max, std::int64_t timeout_usecs) + { + size_t count = 0; + max = (size_t)sema->waitMany((LightweightSemaphore::ssize_t)(ssize_t)max, timeout_usecs); + while (count != max) { + count += inner.template try_dequeue_bulk(token, itemFirst, max - count); + } + return count; + } + + // Attempts to dequeue several elements from the queue using an explicit consumer token. + // Returns the number of items actually dequeued, which can + // be 0 if the timeout expires while waiting for elements, + // and at most max. + // Never allocates. Thread-safe. + template + inline size_t wait_dequeue_bulk_timed(consumer_token_t& token, It itemFirst, size_t max, std::chrono::duration const& timeout) + { + return wait_dequeue_bulk_timed(token, itemFirst, max, std::chrono::duration_cast(timeout).count()); + } + + + // Returns an estimate of the total number of elements currently in the queue. This + // estimate is only accurate if the queue has completely stabilized before it is called + // (i.e. all enqueue and dequeue operations have completed and their memory effects are + // visible on the calling thread, and no further operations start while this method is + // being called). + // Thread-safe. + inline size_t size_approx() const + { + return (size_t)sema->availableApprox(); + } + + + // Returns true if the underlying atomic variables used by + // the queue are lock-free (they should be on most platforms). + // Thread-safe. + static bool is_lock_free() + { + return ConcurrentQueue::is_lock_free(); + } + + +private: + template + static inline U* create(A1&& a1, A2&& a2) + { + void* p = (Traits::malloc)(sizeof(U)); + return p != nullptr ? new (p) U(std::forward(a1), std::forward(a2)) : nullptr; + } + + template + static inline void destroy(U* p) + { + if (p != nullptr) { + p->~U(); + } + (Traits::free)(p); + } + +private: + ConcurrentQueue inner; + std::unique_ptr sema; +}; + + +template +inline void swap(BlockingConcurrentQueue& a, BlockingConcurrentQueue& b) MOODYCAMEL_NOEXCEPT +{ + a.swap(b); +} + +} // end namespace moodycamel diff --git a/indra/llcommon/concurrentqueue.h b/indra/llcommon/concurrentqueue.h new file mode 100644 index 0000000000..609ca4ab50 --- /dev/null +++ b/indra/llcommon/concurrentqueue.h @@ -0,0 +1,3742 @@ +// Provides a C++11 implementation of a multi-producer, multi-consumer lock-free queue. +// An overview, including benchmark results, is provided here: +// http://moodycamel.com/blog/2014/a-fast-general-purpose-lock-free-queue-for-c++ +// The full design is also described in excruciating detail at: +// http://moodycamel.com/blog/2014/detailed-design-of-a-lock-free-queue + +// Simplified BSD license: +// Copyright (c) 2013-2020, Cameron Desrochers. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// - Redistributions of source code must retain the above copyright notice, this list of +// conditions and the following disclaimer. +// - Redistributions in binary form must reproduce the above copyright notice, this list of +// conditions and the following disclaimer in the documentation and/or other materials +// provided with the distribution. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL +// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT +// OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR +// TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, +// EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Also dual-licensed under the Boost Software License (see LICENSE.md) + +#pragma once + +#if defined(__GNUC__) && !defined(__INTEL_COMPILER) +// Disable -Wconversion warnings (spuriously triggered when Traits::size_t and +// Traits::index_t are set to < 32 bits, causing integer promotion, causing warnings +// upon assigning any computed values) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wconversion" + +#ifdef MCDBGQ_USE_RELACY +#pragma GCC diagnostic ignored "-Wint-to-pointer-cast" +#endif +#endif + +#if defined(_MSC_VER) && (!defined(_HAS_CXX17) || !_HAS_CXX17) +// VS2019 with /W4 warns about constant conditional expressions but unless /std=c++17 or higher +// does not support `if constexpr`, so we have no choice but to simply disable the warning +#pragma warning(push) +#pragma warning(disable: 4127) // conditional expression is constant +#endif + +#if defined(__APPLE__) +#include "TargetConditionals.h" +#endif + +#ifdef MCDBGQ_USE_RELACY +#include "relacy/relacy_std.hpp" +#include "relacy_shims.h" +// We only use malloc/free anyway, and the delete macro messes up `= delete` method declarations. +// We'll override the default trait malloc ourselves without a macro. +#undef new +#undef delete +#undef malloc +#undef free +#else +#include // Requires C++11. Sorry VS2010. +#include +#endif +#include // for max_align_t +#include +#include +#include +#include +#include +#include +#include // for CHAR_BIT +#include +#include // partly for __WINPTHREADS_VERSION if on MinGW-w64 w/ POSIX threading + +// Platform-specific definitions of a numeric thread ID type and an invalid value +namespace moodycamel { namespace details { + template struct thread_id_converter { + typedef thread_id_t thread_id_numeric_size_t; + typedef thread_id_t thread_id_hash_t; + static thread_id_hash_t prehash(thread_id_t const& x) { return x; } + }; +} } +#if defined(MCDBGQ_USE_RELACY) +namespace moodycamel { namespace details { + typedef std::uint32_t thread_id_t; + static const thread_id_t invalid_thread_id = 0xFFFFFFFFU; + static const thread_id_t invalid_thread_id2 = 0xFFFFFFFEU; + static inline thread_id_t thread_id() { return rl::thread_index(); } +} } +#elif defined(_WIN32) || defined(__WINDOWS__) || defined(__WIN32__) +// No sense pulling in windows.h in a header, we'll manually declare the function +// we use and rely on backwards-compatibility for this not to break +extern "C" __declspec(dllimport) unsigned long __stdcall GetCurrentThreadId(void); +namespace moodycamel { namespace details { + static_assert(sizeof(unsigned long) == sizeof(std::uint32_t), "Expected size of unsigned long to be 32 bits on Windows"); + typedef std::uint32_t thread_id_t; + static const thread_id_t invalid_thread_id = 0; // See http://blogs.msdn.com/b/oldnewthing/archive/2004/02/23/78395.aspx + static const thread_id_t invalid_thread_id2 = 0xFFFFFFFFU; // Not technically guaranteed to be invalid, but is never used in practice. Note that all Win32 thread IDs are presently multiples of 4. + static inline thread_id_t thread_id() { return static_cast(::GetCurrentThreadId()); } +} } +#elif defined(__arm__) || defined(_M_ARM) || defined(__aarch64__) || (defined(__APPLE__) && TARGET_OS_IPHONE) || defined(MOODYCAMEL_NO_THREAD_LOCAL) +namespace moodycamel { namespace details { + static_assert(sizeof(std::thread::id) == 4 || sizeof(std::thread::id) == 8, "std::thread::id is expected to be either 4 or 8 bytes"); + + typedef std::thread::id thread_id_t; + static const thread_id_t invalid_thread_id; // Default ctor creates invalid ID + + // Note we don't define a invalid_thread_id2 since std::thread::id doesn't have one; it's + // only used if MOODYCAMEL_CPP11_THREAD_LOCAL_SUPPORTED is defined anyway, which it won't + // be. + static inline thread_id_t thread_id() { return std::this_thread::get_id(); } + + template struct thread_id_size { }; + template<> struct thread_id_size<4> { typedef std::uint32_t numeric_t; }; + template<> struct thread_id_size<8> { typedef std::uint64_t numeric_t; }; + + template<> struct thread_id_converter { + typedef thread_id_size::numeric_t thread_id_numeric_size_t; +#ifndef __APPLE__ + typedef std::size_t thread_id_hash_t; +#else + typedef thread_id_numeric_size_t thread_id_hash_t; +#endif + + static thread_id_hash_t prehash(thread_id_t const& x) + { +#ifndef __APPLE__ + return std::hash()(x); +#else + return *reinterpret_cast(&x); +#endif + } + }; +} } +#else +// Use a nice trick from this answer: http://stackoverflow.com/a/8438730/21475 +// In order to get a numeric thread ID in a platform-independent way, we use a thread-local +// static variable's address as a thread identifier :-) +#if defined(__GNUC__) || defined(__INTEL_COMPILER) +#define MOODYCAMEL_THREADLOCAL __thread +#elif defined(_MSC_VER) +#define MOODYCAMEL_THREADLOCAL __declspec(thread) +#else +// Assume C++11 compliant compiler +#define MOODYCAMEL_THREADLOCAL thread_local +#endif +namespace moodycamel { namespace details { + typedef std::uintptr_t thread_id_t; + static const thread_id_t invalid_thread_id = 0; // Address can't be nullptr + static const thread_id_t invalid_thread_id2 = 1; // Member accesses off a null pointer are also generally invalid. Plus it's not aligned. + inline thread_id_t thread_id() { static MOODYCAMEL_THREADLOCAL int x; return reinterpret_cast(&x); } +} } +#endif + +// Constexpr if +#ifndef MOODYCAMEL_CONSTEXPR_IF +#if (defined(_MSC_VER) && defined(_HAS_CXX17) && _HAS_CXX17) || __cplusplus > 201402L +#define MOODYCAMEL_CONSTEXPR_IF if constexpr +#define MOODYCAMEL_MAYBE_UNUSED [[maybe_unused]] +#else +#define MOODYCAMEL_CONSTEXPR_IF if +#define MOODYCAMEL_MAYBE_UNUSED +#endif +#endif + +// Exceptions +#ifndef MOODYCAMEL_EXCEPTIONS_ENABLED +#if (defined(_MSC_VER) && defined(_CPPUNWIND)) || (defined(__GNUC__) && defined(__EXCEPTIONS)) || (!defined(_MSC_VER) && !defined(__GNUC__)) +#define MOODYCAMEL_EXCEPTIONS_ENABLED +#endif +#endif +#ifdef MOODYCAMEL_EXCEPTIONS_ENABLED +#define MOODYCAMEL_TRY try +#define MOODYCAMEL_CATCH(...) catch(__VA_ARGS__) +#define MOODYCAMEL_RETHROW throw +#define MOODYCAMEL_THROW(expr) throw (expr) +#else +#define MOODYCAMEL_TRY MOODYCAMEL_CONSTEXPR_IF (true) +#define MOODYCAMEL_CATCH(...) else MOODYCAMEL_CONSTEXPR_IF (false) +#define MOODYCAMEL_RETHROW +#define MOODYCAMEL_THROW(expr) +#endif + +#ifndef MOODYCAMEL_NOEXCEPT +#if !defined(MOODYCAMEL_EXCEPTIONS_ENABLED) +#define MOODYCAMEL_NOEXCEPT +#define MOODYCAMEL_NOEXCEPT_CTOR(type, valueType, expr) true +#define MOODYCAMEL_NOEXCEPT_ASSIGN(type, valueType, expr) true +#elif defined(_MSC_VER) && defined(_NOEXCEPT) && _MSC_VER < 1800 +// VS2012's std::is_nothrow_[move_]constructible is broken and returns true when it shouldn't :-( +// We have to assume *all* non-trivial constructors may throw on VS2012! +#define MOODYCAMEL_NOEXCEPT _NOEXCEPT +#define MOODYCAMEL_NOEXCEPT_CTOR(type, valueType, expr) (std::is_rvalue_reference::value && std::is_move_constructible::value ? std::is_trivially_move_constructible::value : std::is_trivially_copy_constructible::value) +#define MOODYCAMEL_NOEXCEPT_ASSIGN(type, valueType, expr) ((std::is_rvalue_reference::value && std::is_move_assignable::value ? std::is_trivially_move_assignable::value || std::is_nothrow_move_assignable::value : std::is_trivially_copy_assignable::value || std::is_nothrow_copy_assignable::value) && MOODYCAMEL_NOEXCEPT_CTOR(type, valueType, expr)) +#elif defined(_MSC_VER) && defined(_NOEXCEPT) && _MSC_VER < 1900 +#define MOODYCAMEL_NOEXCEPT _NOEXCEPT +#define MOODYCAMEL_NOEXCEPT_CTOR(type, valueType, expr) (std::is_rvalue_reference::value && std::is_move_constructible::value ? std::is_trivially_move_constructible::value || std::is_nothrow_move_constructible::value : std::is_trivially_copy_constructible::value || std::is_nothrow_copy_constructible::value) +#define MOODYCAMEL_NOEXCEPT_ASSIGN(type, valueType, expr) ((std::is_rvalue_reference::value && std::is_move_assignable::value ? std::is_trivially_move_assignable::value || std::is_nothrow_move_assignable::value : std::is_trivially_copy_assignable::value || std::is_nothrow_copy_assignable::value) && MOODYCAMEL_NOEXCEPT_CTOR(type, valueType, expr)) +#else +#define MOODYCAMEL_NOEXCEPT noexcept +#define MOODYCAMEL_NOEXCEPT_CTOR(type, valueType, expr) noexcept(expr) +#define MOODYCAMEL_NOEXCEPT_ASSIGN(type, valueType, expr) noexcept(expr) +#endif +#endif + +#ifndef MOODYCAMEL_CPP11_THREAD_LOCAL_SUPPORTED +#ifdef MCDBGQ_USE_RELACY +#define MOODYCAMEL_CPP11_THREAD_LOCAL_SUPPORTED +#else +// VS2013 doesn't support `thread_local`, and MinGW-w64 w/ POSIX threading has a crippling bug: http://sourceforge.net/p/mingw-w64/bugs/445 +// g++ <=4.7 doesn't support thread_local either. +// Finally, iOS/ARM doesn't have support for it either, and g++/ARM allows it to compile but it's unconfirmed to actually work +#if (!defined(_MSC_VER) || _MSC_VER >= 1900) && (!defined(__MINGW32__) && !defined(__MINGW64__) || !defined(__WINPTHREADS_VERSION)) && (!defined(__GNUC__) || __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8)) && (!defined(__APPLE__) || !TARGET_OS_IPHONE) && !defined(__arm__) && !defined(_M_ARM) && !defined(__aarch64__) +// Assume `thread_local` is fully supported in all other C++11 compilers/platforms +//#define MOODYCAMEL_CPP11_THREAD_LOCAL_SUPPORTED // always disabled for now since several users report having problems with it on +#endif +#endif +#endif + +// VS2012 doesn't support deleted functions. +// In this case, we declare the function normally but don't define it. A link error will be generated if the function is called. +#ifndef MOODYCAMEL_DELETE_FUNCTION +#if defined(_MSC_VER) && _MSC_VER < 1800 +#define MOODYCAMEL_DELETE_FUNCTION +#else +#define MOODYCAMEL_DELETE_FUNCTION = delete +#endif +#endif + +namespace moodycamel { namespace details { +#ifndef MOODYCAMEL_ALIGNAS +// VS2013 doesn't support alignas or alignof, and align() requires a constant literal +#if defined(_MSC_VER) && _MSC_VER <= 1800 +#define MOODYCAMEL_ALIGNAS(alignment) __declspec(align(alignment)) +#define MOODYCAMEL_ALIGNOF(obj) __alignof(obj) +#define MOODYCAMEL_ALIGNED_TYPE_LIKE(T, obj) typename details::Vs2013Aligned::value, T>::type + template struct Vs2013Aligned { }; // default, unsupported alignment + template struct Vs2013Aligned<1, T> { typedef __declspec(align(1)) T type; }; + template struct Vs2013Aligned<2, T> { typedef __declspec(align(2)) T type; }; + template struct Vs2013Aligned<4, T> { typedef __declspec(align(4)) T type; }; + template struct Vs2013Aligned<8, T> { typedef __declspec(align(8)) T type; }; + template struct Vs2013Aligned<16, T> { typedef __declspec(align(16)) T type; }; + template struct Vs2013Aligned<32, T> { typedef __declspec(align(32)) T type; }; + template struct Vs2013Aligned<64, T> { typedef __declspec(align(64)) T type; }; + template struct Vs2013Aligned<128, T> { typedef __declspec(align(128)) T type; }; + template struct Vs2013Aligned<256, T> { typedef __declspec(align(256)) T type; }; +#else + template struct identity { typedef T type; }; +#define MOODYCAMEL_ALIGNAS(alignment) alignas(alignment) +#define MOODYCAMEL_ALIGNOF(obj) alignof(obj) +#define MOODYCAMEL_ALIGNED_TYPE_LIKE(T, obj) alignas(alignof(obj)) typename details::identity::type +#endif +#endif +} } + + +// TSAN can false report races in lock-free code. To enable TSAN to be used from projects that use this one, +// we can apply per-function compile-time suppression. +// See https://clang.llvm.org/docs/ThreadSanitizer.html#has-feature-thread-sanitizer +#define MOODYCAMEL_NO_TSAN +#if defined(__has_feature) + #if __has_feature(thread_sanitizer) + #undef MOODYCAMEL_NO_TSAN + #define MOODYCAMEL_NO_TSAN __attribute__((no_sanitize("thread"))) + #endif // TSAN +#endif // TSAN + +// Compiler-specific likely/unlikely hints +namespace moodycamel { namespace details { +#if defined(__GNUC__) + static inline bool (likely)(bool x) { return __builtin_expect((x), true); } + static inline bool (unlikely)(bool x) { return __builtin_expect((x), false); } +#else + static inline bool (likely)(bool x) { return x; } + static inline bool (unlikely)(bool x) { return x; } +#endif +} } + +#ifdef MOODYCAMEL_QUEUE_INTERNAL_DEBUG +#include "internal/concurrentqueue_internal_debug.h" +#endif + +namespace moodycamel { +namespace details { + template + struct const_numeric_max { + static_assert(std::is_integral::value, "const_numeric_max can only be used with integers"); + static const T value = std::numeric_limits::is_signed + ? (static_cast(1) << (sizeof(T) * CHAR_BIT - 1)) - static_cast(1) + : static_cast(-1); + }; + +#if defined(__GLIBCXX__) + typedef ::max_align_t std_max_align_t; // libstdc++ forgot to add it to std:: for a while +#else + typedef std::max_align_t std_max_align_t; // Others (e.g. MSVC) insist it can *only* be accessed via std:: +#endif + + // Some platforms have incorrectly set max_align_t to a type with <8 bytes alignment even while supporting + // 8-byte aligned scalar values (*cough* 32-bit iOS). Work around this with our own union. See issue #64. + typedef union { + std_max_align_t x; + long long y; + void* z; + } max_align_t; +} + +// Default traits for the ConcurrentQueue. To change some of the +// traits without re-implementing all of them, inherit from this +// struct and shadow the declarations you wish to be different; +// since the traits are used as a template type parameter, the +// shadowed declarations will be used where defined, and the defaults +// otherwise. +struct ConcurrentQueueDefaultTraits +{ + // General-purpose size type. std::size_t is strongly recommended. + typedef std::size_t size_t; + + // The type used for the enqueue and dequeue indices. Must be at least as + // large as size_t. Should be significantly larger than the number of elements + // you expect to hold at once, especially if you have a high turnover rate; + // for example, on 32-bit x86, if you expect to have over a hundred million + // elements or pump several million elements through your queue in a very + // short space of time, using a 32-bit type *may* trigger a race condition. + // A 64-bit int type is recommended in that case, and in practice will + // prevent a race condition no matter the usage of the queue. Note that + // whether the queue is lock-free with a 64-int type depends on the whether + // std::atomic is lock-free, which is platform-specific. + typedef std::size_t index_t; + + // Internally, all elements are enqueued and dequeued from multi-element + // blocks; this is the smallest controllable unit. If you expect few elements + // but many producers, a smaller block size should be favoured. For few producers + // and/or many elements, a larger block size is preferred. A sane default + // is provided. Must be a power of 2. + static const size_t BLOCK_SIZE = 32; + + // For explicit producers (i.e. when using a producer token), the block is + // checked for being empty by iterating through a list of flags, one per element. + // For large block sizes, this is too inefficient, and switching to an atomic + // counter-based approach is faster. The switch is made for block sizes strictly + // larger than this threshold. + static const size_t EXPLICIT_BLOCK_EMPTY_COUNTER_THRESHOLD = 32; + + // How many full blocks can be expected for a single explicit producer? This should + // reflect that number's maximum for optimal performance. Must be a power of 2. + static const size_t EXPLICIT_INITIAL_INDEX_SIZE = 32; + + // How many full blocks can be expected for a single implicit producer? This should + // reflect that number's maximum for optimal performance. Must be a power of 2. + static const size_t IMPLICIT_INITIAL_INDEX_SIZE = 32; + + // The initial size of the hash table mapping thread IDs to implicit producers. + // Note that the hash is resized every time it becomes half full. + // Must be a power of two, and either 0 or at least 1. If 0, implicit production + // (using the enqueue methods without an explicit producer token) is disabled. + static const size_t INITIAL_IMPLICIT_PRODUCER_HASH_SIZE = 32; + + // Controls the number of items that an explicit consumer (i.e. one with a token) + // must consume before it causes all consumers to rotate and move on to the next + // internal queue. + static const std::uint32_t EXPLICIT_CONSUMER_CONSUMPTION_QUOTA_BEFORE_ROTATE = 256; + + // The maximum number of elements (inclusive) that can be enqueued to a sub-queue. + // Enqueue operations that would cause this limit to be surpassed will fail. Note + // that this limit is enforced at the block level (for performance reasons), i.e. + // it's rounded up to the nearest block size. + static const size_t MAX_SUBQUEUE_SIZE = details::const_numeric_max::value; + + // The number of times to spin before sleeping when waiting on a semaphore. + // Recommended values are on the order of 1000-10000 unless the number of + // consumer threads exceeds the number of idle cores (in which case try 0-100). + // Only affects instances of the BlockingConcurrentQueue. + static const int MAX_SEMA_SPINS = 10000; + + +#ifndef MCDBGQ_USE_RELACY + // Memory allocation can be customized if needed. + // malloc should return nullptr on failure, and handle alignment like std::malloc. +#if defined(malloc) || defined(free) + // Gah, this is 2015, stop defining macros that break standard code already! + // Work around malloc/free being special macros: + static inline void* WORKAROUND_malloc(size_t size) { return malloc(size); } + static inline void WORKAROUND_free(void* ptr) { return free(ptr); } + static inline void* (malloc)(size_t size) { return WORKAROUND_malloc(size); } + static inline void (free)(void* ptr) { return WORKAROUND_free(ptr); } +#else + static inline void* malloc(size_t size) { return std::malloc(size); } + static inline void free(void* ptr) { return std::free(ptr); } +#endif +#else + // Debug versions when running under the Relacy race detector (ignore + // these in user code) + static inline void* malloc(size_t size) { return rl::rl_malloc(size, $); } + static inline void free(void* ptr) { return rl::rl_free(ptr, $); } +#endif +}; + + +// When producing or consuming many elements, the most efficient way is to: +// 1) Use one of the bulk-operation methods of the queue with a token +// 2) Failing that, use the bulk-operation methods without a token +// 3) Failing that, create a token and use that with the single-item methods +// 4) Failing that, use the single-parameter methods of the queue +// Having said that, don't create tokens willy-nilly -- ideally there should be +// a maximum of one token per thread (of each kind). +struct ProducerToken; +struct ConsumerToken; + +template class ConcurrentQueue; +template class BlockingConcurrentQueue; +class ConcurrentQueueTests; + + +namespace details +{ + struct ConcurrentQueueProducerTypelessBase + { + ConcurrentQueueProducerTypelessBase* next; + std::atomic inactive; + ProducerToken* token; + + ConcurrentQueueProducerTypelessBase() + : next(nullptr), inactive(false), token(nullptr) + { + } + }; + + template struct _hash_32_or_64 { + static inline std::uint32_t hash(std::uint32_t h) + { + // MurmurHash3 finalizer -- see https://code.google.com/p/smhasher/source/browse/trunk/MurmurHash3.cpp + // Since the thread ID is already unique, all we really want to do is propagate that + // uniqueness evenly across all the bits, so that we can use a subset of the bits while + // reducing collisions significantly + h ^= h >> 16; + h *= 0x85ebca6b; + h ^= h >> 13; + h *= 0xc2b2ae35; + return h ^ (h >> 16); + } + }; + template<> struct _hash_32_or_64<1> { + static inline std::uint64_t hash(std::uint64_t h) + { + h ^= h >> 33; + h *= 0xff51afd7ed558ccd; + h ^= h >> 33; + h *= 0xc4ceb9fe1a85ec53; + return h ^ (h >> 33); + } + }; + template struct hash_32_or_64 : public _hash_32_or_64<(size > 4)> { }; + + static inline size_t hash_thread_id(thread_id_t id) + { + static_assert(sizeof(thread_id_t) <= 8, "Expected a platform where thread IDs are at most 64-bit values"); + return static_cast(hash_32_or_64::thread_id_hash_t)>::hash( + thread_id_converter::prehash(id))); + } + + template + static inline bool circular_less_than(T a, T b) + { +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable: 4554) +#endif + static_assert(std::is_integral::value && !std::numeric_limits::is_signed, "circular_less_than is intended to be used only with unsigned integer types"); + return static_cast(a - b) > static_cast(static_cast(1) << static_cast(sizeof(T) * CHAR_BIT - 1)); +#ifdef _MSC_VER +#pragma warning(pop) +#endif + } + + template + static inline char* align_for(char* ptr) + { + const std::size_t alignment = std::alignment_of::value; + return ptr + (alignment - (reinterpret_cast(ptr) % alignment)) % alignment; + } + + template + static inline T ceil_to_pow_2(T x) + { + static_assert(std::is_integral::value && !std::numeric_limits::is_signed, "ceil_to_pow_2 is intended to be used only with unsigned integer types"); + + // Adapted from http://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2 + --x; + x |= x >> 1; + x |= x >> 2; + x |= x >> 4; + for (std::size_t i = 1; i < sizeof(T); i <<= 1) { + x |= x >> (i << 3); + } + ++x; + return x; + } + + template + static inline void swap_relaxed(std::atomic& left, std::atomic& right) + { + T temp = std::move(left.load(std::memory_order_relaxed)); + left.store(std::move(right.load(std::memory_order_relaxed)), std::memory_order_relaxed); + right.store(std::move(temp), std::memory_order_relaxed); + } + + template + static inline T const& nomove(T const& x) + { + return x; + } + + template + struct nomove_if + { + template + static inline T const& eval(T const& x) + { + return x; + } + }; + + template<> + struct nomove_if + { + template + static inline auto eval(U&& x) + -> decltype(std::forward(x)) + { + return std::forward(x); + } + }; + + template + static inline auto deref_noexcept(It& it) MOODYCAMEL_NOEXCEPT -> decltype(*it) + { + return *it; + } + +#if defined(__clang__) || !defined(__GNUC__) || __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8) + template struct is_trivially_destructible : std::is_trivially_destructible { }; +#else + template struct is_trivially_destructible : std::has_trivial_destructor { }; +#endif + +#ifdef MOODYCAMEL_CPP11_THREAD_LOCAL_SUPPORTED +#ifdef MCDBGQ_USE_RELACY + typedef RelacyThreadExitListener ThreadExitListener; + typedef RelacyThreadExitNotifier ThreadExitNotifier; +#else + struct ThreadExitListener + { + typedef void (*callback_t)(void*); + callback_t callback; + void* userData; + + ThreadExitListener* next; // reserved for use by the ThreadExitNotifier + }; + + + class ThreadExitNotifier + { + public: + static void subscribe(ThreadExitListener* listener) + { + auto& tlsInst = instance(); + listener->next = tlsInst.tail; + tlsInst.tail = listener; + } + + static void unsubscribe(ThreadExitListener* listener) + { + auto& tlsInst = instance(); + ThreadExitListener** prev = &tlsInst.tail; + for (auto ptr = tlsInst.tail; ptr != nullptr; ptr = ptr->next) { + if (ptr == listener) { + *prev = ptr->next; + break; + } + prev = &ptr->next; + } + } + + private: + ThreadExitNotifier() : tail(nullptr) { } + ThreadExitNotifier(ThreadExitNotifier const&) MOODYCAMEL_DELETE_FUNCTION; + ThreadExitNotifier& operator=(ThreadExitNotifier const&) MOODYCAMEL_DELETE_FUNCTION; + + ~ThreadExitNotifier() + { + // This thread is about to exit, let everyone know! + assert(this == &instance() && "If this assert fails, you likely have a buggy compiler! Change the preprocessor conditions such that MOODYCAMEL_CPP11_THREAD_LOCAL_SUPPORTED is no longer defined."); + for (auto ptr = tail; ptr != nullptr; ptr = ptr->next) { + ptr->callback(ptr->userData); + } + } + + // Thread-local + static inline ThreadExitNotifier& instance() + { + static thread_local ThreadExitNotifier notifier; + return notifier; + } + + private: + ThreadExitListener* tail; + }; +#endif +#endif + + template struct static_is_lock_free_num { enum { value = 0 }; }; + template<> struct static_is_lock_free_num { enum { value = ATOMIC_CHAR_LOCK_FREE }; }; + template<> struct static_is_lock_free_num { enum { value = ATOMIC_SHORT_LOCK_FREE }; }; + template<> struct static_is_lock_free_num { enum { value = ATOMIC_INT_LOCK_FREE }; }; + template<> struct static_is_lock_free_num { enum { value = ATOMIC_LONG_LOCK_FREE }; }; + template<> struct static_is_lock_free_num { enum { value = ATOMIC_LLONG_LOCK_FREE }; }; + template struct static_is_lock_free : static_is_lock_free_num::type> { }; + template<> struct static_is_lock_free { enum { value = ATOMIC_BOOL_LOCK_FREE }; }; + template struct static_is_lock_free { enum { value = ATOMIC_POINTER_LOCK_FREE }; }; +} + + +struct ProducerToken +{ + template + explicit ProducerToken(ConcurrentQueue& queue); + + template + explicit ProducerToken(BlockingConcurrentQueue& queue); + + ProducerToken(ProducerToken&& other) MOODYCAMEL_NOEXCEPT + : producer(other.producer) + { + other.producer = nullptr; + if (producer != nullptr) { + producer->token = this; + } + } + + inline ProducerToken& operator=(ProducerToken&& other) MOODYCAMEL_NOEXCEPT + { + swap(other); + return *this; + } + + void swap(ProducerToken& other) MOODYCAMEL_NOEXCEPT + { + std::swap(producer, other.producer); + if (producer != nullptr) { + producer->token = this; + } + if (other.producer != nullptr) { + other.producer->token = &other; + } + } + + // A token is always valid unless: + // 1) Memory allocation failed during construction + // 2) It was moved via the move constructor + // (Note: assignment does a swap, leaving both potentially valid) + // 3) The associated queue was destroyed + // Note that if valid() returns true, that only indicates + // that the token is valid for use with a specific queue, + // but not which one; that's up to the user to track. + inline bool valid() const { return producer != nullptr; } + + ~ProducerToken() + { + if (producer != nullptr) { + producer->token = nullptr; + producer->inactive.store(true, std::memory_order_release); + } + } + + // Disable copying and assignment + ProducerToken(ProducerToken const&) MOODYCAMEL_DELETE_FUNCTION; + ProducerToken& operator=(ProducerToken const&) MOODYCAMEL_DELETE_FUNCTION; + +private: + template friend class ConcurrentQueue; + friend class ConcurrentQueueTests; + +protected: + details::ConcurrentQueueProducerTypelessBase* producer; +}; + + +struct ConsumerToken +{ + template + explicit ConsumerToken(ConcurrentQueue& q); + + template + explicit ConsumerToken(BlockingConcurrentQueue& q); + + ConsumerToken(ConsumerToken&& other) MOODYCAMEL_NOEXCEPT + : initialOffset(other.initialOffset), lastKnownGlobalOffset(other.lastKnownGlobalOffset), itemsConsumedFromCurrent(other.itemsConsumedFromCurrent), currentProducer(other.currentProducer), desiredProducer(other.desiredProducer) + { + } + + inline ConsumerToken& operator=(ConsumerToken&& other) MOODYCAMEL_NOEXCEPT + { + swap(other); + return *this; + } + + void swap(ConsumerToken& other) MOODYCAMEL_NOEXCEPT + { + std::swap(initialOffset, other.initialOffset); + std::swap(lastKnownGlobalOffset, other.lastKnownGlobalOffset); + std::swap(itemsConsumedFromCurrent, other.itemsConsumedFromCurrent); + std::swap(currentProducer, other.currentProducer); + std::swap(desiredProducer, other.desiredProducer); + } + + // Disable copying and assignment + ConsumerToken(ConsumerToken const&) MOODYCAMEL_DELETE_FUNCTION; + ConsumerToken& operator=(ConsumerToken const&) MOODYCAMEL_DELETE_FUNCTION; + +private: + template friend class ConcurrentQueue; + friend class ConcurrentQueueTests; + +private: // but shared with ConcurrentQueue + std::uint32_t initialOffset; + std::uint32_t lastKnownGlobalOffset; + std::uint32_t itemsConsumedFromCurrent; + details::ConcurrentQueueProducerTypelessBase* currentProducer; + details::ConcurrentQueueProducerTypelessBase* desiredProducer; +}; + +// Need to forward-declare this swap because it's in a namespace. +// See http://stackoverflow.com/questions/4492062/why-does-a-c-friend-class-need-a-forward-declaration-only-in-other-namespaces +template +inline void swap(typename ConcurrentQueue::ImplicitProducerKVP& a, typename ConcurrentQueue::ImplicitProducerKVP& b) MOODYCAMEL_NOEXCEPT; + + +template +class ConcurrentQueue +{ +public: + typedef ::moodycamel::ProducerToken producer_token_t; + typedef ::moodycamel::ConsumerToken consumer_token_t; + + typedef typename Traits::index_t index_t; + typedef typename Traits::size_t size_t; + + static const size_t BLOCK_SIZE = static_cast(Traits::BLOCK_SIZE); + static const size_t EXPLICIT_BLOCK_EMPTY_COUNTER_THRESHOLD = static_cast(Traits::EXPLICIT_BLOCK_EMPTY_COUNTER_THRESHOLD); + static const size_t EXPLICIT_INITIAL_INDEX_SIZE = static_cast(Traits::EXPLICIT_INITIAL_INDEX_SIZE); + static const size_t IMPLICIT_INITIAL_INDEX_SIZE = static_cast(Traits::IMPLICIT_INITIAL_INDEX_SIZE); + static const size_t INITIAL_IMPLICIT_PRODUCER_HASH_SIZE = static_cast(Traits::INITIAL_IMPLICIT_PRODUCER_HASH_SIZE); + static const std::uint32_t EXPLICIT_CONSUMER_CONSUMPTION_QUOTA_BEFORE_ROTATE = static_cast(Traits::EXPLICIT_CONSUMER_CONSUMPTION_QUOTA_BEFORE_ROTATE); +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable: 4307) // + integral constant overflow (that's what the ternary expression is for!) +#pragma warning(disable: 4309) // static_cast: Truncation of constant value +#endif + static const size_t MAX_SUBQUEUE_SIZE = (details::const_numeric_max::value - static_cast(Traits::MAX_SUBQUEUE_SIZE) < BLOCK_SIZE) ? details::const_numeric_max::value : ((static_cast(Traits::MAX_SUBQUEUE_SIZE) + (BLOCK_SIZE - 1)) / BLOCK_SIZE * BLOCK_SIZE); +#ifdef _MSC_VER +#pragma warning(pop) +#endif + + static_assert(!std::numeric_limits::is_signed && std::is_integral::value, "Traits::size_t must be an unsigned integral type"); + static_assert(!std::numeric_limits::is_signed && std::is_integral::value, "Traits::index_t must be an unsigned integral type"); + static_assert(sizeof(index_t) >= sizeof(size_t), "Traits::index_t must be at least as wide as Traits::size_t"); + static_assert((BLOCK_SIZE > 1) && !(BLOCK_SIZE & (BLOCK_SIZE - 1)), "Traits::BLOCK_SIZE must be a power of 2 (and at least 2)"); + static_assert((EXPLICIT_BLOCK_EMPTY_COUNTER_THRESHOLD > 1) && !(EXPLICIT_BLOCK_EMPTY_COUNTER_THRESHOLD & (EXPLICIT_BLOCK_EMPTY_COUNTER_THRESHOLD - 1)), "Traits::EXPLICIT_BLOCK_EMPTY_COUNTER_THRESHOLD must be a power of 2 (and greater than 1)"); + static_assert((EXPLICIT_INITIAL_INDEX_SIZE > 1) && !(EXPLICIT_INITIAL_INDEX_SIZE & (EXPLICIT_INITIAL_INDEX_SIZE - 1)), "Traits::EXPLICIT_INITIAL_INDEX_SIZE must be a power of 2 (and greater than 1)"); + static_assert((IMPLICIT_INITIAL_INDEX_SIZE > 1) && !(IMPLICIT_INITIAL_INDEX_SIZE & (IMPLICIT_INITIAL_INDEX_SIZE - 1)), "Traits::IMPLICIT_INITIAL_INDEX_SIZE must be a power of 2 (and greater than 1)"); + static_assert((INITIAL_IMPLICIT_PRODUCER_HASH_SIZE == 0) || !(INITIAL_IMPLICIT_PRODUCER_HASH_SIZE & (INITIAL_IMPLICIT_PRODUCER_HASH_SIZE - 1)), "Traits::INITIAL_IMPLICIT_PRODUCER_HASH_SIZE must be a power of 2"); + static_assert(INITIAL_IMPLICIT_PRODUCER_HASH_SIZE == 0 || INITIAL_IMPLICIT_PRODUCER_HASH_SIZE >= 1, "Traits::INITIAL_IMPLICIT_PRODUCER_HASH_SIZE must be at least 1 (or 0 to disable implicit enqueueing)"); + +public: + // Creates a queue with at least `capacity` element slots; note that the + // actual number of elements that can be inserted without additional memory + // allocation depends on the number of producers and the block size (e.g. if + // the block size is equal to `capacity`, only a single block will be allocated + // up-front, which means only a single producer will be able to enqueue elements + // without an extra allocation -- blocks aren't shared between producers). + // This method is not thread safe -- it is up to the user to ensure that the + // queue is fully constructed before it starts being used by other threads (this + // includes making the memory effects of construction visible, possibly with a + // memory barrier). + explicit ConcurrentQueue(size_t capacity = 6 * BLOCK_SIZE) + : producerListTail(nullptr), + producerCount(0), + initialBlockPoolIndex(0), + nextExplicitConsumerId(0), + globalExplicitConsumerOffset(0) + { + implicitProducerHashResizeInProgress.clear(std::memory_order_relaxed); + populate_initial_implicit_producer_hash(); + populate_initial_block_list(capacity / BLOCK_SIZE + ((capacity & (BLOCK_SIZE - 1)) == 0 ? 0 : 1)); + +#ifdef MOODYCAMEL_QUEUE_INTERNAL_DEBUG + // Track all the producers using a fully-resolved typed list for + // each kind; this makes it possible to debug them starting from + // the root queue object (otherwise wacky casts are needed that + // don't compile in the debugger's expression evaluator). + explicitProducers.store(nullptr, std::memory_order_relaxed); + implicitProducers.store(nullptr, std::memory_order_relaxed); +#endif + } + + // Computes the correct amount of pre-allocated blocks for you based + // on the minimum number of elements you want available at any given + // time, and the maximum concurrent number of each type of producer. + ConcurrentQueue(size_t minCapacity, size_t maxExplicitProducers, size_t maxImplicitProducers) + : producerListTail(nullptr), + producerCount(0), + initialBlockPoolIndex(0), + nextExplicitConsumerId(0), + globalExplicitConsumerOffset(0) + { + implicitProducerHashResizeInProgress.clear(std::memory_order_relaxed); + populate_initial_implicit_producer_hash(); + size_t blocks = (((minCapacity + BLOCK_SIZE - 1) / BLOCK_SIZE) - 1) * (maxExplicitProducers + 1) + 2 * (maxExplicitProducers + maxImplicitProducers); + populate_initial_block_list(blocks); + +#ifdef MOODYCAMEL_QUEUE_INTERNAL_DEBUG + explicitProducers.store(nullptr, std::memory_order_relaxed); + implicitProducers.store(nullptr, std::memory_order_relaxed); +#endif + } + + // Note: The queue should not be accessed concurrently while it's + // being deleted. It's up to the user to synchronize this. + // This method is not thread safe. + ~ConcurrentQueue() + { + // Destroy producers + auto ptr = producerListTail.load(std::memory_order_relaxed); + while (ptr != nullptr) { + auto next = ptr->next_prod(); + if (ptr->token != nullptr) { + ptr->token->producer = nullptr; + } + destroy(ptr); + ptr = next; + } + + // Destroy implicit producer hash tables + MOODYCAMEL_CONSTEXPR_IF (INITIAL_IMPLICIT_PRODUCER_HASH_SIZE != 0) { + auto hash = implicitProducerHash.load(std::memory_order_relaxed); + while (hash != nullptr) { + auto prev = hash->prev; + if (prev != nullptr) { // The last hash is part of this object and was not allocated dynamically + for (size_t i = 0; i != hash->capacity; ++i) { + hash->entries[i].~ImplicitProducerKVP(); + } + hash->~ImplicitProducerHash(); + (Traits::free)(hash); + } + hash = prev; + } + } + + // Destroy global free list + auto block = freeList.head_unsafe(); + while (block != nullptr) { + auto next = block->freeListNext.load(std::memory_order_relaxed); + if (block->dynamicallyAllocated) { + destroy(block); + } + block = next; + } + + // Destroy initial free list + destroy_array(initialBlockPool, initialBlockPoolSize); + } + + // Disable copying and copy assignment + ConcurrentQueue(ConcurrentQueue const&) MOODYCAMEL_DELETE_FUNCTION; + ConcurrentQueue& operator=(ConcurrentQueue const&) MOODYCAMEL_DELETE_FUNCTION; + + // Moving is supported, but note that it is *not* a thread-safe operation. + // Nobody can use the queue while it's being moved, and the memory effects + // of that move must be propagated to other threads before they can use it. + // Note: When a queue is moved, its tokens are still valid but can only be + // used with the destination queue (i.e. semantically they are moved along + // with the queue itself). + ConcurrentQueue(ConcurrentQueue&& other) MOODYCAMEL_NOEXCEPT + : producerListTail(other.producerListTail.load(std::memory_order_relaxed)), + producerCount(other.producerCount.load(std::memory_order_relaxed)), + initialBlockPoolIndex(other.initialBlockPoolIndex.load(std::memory_order_relaxed)), + initialBlockPool(other.initialBlockPool), + initialBlockPoolSize(other.initialBlockPoolSize), + freeList(std::move(other.freeList)), + nextExplicitConsumerId(other.nextExplicitConsumerId.load(std::memory_order_relaxed)), + globalExplicitConsumerOffset(other.globalExplicitConsumerOffset.load(std::memory_order_relaxed)) + { + // Move the other one into this, and leave the other one as an empty queue + implicitProducerHashResizeInProgress.clear(std::memory_order_relaxed); + populate_initial_implicit_producer_hash(); + swap_implicit_producer_hashes(other); + + other.producerListTail.store(nullptr, std::memory_order_relaxed); + other.producerCount.store(0, std::memory_order_relaxed); + other.nextExplicitConsumerId.store(0, std::memory_order_relaxed); + other.globalExplicitConsumerOffset.store(0, std::memory_order_relaxed); + +#ifdef MOODYCAMEL_QUEUE_INTERNAL_DEBUG + explicitProducers.store(other.explicitProducers.load(std::memory_order_relaxed), std::memory_order_relaxed); + other.explicitProducers.store(nullptr, std::memory_order_relaxed); + implicitProducers.store(other.implicitProducers.load(std::memory_order_relaxed), std::memory_order_relaxed); + other.implicitProducers.store(nullptr, std::memory_order_relaxed); +#endif + + other.initialBlockPoolIndex.store(0, std::memory_order_relaxed); + other.initialBlockPoolSize = 0; + other.initialBlockPool = nullptr; + + reown_producers(); + } + + inline ConcurrentQueue& operator=(ConcurrentQueue&& other) MOODYCAMEL_NOEXCEPT + { + return swap_internal(other); + } + + // Swaps this queue's state with the other's. Not thread-safe. + // Swapping two queues does not invalidate their tokens, however + // the tokens that were created for one queue must be used with + // only the swapped queue (i.e. the tokens are tied to the + // queue's movable state, not the object itself). + inline void swap(ConcurrentQueue& other) MOODYCAMEL_NOEXCEPT + { + swap_internal(other); + } + +private: + ConcurrentQueue& swap_internal(ConcurrentQueue& other) + { + if (this == &other) { + return *this; + } + + details::swap_relaxed(producerListTail, other.producerListTail); + details::swap_relaxed(producerCount, other.producerCount); + details::swap_relaxed(initialBlockPoolIndex, other.initialBlockPoolIndex); + std::swap(initialBlockPool, other.initialBlockPool); + std::swap(initialBlockPoolSize, other.initialBlockPoolSize); + freeList.swap(other.freeList); + details::swap_relaxed(nextExplicitConsumerId, other.nextExplicitConsumerId); + details::swap_relaxed(globalExplicitConsumerOffset, other.globalExplicitConsumerOffset); + + swap_implicit_producer_hashes(other); + + reown_producers(); + other.reown_producers(); + +#ifdef MOODYCAMEL_QUEUE_INTERNAL_DEBUG + details::swap_relaxed(explicitProducers, other.explicitProducers); + details::swap_relaxed(implicitProducers, other.implicitProducers); +#endif + + return *this; + } + +public: + // Enqueues a single item (by copying it). + // Allocates memory if required. Only fails if memory allocation fails (or implicit + // production is disabled because Traits::INITIAL_IMPLICIT_PRODUCER_HASH_SIZE is 0, + // or Traits::MAX_SUBQUEUE_SIZE has been defined and would be surpassed). + // Thread-safe. + inline bool enqueue(T const& item) + { + MOODYCAMEL_CONSTEXPR_IF (INITIAL_IMPLICIT_PRODUCER_HASH_SIZE == 0) return false; + else return inner_enqueue(item); + } + + // Enqueues a single item (by moving it, if possible). + // Allocates memory if required. Only fails if memory allocation fails (or implicit + // production is disabled because Traits::INITIAL_IMPLICIT_PRODUCER_HASH_SIZE is 0, + // or Traits::MAX_SUBQUEUE_SIZE has been defined and would be surpassed). + // Thread-safe. + inline bool enqueue(T&& item) + { + MOODYCAMEL_CONSTEXPR_IF (INITIAL_IMPLICIT_PRODUCER_HASH_SIZE == 0) return false; + else return inner_enqueue(std::move(item)); + } + + // Enqueues a single item (by copying it) using an explicit producer token. + // Allocates memory if required. Only fails if memory allocation fails (or + // Traits::MAX_SUBQUEUE_SIZE has been defined and would be surpassed). + // Thread-safe. + inline bool enqueue(producer_token_t const& token, T const& item) + { + return inner_enqueue(token, item); + } + + // Enqueues a single item (by moving it, if possible) using an explicit producer token. + // Allocates memory if required. Only fails if memory allocation fails (or + // Traits::MAX_SUBQUEUE_SIZE has been defined and would be surpassed). + // Thread-safe. + inline bool enqueue(producer_token_t const& token, T&& item) + { + return inner_enqueue(token, std::move(item)); + } + + // Enqueues several items. + // Allocates memory if required. Only fails if memory allocation fails (or + // implicit production is disabled because Traits::INITIAL_IMPLICIT_PRODUCER_HASH_SIZE + // is 0, or Traits::MAX_SUBQUEUE_SIZE has been defined and would be surpassed). + // Note: Use std::make_move_iterator if the elements should be moved instead of copied. + // Thread-safe. + template + bool enqueue_bulk(It itemFirst, size_t count) + { + MOODYCAMEL_CONSTEXPR_IF (INITIAL_IMPLICIT_PRODUCER_HASH_SIZE == 0) return false; + else return inner_enqueue_bulk(itemFirst, count); + } + + // Enqueues several items using an explicit producer token. + // Allocates memory if required. Only fails if memory allocation fails + // (or Traits::MAX_SUBQUEUE_SIZE has been defined and would be surpassed). + // Note: Use std::make_move_iterator if the elements should be moved + // instead of copied. + // Thread-safe. + template + bool enqueue_bulk(producer_token_t const& token, It itemFirst, size_t count) + { + return inner_enqueue_bulk(token, itemFirst, count); + } + + // Enqueues a single item (by copying it). + // Does not allocate memory. Fails if not enough room to enqueue (or implicit + // production is disabled because Traits::INITIAL_IMPLICIT_PRODUCER_HASH_SIZE + // is 0). + // Thread-safe. + inline bool try_enqueue(T const& item) + { + MOODYCAMEL_CONSTEXPR_IF (INITIAL_IMPLICIT_PRODUCER_HASH_SIZE == 0) return false; + else return inner_enqueue(item); + } + + // Enqueues a single item (by moving it, if possible). + // Does not allocate memory (except for one-time implicit producer). + // Fails if not enough room to enqueue (or implicit production is + // disabled because Traits::INITIAL_IMPLICIT_PRODUCER_HASH_SIZE is 0). + // Thread-safe. + inline bool try_enqueue(T&& item) + { + MOODYCAMEL_CONSTEXPR_IF (INITIAL_IMPLICIT_PRODUCER_HASH_SIZE == 0) return false; + else return inner_enqueue(std::move(item)); + } + + // Enqueues a single item (by copying it) using an explicit producer token. + // Does not allocate memory. Fails if not enough room to enqueue. + // Thread-safe. + inline bool try_enqueue(producer_token_t const& token, T const& item) + { + return inner_enqueue(token, item); + } + + // Enqueues a single item (by moving it, if possible) using an explicit producer token. + // Does not allocate memory. Fails if not enough room to enqueue. + // Thread-safe. + inline bool try_enqueue(producer_token_t const& token, T&& item) + { + return inner_enqueue(token, std::move(item)); + } + + // Enqueues several items. + // Does not allocate memory (except for one-time implicit producer). + // Fails if not enough room to enqueue (or implicit production is + // disabled because Traits::INITIAL_IMPLICIT_PRODUCER_HASH_SIZE is 0). + // Note: Use std::make_move_iterator if the elements should be moved + // instead of copied. + // Thread-safe. + template + bool try_enqueue_bulk(It itemFirst, size_t count) + { + MOODYCAMEL_CONSTEXPR_IF (INITIAL_IMPLICIT_PRODUCER_HASH_SIZE == 0) return false; + else return inner_enqueue_bulk(itemFirst, count); + } + + // Enqueues several items using an explicit producer token. + // Does not allocate memory. Fails if not enough room to enqueue. + // Note: Use std::make_move_iterator if the elements should be moved + // instead of copied. + // Thread-safe. + template + bool try_enqueue_bulk(producer_token_t const& token, It itemFirst, size_t count) + { + return inner_enqueue_bulk(token, itemFirst, count); + } + + + + // Attempts to dequeue from the queue. + // Returns false if all producer streams appeared empty at the time they + // were checked (so, the queue is likely but not guaranteed to be empty). + // Never allocates. Thread-safe. + template + bool try_dequeue(U& item) + { + // Instead of simply trying each producer in turn (which could cause needless contention on the first + // producer), we score them heuristically. + size_t nonEmptyCount = 0; + ProducerBase* best = nullptr; + size_t bestSize = 0; + for (auto ptr = producerListTail.load(std::memory_order_acquire); nonEmptyCount < 3 && ptr != nullptr; ptr = ptr->next_prod()) { + auto size = ptr->size_approx(); + if (size > 0) { + if (size > bestSize) { + bestSize = size; + best = ptr; + } + ++nonEmptyCount; + } + } + + // If there was at least one non-empty queue but it appears empty at the time + // we try to dequeue from it, we need to make sure every queue's been tried + if (nonEmptyCount > 0) { + if ((details::likely)(best->dequeue(item))) { + return true; + } + for (auto ptr = producerListTail.load(std::memory_order_acquire); ptr != nullptr; ptr = ptr->next_prod()) { + if (ptr != best && ptr->dequeue(item)) { + return true; + } + } + } + return false; + } + + // Attempts to dequeue from the queue. + // Returns false if all producer streams appeared empty at the time they + // were checked (so, the queue is likely but not guaranteed to be empty). + // This differs from the try_dequeue(item) method in that this one does + // not attempt to reduce contention by interleaving the order that producer + // streams are dequeued from. So, using this method can reduce overall throughput + // under contention, but will give more predictable results in single-threaded + // consumer scenarios. This is mostly only useful for internal unit tests. + // Never allocates. Thread-safe. + template + bool try_dequeue_non_interleaved(U& item) + { + for (auto ptr = producerListTail.load(std::memory_order_acquire); ptr != nullptr; ptr = ptr->next_prod()) { + if (ptr->dequeue(item)) { + return true; + } + } + return false; + } + + // Attempts to dequeue from the queue using an explicit consumer token. + // Returns false if all producer streams appeared empty at the time they + // were checked (so, the queue is likely but not guaranteed to be empty). + // Never allocates. Thread-safe. + template + bool try_dequeue(consumer_token_t& token, U& item) + { + // The idea is roughly as follows: + // Every 256 items from one producer, make everyone rotate (increase the global offset) -> this means the highest efficiency consumer dictates the rotation speed of everyone else, more or less + // If you see that the global offset has changed, you must reset your consumption counter and move to your designated place + // If there's no items where you're supposed to be, keep moving until you find a producer with some items + // If the global offset has not changed but you've run out of items to consume, move over from your current position until you find an producer with something in it + + if (token.desiredProducer == nullptr || token.lastKnownGlobalOffset != globalExplicitConsumerOffset.load(std::memory_order_relaxed)) { + if (!update_current_producer_after_rotation(token)) { + return false; + } + } + + // If there was at least one non-empty queue but it appears empty at the time + // we try to dequeue from it, we need to make sure every queue's been tried + if (static_cast(token.currentProducer)->dequeue(item)) { + if (++token.itemsConsumedFromCurrent == EXPLICIT_CONSUMER_CONSUMPTION_QUOTA_BEFORE_ROTATE) { + globalExplicitConsumerOffset.fetch_add(1, std::memory_order_relaxed); + } + return true; + } + + auto tail = producerListTail.load(std::memory_order_acquire); + auto ptr = static_cast(token.currentProducer)->next_prod(); + if (ptr == nullptr) { + ptr = tail; + } + while (ptr != static_cast(token.currentProducer)) { + if (ptr->dequeue(item)) { + token.currentProducer = ptr; + token.itemsConsumedFromCurrent = 1; + return true; + } + ptr = ptr->next_prod(); + if (ptr == nullptr) { + ptr = tail; + } + } + return false; + } + + // Attempts to dequeue several elements from the queue. + // Returns the number of items actually dequeued. + // Returns 0 if all producer streams appeared empty at the time they + // were checked (so, the queue is likely but not guaranteed to be empty). + // Never allocates. Thread-safe. + template + size_t try_dequeue_bulk(It itemFirst, size_t max) + { + size_t count = 0; + for (auto ptr = producerListTail.load(std::memory_order_acquire); ptr != nullptr; ptr = ptr->next_prod()) { + count += ptr->dequeue_bulk(itemFirst, max - count); + if (count == max) { + break; + } + } + return count; + } + + // Attempts to dequeue several elements from the queue using an explicit consumer token. + // Returns the number of items actually dequeued. + // Returns 0 if all producer streams appeared empty at the time they + // were checked (so, the queue is likely but not guaranteed to be empty). + // Never allocates. Thread-safe. + template + size_t try_dequeue_bulk(consumer_token_t& token, It itemFirst, size_t max) + { + if (token.desiredProducer == nullptr || token.lastKnownGlobalOffset != globalExplicitConsumerOffset.load(std::memory_order_relaxed)) { + if (!update_current_producer_after_rotation(token)) { + return 0; + } + } + + size_t count = static_cast(token.currentProducer)->dequeue_bulk(itemFirst, max); + if (count == max) { + if ((token.itemsConsumedFromCurrent += static_cast(max)) >= EXPLICIT_CONSUMER_CONSUMPTION_QUOTA_BEFORE_ROTATE) { + globalExplicitConsumerOffset.fetch_add(1, std::memory_order_relaxed); + } + return max; + } + token.itemsConsumedFromCurrent += static_cast(count); + max -= count; + + auto tail = producerListTail.load(std::memory_order_acquire); + auto ptr = static_cast(token.currentProducer)->next_prod(); + if (ptr == nullptr) { + ptr = tail; + } + while (ptr != static_cast(token.currentProducer)) { + auto dequeued = ptr->dequeue_bulk(itemFirst, max); + count += dequeued; + if (dequeued != 0) { + token.currentProducer = ptr; + token.itemsConsumedFromCurrent = static_cast(dequeued); + } + if (dequeued == max) { + break; + } + max -= dequeued; + ptr = ptr->next_prod(); + if (ptr == nullptr) { + ptr = tail; + } + } + return count; + } + + + + // Attempts to dequeue from a specific producer's inner queue. + // If you happen to know which producer you want to dequeue from, this + // is significantly faster than using the general-case try_dequeue methods. + // Returns false if the producer's queue appeared empty at the time it + // was checked (so, the queue is likely but not guaranteed to be empty). + // Never allocates. Thread-safe. + template + inline bool try_dequeue_from_producer(producer_token_t const& producer, U& item) + { + return static_cast(producer.producer)->dequeue(item); + } + + // Attempts to dequeue several elements from a specific producer's inner queue. + // Returns the number of items actually dequeued. + // If you happen to know which producer you want to dequeue from, this + // is significantly faster than using the general-case try_dequeue methods. + // Returns 0 if the producer's queue appeared empty at the time it + // was checked (so, the queue is likely but not guaranteed to be empty). + // Never allocates. Thread-safe. + template + inline size_t try_dequeue_bulk_from_producer(producer_token_t const& producer, It itemFirst, size_t max) + { + return static_cast(producer.producer)->dequeue_bulk(itemFirst, max); + } + + + // Returns an estimate of the total number of elements currently in the queue. This + // estimate is only accurate if the queue has completely stabilized before it is called + // (i.e. all enqueue and dequeue operations have completed and their memory effects are + // visible on the calling thread, and no further operations start while this method is + // being called). + // Thread-safe. + size_t size_approx() const + { + size_t size = 0; + for (auto ptr = producerListTail.load(std::memory_order_acquire); ptr != nullptr; ptr = ptr->next_prod()) { + size += ptr->size_approx(); + } + return size; + } + + + // Returns true if the underlying atomic variables used by + // the queue are lock-free (they should be on most platforms). + // Thread-safe. + static bool is_lock_free() + { + return + details::static_is_lock_free::value == 2 && + details::static_is_lock_free::value == 2 && + details::static_is_lock_free::value == 2 && + details::static_is_lock_free::value == 2 && + details::static_is_lock_free::value == 2 && + details::static_is_lock_free::thread_id_numeric_size_t>::value == 2; + } + + +private: + friend struct ProducerToken; + friend struct ConsumerToken; + struct ExplicitProducer; + friend struct ExplicitProducer; + struct ImplicitProducer; + friend struct ImplicitProducer; + friend class ConcurrentQueueTests; + + enum AllocationMode { CanAlloc, CannotAlloc }; + + + /////////////////////////////// + // Queue methods + /////////////////////////////// + + template + inline bool inner_enqueue(producer_token_t const& token, U&& element) + { + return static_cast(token.producer)->ConcurrentQueue::ExplicitProducer::template enqueue(std::forward(element)); + } + + template + inline bool inner_enqueue(U&& element) + { + auto producer = get_or_add_implicit_producer(); + return producer == nullptr ? false : producer->ConcurrentQueue::ImplicitProducer::template enqueue(std::forward(element)); + } + + template + inline bool inner_enqueue_bulk(producer_token_t const& token, It itemFirst, size_t count) + { + return static_cast(token.producer)->ConcurrentQueue::ExplicitProducer::template enqueue_bulk(itemFirst, count); + } + + template + inline bool inner_enqueue_bulk(It itemFirst, size_t count) + { + auto producer = get_or_add_implicit_producer(); + return producer == nullptr ? false : producer->ConcurrentQueue::ImplicitProducer::template enqueue_bulk(itemFirst, count); + } + + inline bool update_current_producer_after_rotation(consumer_token_t& token) + { + // Ah, there's been a rotation, figure out where we should be! + auto tail = producerListTail.load(std::memory_order_acquire); + if (token.desiredProducer == nullptr && tail == nullptr) { + return false; + } + auto prodCount = producerCount.load(std::memory_order_relaxed); + auto globalOffset = globalExplicitConsumerOffset.load(std::memory_order_relaxed); + if ((details::unlikely)(token.desiredProducer == nullptr)) { + // Aha, first time we're dequeueing anything. + // Figure out our local position + // Note: offset is from start, not end, but we're traversing from end -- subtract from count first + std::uint32_t offset = prodCount - 1 - (token.initialOffset % prodCount); + token.desiredProducer = tail; + for (std::uint32_t i = 0; i != offset; ++i) { + token.desiredProducer = static_cast(token.desiredProducer)->next_prod(); + if (token.desiredProducer == nullptr) { + token.desiredProducer = tail; + } + } + } + + std::uint32_t delta = globalOffset - token.lastKnownGlobalOffset; + if (delta >= prodCount) { + delta = delta % prodCount; + } + for (std::uint32_t i = 0; i != delta; ++i) { + token.desiredProducer = static_cast(token.desiredProducer)->next_prod(); + if (token.desiredProducer == nullptr) { + token.desiredProducer = tail; + } + } + + token.lastKnownGlobalOffset = globalOffset; + token.currentProducer = token.desiredProducer; + token.itemsConsumedFromCurrent = 0; + return true; + } + + + /////////////////////////// + // Free list + /////////////////////////// + + template + struct FreeListNode + { + FreeListNode() : freeListRefs(0), freeListNext(nullptr) { } + + std::atomic freeListRefs; + std::atomic freeListNext; + }; + + // A simple CAS-based lock-free free list. Not the fastest thing in the world under heavy contention, but + // simple and correct (assuming nodes are never freed until after the free list is destroyed), and fairly + // speedy under low contention. + template // N must inherit FreeListNode or have the same fields (and initialization of them) + struct FreeList + { + FreeList() : freeListHead(nullptr) { } + FreeList(FreeList&& other) : freeListHead(other.freeListHead.load(std::memory_order_relaxed)) { other.freeListHead.store(nullptr, std::memory_order_relaxed); } + void swap(FreeList& other) { details::swap_relaxed(freeListHead, other.freeListHead); } + + FreeList(FreeList const&) MOODYCAMEL_DELETE_FUNCTION; + FreeList& operator=(FreeList const&) MOODYCAMEL_DELETE_FUNCTION; + + inline void add(N* node) + { +#ifdef MCDBGQ_NOLOCKFREE_FREELIST + debug::DebugLock lock(mutex); +#endif + // We know that the should-be-on-freelist bit is 0 at this point, so it's safe to + // set it using a fetch_add + if (node->freeListRefs.fetch_add(SHOULD_BE_ON_FREELIST, std::memory_order_acq_rel) == 0) { + // Oh look! We were the last ones referencing this node, and we know + // we want to add it to the free list, so let's do it! + add_knowing_refcount_is_zero(node); + } + } + + inline N* try_get() + { +#ifdef MCDBGQ_NOLOCKFREE_FREELIST + debug::DebugLock lock(mutex); +#endif + auto head = freeListHead.load(std::memory_order_acquire); + while (head != nullptr) { + auto prevHead = head; + auto refs = head->freeListRefs.load(std::memory_order_relaxed); + if ((refs & REFS_MASK) == 0 || !head->freeListRefs.compare_exchange_strong(refs, refs + 1, std::memory_order_acquire, std::memory_order_relaxed)) { + head = freeListHead.load(std::memory_order_acquire); + continue; + } + + // Good, reference count has been incremented (it wasn't at zero), which means we can read the + // next and not worry about it changing between now and the time we do the CAS + auto next = head->freeListNext.load(std::memory_order_relaxed); + if (freeListHead.compare_exchange_strong(head, next, std::memory_order_acquire, std::memory_order_relaxed)) { + // Yay, got the node. This means it was on the list, which means shouldBeOnFreeList must be false no + // matter the refcount (because nobody else knows it's been taken off yet, it can't have been put back on). + assert((head->freeListRefs.load(std::memory_order_relaxed) & SHOULD_BE_ON_FREELIST) == 0); + + // Decrease refcount twice, once for our ref, and once for the list's ref + head->freeListRefs.fetch_sub(2, std::memory_order_release); + return head; + } + + // OK, the head must have changed on us, but we still need to decrease the refcount we increased. + // Note that we don't need to release any memory effects, but we do need to ensure that the reference + // count decrement happens-after the CAS on the head. + refs = prevHead->freeListRefs.fetch_sub(1, std::memory_order_acq_rel); + if (refs == SHOULD_BE_ON_FREELIST + 1) { + add_knowing_refcount_is_zero(prevHead); + } + } + + return nullptr; + } + + // Useful for traversing the list when there's no contention (e.g. to destroy remaining nodes) + N* head_unsafe() const { return freeListHead.load(std::memory_order_relaxed); } + + private: + inline void add_knowing_refcount_is_zero(N* node) + { + // Since the refcount is zero, and nobody can increase it once it's zero (except us, and we run + // only one copy of this method per node at a time, i.e. the single thread case), then we know + // we can safely change the next pointer of the node; however, once the refcount is back above + // zero, then other threads could increase it (happens under heavy contention, when the refcount + // goes to zero in between a load and a refcount increment of a node in try_get, then back up to + // something non-zero, then the refcount increment is done by the other thread) -- so, if the CAS + // to add the node to the actual list fails, decrease the refcount and leave the add operation to + // the next thread who puts the refcount back at zero (which could be us, hence the loop). + auto head = freeListHead.load(std::memory_order_relaxed); + while (true) { + node->freeListNext.store(head, std::memory_order_relaxed); + node->freeListRefs.store(1, std::memory_order_release); + if (!freeListHead.compare_exchange_strong(head, node, std::memory_order_release, std::memory_order_relaxed)) { + // Hmm, the add failed, but we can only try again when the refcount goes back to zero + if (node->freeListRefs.fetch_add(SHOULD_BE_ON_FREELIST - 1, std::memory_order_release) == 1) { + continue; + } + } + return; + } + } + + private: + // Implemented like a stack, but where node order doesn't matter (nodes are inserted out of order under contention) + std::atomic freeListHead; + + static const std::uint32_t REFS_MASK = 0x7FFFFFFF; + static const std::uint32_t SHOULD_BE_ON_FREELIST = 0x80000000; + +#ifdef MCDBGQ_NOLOCKFREE_FREELIST + debug::DebugMutex mutex; +#endif + }; + + + /////////////////////////// + // Block + /////////////////////////// + + enum InnerQueueContext { implicit_context = 0, explicit_context = 1 }; + + struct Block + { + Block() + : next(nullptr), elementsCompletelyDequeued(0), freeListRefs(0), freeListNext(nullptr), shouldBeOnFreeList(false), dynamicallyAllocated(true) + { +#ifdef MCDBGQ_TRACKMEM + owner = nullptr; +#endif + } + + template + inline bool is_empty() const + { + MOODYCAMEL_CONSTEXPR_IF (context == explicit_context && BLOCK_SIZE <= EXPLICIT_BLOCK_EMPTY_COUNTER_THRESHOLD) { + // Check flags + for (size_t i = 0; i < BLOCK_SIZE; ++i) { + if (!emptyFlags[i].load(std::memory_order_relaxed)) { + return false; + } + } + + // Aha, empty; make sure we have all other memory effects that happened before the empty flags were set + std::atomic_thread_fence(std::memory_order_acquire); + return true; + } + else { + // Check counter + if (elementsCompletelyDequeued.load(std::memory_order_relaxed) == BLOCK_SIZE) { + std::atomic_thread_fence(std::memory_order_acquire); + return true; + } + assert(elementsCompletelyDequeued.load(std::memory_order_relaxed) <= BLOCK_SIZE); + return false; + } + } + + // Returns true if the block is now empty (does not apply in explicit context) + template + inline bool set_empty(MOODYCAMEL_MAYBE_UNUSED index_t i) + { + MOODYCAMEL_CONSTEXPR_IF (context == explicit_context && BLOCK_SIZE <= EXPLICIT_BLOCK_EMPTY_COUNTER_THRESHOLD) { + // Set flag + assert(!emptyFlags[BLOCK_SIZE - 1 - static_cast(i & static_cast(BLOCK_SIZE - 1))].load(std::memory_order_relaxed)); + emptyFlags[BLOCK_SIZE - 1 - static_cast(i & static_cast(BLOCK_SIZE - 1))].store(true, std::memory_order_release); + return false; + } + else { + // Increment counter + auto prevVal = elementsCompletelyDequeued.fetch_add(1, std::memory_order_release); + assert(prevVal < BLOCK_SIZE); + return prevVal == BLOCK_SIZE - 1; + } + } + + // Sets multiple contiguous item statuses to 'empty' (assumes no wrapping and count > 0). + // Returns true if the block is now empty (does not apply in explicit context). + template + inline bool set_many_empty(MOODYCAMEL_MAYBE_UNUSED index_t i, size_t count) + { + MOODYCAMEL_CONSTEXPR_IF (context == explicit_context && BLOCK_SIZE <= EXPLICIT_BLOCK_EMPTY_COUNTER_THRESHOLD) { + // Set flags + std::atomic_thread_fence(std::memory_order_release); + i = BLOCK_SIZE - 1 - static_cast(i & static_cast(BLOCK_SIZE - 1)) - count + 1; + for (size_t j = 0; j != count; ++j) { + assert(!emptyFlags[i + j].load(std::memory_order_relaxed)); + emptyFlags[i + j].store(true, std::memory_order_relaxed); + } + return false; + } + else { + // Increment counter + auto prevVal = elementsCompletelyDequeued.fetch_add(count, std::memory_order_release); + assert(prevVal + count <= BLOCK_SIZE); + return prevVal + count == BLOCK_SIZE; + } + } + + template + inline void set_all_empty() + { + MOODYCAMEL_CONSTEXPR_IF (context == explicit_context && BLOCK_SIZE <= EXPLICIT_BLOCK_EMPTY_COUNTER_THRESHOLD) { + // Set all flags + for (size_t i = 0; i != BLOCK_SIZE; ++i) { + emptyFlags[i].store(true, std::memory_order_relaxed); + } + } + else { + // Reset counter + elementsCompletelyDequeued.store(BLOCK_SIZE, std::memory_order_relaxed); + } + } + + template + inline void reset_empty() + { + MOODYCAMEL_CONSTEXPR_IF (context == explicit_context && BLOCK_SIZE <= EXPLICIT_BLOCK_EMPTY_COUNTER_THRESHOLD) { + // Reset flags + for (size_t i = 0; i != BLOCK_SIZE; ++i) { + emptyFlags[i].store(false, std::memory_order_relaxed); + } + } + else { + // Reset counter + elementsCompletelyDequeued.store(0, std::memory_order_relaxed); + } + } + + inline T* operator[](index_t idx) MOODYCAMEL_NOEXCEPT { return static_cast(static_cast(elements)) + static_cast(idx & static_cast(BLOCK_SIZE - 1)); } + inline T const* operator[](index_t idx) const MOODYCAMEL_NOEXCEPT { return static_cast(static_cast(elements)) + static_cast(idx & static_cast(BLOCK_SIZE - 1)); } + + private: + static_assert(std::alignment_of::value <= sizeof(T), "The queue does not support types with an alignment greater than their size at this time"); + MOODYCAMEL_ALIGNED_TYPE_LIKE(char[sizeof(T) * BLOCK_SIZE], T) elements; + public: + Block* next; + std::atomic elementsCompletelyDequeued; + std::atomic emptyFlags[BLOCK_SIZE <= EXPLICIT_BLOCK_EMPTY_COUNTER_THRESHOLD ? BLOCK_SIZE : 1]; + public: + std::atomic freeListRefs; + std::atomic freeListNext; + std::atomic shouldBeOnFreeList; + bool dynamicallyAllocated; // Perhaps a better name for this would be 'isNotPartOfInitialBlockPool' + +#ifdef MCDBGQ_TRACKMEM + void* owner; +#endif + }; + static_assert(std::alignment_of::value >= std::alignment_of::value, "Internal error: Blocks must be at least as aligned as the type they are wrapping"); + + +#ifdef MCDBGQ_TRACKMEM +public: + struct MemStats; +private: +#endif + + /////////////////////////// + // Producer base + /////////////////////////// + + struct ProducerBase : public details::ConcurrentQueueProducerTypelessBase + { + ProducerBase(ConcurrentQueue* parent_, bool isExplicit_) : + tailIndex(0), + headIndex(0), + dequeueOptimisticCount(0), + dequeueOvercommit(0), + tailBlock(nullptr), + isExplicit(isExplicit_), + parent(parent_) + { + } + + virtual ~ProducerBase() { } + + template + inline bool dequeue(U& element) + { + if (isExplicit) { + return static_cast(this)->dequeue(element); + } + else { + return static_cast(this)->dequeue(element); + } + } + + template + inline size_t dequeue_bulk(It& itemFirst, size_t max) + { + if (isExplicit) { + return static_cast(this)->dequeue_bulk(itemFirst, max); + } + else { + return static_cast(this)->dequeue_bulk(itemFirst, max); + } + } + + inline ProducerBase* next_prod() const { return static_cast(next); } + + inline size_t size_approx() const + { + auto tail = tailIndex.load(std::memory_order_relaxed); + auto head = headIndex.load(std::memory_order_relaxed); + return details::circular_less_than(head, tail) ? static_cast(tail - head) : 0; + } + + inline index_t getTail() const { return tailIndex.load(std::memory_order_relaxed); } + protected: + std::atomic tailIndex; // Where to enqueue to next + std::atomic headIndex; // Where to dequeue from next + + std::atomic dequeueOptimisticCount; + std::atomic dequeueOvercommit; + + Block* tailBlock; + + public: + bool isExplicit; + ConcurrentQueue* parent; + + protected: +#ifdef MCDBGQ_TRACKMEM + friend struct MemStats; +#endif + }; + + + /////////////////////////// + // Explicit queue + /////////////////////////// + + struct ExplicitProducer : public ProducerBase + { + explicit ExplicitProducer(ConcurrentQueue* parent_) : + ProducerBase(parent_, true), + blockIndex(nullptr), + pr_blockIndexSlotsUsed(0), + pr_blockIndexSize(EXPLICIT_INITIAL_INDEX_SIZE >> 1), + pr_blockIndexFront(0), + pr_blockIndexEntries(nullptr), + pr_blockIndexRaw(nullptr) + { + size_t poolBasedIndexSize = details::ceil_to_pow_2(parent_->initialBlockPoolSize) >> 1; + if (poolBasedIndexSize > pr_blockIndexSize) { + pr_blockIndexSize = poolBasedIndexSize; + } + + new_block_index(0); // This creates an index with double the number of current entries, i.e. EXPLICIT_INITIAL_INDEX_SIZE + } + + ~ExplicitProducer() + { + // Destruct any elements not yet dequeued. + // Since we're in the destructor, we can assume all elements + // are either completely dequeued or completely not (no halfways). + if (this->tailBlock != nullptr) { // Note this means there must be a block index too + // First find the block that's partially dequeued, if any + Block* halfDequeuedBlock = nullptr; + if ((this->headIndex.load(std::memory_order_relaxed) & static_cast(BLOCK_SIZE - 1)) != 0) { + // The head's not on a block boundary, meaning a block somewhere is partially dequeued + // (or the head block is the tail block and was fully dequeued, but the head/tail are still not on a boundary) + size_t i = (pr_blockIndexFront - pr_blockIndexSlotsUsed) & (pr_blockIndexSize - 1); + while (details::circular_less_than(pr_blockIndexEntries[i].base + BLOCK_SIZE, this->headIndex.load(std::memory_order_relaxed))) { + i = (i + 1) & (pr_blockIndexSize - 1); + } + assert(details::circular_less_than(pr_blockIndexEntries[i].base, this->headIndex.load(std::memory_order_relaxed))); + halfDequeuedBlock = pr_blockIndexEntries[i].block; + } + + // Start at the head block (note the first line in the loop gives us the head from the tail on the first iteration) + auto block = this->tailBlock; + do { + block = block->next; + if (block->ConcurrentQueue::Block::template is_empty()) { + continue; + } + + size_t i = 0; // Offset into block + if (block == halfDequeuedBlock) { + i = static_cast(this->headIndex.load(std::memory_order_relaxed) & static_cast(BLOCK_SIZE - 1)); + } + + // Walk through all the items in the block; if this is the tail block, we need to stop when we reach the tail index + auto lastValidIndex = (this->tailIndex.load(std::memory_order_relaxed) & static_cast(BLOCK_SIZE - 1)) == 0 ? BLOCK_SIZE : static_cast(this->tailIndex.load(std::memory_order_relaxed) & static_cast(BLOCK_SIZE - 1)); + while (i != BLOCK_SIZE && (block != this->tailBlock || i != lastValidIndex)) { + (*block)[i++]->~T(); + } + } while (block != this->tailBlock); + } + + // Destroy all blocks that we own + if (this->tailBlock != nullptr) { + auto block = this->tailBlock; + do { + auto nextBlock = block->next; + if (block->dynamicallyAllocated) { + destroy(block); + } + else { + this->parent->add_block_to_free_list(block); + } + block = nextBlock; + } while (block != this->tailBlock); + } + + // Destroy the block indices + auto header = static_cast(pr_blockIndexRaw); + while (header != nullptr) { + auto prev = static_cast(header->prev); + header->~BlockIndexHeader(); + (Traits::free)(header); + header = prev; + } + } + + template + inline bool enqueue(U&& element) + { + index_t currentTailIndex = this->tailIndex.load(std::memory_order_relaxed); + index_t newTailIndex = 1 + currentTailIndex; + if ((currentTailIndex & static_cast(BLOCK_SIZE - 1)) == 0) { + // We reached the end of a block, start a new one + auto startBlock = this->tailBlock; + auto originalBlockIndexSlotsUsed = pr_blockIndexSlotsUsed; + if (this->tailBlock != nullptr && this->tailBlock->next->ConcurrentQueue::Block::template is_empty()) { + // We can re-use the block ahead of us, it's empty! + this->tailBlock = this->tailBlock->next; + this->tailBlock->ConcurrentQueue::Block::template reset_empty(); + + // We'll put the block on the block index (guaranteed to be room since we're conceptually removing the + // last block from it first -- except instead of removing then adding, we can just overwrite). + // Note that there must be a valid block index here, since even if allocation failed in the ctor, + // it would have been re-attempted when adding the first block to the queue; since there is such + // a block, a block index must have been successfully allocated. + } + else { + // Whatever head value we see here is >= the last value we saw here (relatively), + // and <= its current value. Since we have the most recent tail, the head must be + // <= to it. + auto head = this->headIndex.load(std::memory_order_relaxed); + assert(!details::circular_less_than(currentTailIndex, head)); + if (!details::circular_less_than(head, currentTailIndex + BLOCK_SIZE) + || (MAX_SUBQUEUE_SIZE != details::const_numeric_max::value && (MAX_SUBQUEUE_SIZE == 0 || MAX_SUBQUEUE_SIZE - BLOCK_SIZE < currentTailIndex - head))) { + // We can't enqueue in another block because there's not enough leeway -- the + // tail could surpass the head by the time the block fills up! (Or we'll exceed + // the size limit, if the second part of the condition was true.) + return false; + } + // We're going to need a new block; check that the block index has room + if (pr_blockIndexRaw == nullptr || pr_blockIndexSlotsUsed == pr_blockIndexSize) { + // Hmm, the circular block index is already full -- we'll need + // to allocate a new index. Note pr_blockIndexRaw can only be nullptr if + // the initial allocation failed in the constructor. + + MOODYCAMEL_CONSTEXPR_IF (allocMode == CannotAlloc) { + return false; + } + else if (!new_block_index(pr_blockIndexSlotsUsed)) { + return false; + } + } + + // Insert a new block in the circular linked list + auto newBlock = this->parent->ConcurrentQueue::template requisition_block(); + if (newBlock == nullptr) { + return false; + } +#ifdef MCDBGQ_TRACKMEM + newBlock->owner = this; +#endif + newBlock->ConcurrentQueue::Block::template reset_empty(); + if (this->tailBlock == nullptr) { + newBlock->next = newBlock; + } + else { + newBlock->next = this->tailBlock->next; + this->tailBlock->next = newBlock; + } + this->tailBlock = newBlock; + ++pr_blockIndexSlotsUsed; + } + + MOODYCAMEL_CONSTEXPR_IF (!MOODYCAMEL_NOEXCEPT_CTOR(T, U, new (static_cast(nullptr)) T(std::forward(element)))) { + // The constructor may throw. We want the element not to appear in the queue in + // that case (without corrupting the queue): + MOODYCAMEL_TRY { + new ((*this->tailBlock)[currentTailIndex]) T(std::forward(element)); + } + MOODYCAMEL_CATCH (...) { + // Revert change to the current block, but leave the new block available + // for next time + pr_blockIndexSlotsUsed = originalBlockIndexSlotsUsed; + this->tailBlock = startBlock == nullptr ? this->tailBlock : startBlock; + MOODYCAMEL_RETHROW; + } + } + else { + (void)startBlock; + (void)originalBlockIndexSlotsUsed; + } + + // Add block to block index + auto& entry = blockIndex.load(std::memory_order_relaxed)->entries[pr_blockIndexFront]; + entry.base = currentTailIndex; + entry.block = this->tailBlock; + blockIndex.load(std::memory_order_relaxed)->front.store(pr_blockIndexFront, std::memory_order_release); + pr_blockIndexFront = (pr_blockIndexFront + 1) & (pr_blockIndexSize - 1); + + MOODYCAMEL_CONSTEXPR_IF (!MOODYCAMEL_NOEXCEPT_CTOR(T, U, new (static_cast(nullptr)) T(std::forward(element)))) { + this->tailIndex.store(newTailIndex, std::memory_order_release); + return true; + } + } + + // Enqueue + new ((*this->tailBlock)[currentTailIndex]) T(std::forward(element)); + + this->tailIndex.store(newTailIndex, std::memory_order_release); + return true; + } + + template + bool dequeue(U& element) + { + auto tail = this->tailIndex.load(std::memory_order_relaxed); + auto overcommit = this->dequeueOvercommit.load(std::memory_order_relaxed); + if (details::circular_less_than(this->dequeueOptimisticCount.load(std::memory_order_relaxed) - overcommit, tail)) { + // Might be something to dequeue, let's give it a try + + // Note that this if is purely for performance purposes in the common case when the queue is + // empty and the values are eventually consistent -- we may enter here spuriously. + + // Note that whatever the values of overcommit and tail are, they are not going to change (unless we + // change them) and must be the same value at this point (inside the if) as when the if condition was + // evaluated. + + // We insert an acquire fence here to synchronize-with the release upon incrementing dequeueOvercommit below. + // This ensures that whatever the value we got loaded into overcommit, the load of dequeueOptisticCount in + // the fetch_add below will result in a value at least as recent as that (and therefore at least as large). + // Note that I believe a compiler (signal) fence here would be sufficient due to the nature of fetch_add (all + // read-modify-write operations are guaranteed to work on the latest value in the modification order), but + // unfortunately that can't be shown to be correct using only the C++11 standard. + // See http://stackoverflow.com/questions/18223161/what-are-the-c11-memory-ordering-guarantees-in-this-corner-case + std::atomic_thread_fence(std::memory_order_acquire); + + // Increment optimistic counter, then check if it went over the boundary + auto myDequeueCount = this->dequeueOptimisticCount.fetch_add(1, std::memory_order_relaxed); + + // Note that since dequeueOvercommit must be <= dequeueOptimisticCount (because dequeueOvercommit is only ever + // incremented after dequeueOptimisticCount -- this is enforced in the `else` block below), and since we now + // have a version of dequeueOptimisticCount that is at least as recent as overcommit (due to the release upon + // incrementing dequeueOvercommit and the acquire above that synchronizes with it), overcommit <= myDequeueCount. + // However, we can't assert this since both dequeueOptimisticCount and dequeueOvercommit may (independently) + // overflow; in such a case, though, the logic still holds since the difference between the two is maintained. + + // Note that we reload tail here in case it changed; it will be the same value as before or greater, since + // this load is sequenced after (happens after) the earlier load above. This is supported by read-read + // coherency (as defined in the standard), explained here: http://en.cppreference.com/w/cpp/atomic/memory_order + tail = this->tailIndex.load(std::memory_order_acquire); + if ((details::likely)(details::circular_less_than(myDequeueCount - overcommit, tail))) { + // Guaranteed to be at least one element to dequeue! + + // Get the index. Note that since there's guaranteed to be at least one element, this + // will never exceed tail. We need to do an acquire-release fence here since it's possible + // that whatever condition got us to this point was for an earlier enqueued element (that + // we already see the memory effects for), but that by the time we increment somebody else + // has incremented it, and we need to see the memory effects for *that* element, which is + // in such a case is necessarily visible on the thread that incremented it in the first + // place with the more current condition (they must have acquired a tail that is at least + // as recent). + auto index = this->headIndex.fetch_add(1, std::memory_order_acq_rel); + + + // Determine which block the element is in + + auto localBlockIndex = blockIndex.load(std::memory_order_acquire); + auto localBlockIndexHead = localBlockIndex->front.load(std::memory_order_acquire); + + // We need to be careful here about subtracting and dividing because of index wrap-around. + // When an index wraps, we need to preserve the sign of the offset when dividing it by the + // block size (in order to get a correct signed block count offset in all cases): + auto headBase = localBlockIndex->entries[localBlockIndexHead].base; + auto blockBaseIndex = index & ~static_cast(BLOCK_SIZE - 1); + auto offset = static_cast(static_cast::type>(blockBaseIndex - headBase) / BLOCK_SIZE); + auto block = localBlockIndex->entries[(localBlockIndexHead + offset) & (localBlockIndex->size - 1)].block; + + // Dequeue + auto& el = *((*block)[index]); + if (!MOODYCAMEL_NOEXCEPT_ASSIGN(T, T&&, element = std::move(el))) { + // Make sure the element is still fully dequeued and destroyed even if the assignment + // throws + struct Guard { + Block* block; + index_t index; + + ~Guard() + { + (*block)[index]->~T(); + block->ConcurrentQueue::Block::template set_empty(index); + } + } guard = { block, index }; + + element = std::move(el); // NOLINT + } + else { + element = std::move(el); // NOLINT + el.~T(); // NOLINT + block->ConcurrentQueue::Block::template set_empty(index); + } + + return true; + } + else { + // Wasn't anything to dequeue after all; make the effective dequeue count eventually consistent + this->dequeueOvercommit.fetch_add(1, std::memory_order_release); // Release so that the fetch_add on dequeueOptimisticCount is guaranteed to happen before this write + } + } + + return false; + } + + template + bool MOODYCAMEL_NO_TSAN enqueue_bulk(It itemFirst, size_t count) + { + // First, we need to make sure we have enough room to enqueue all of the elements; + // this means pre-allocating blocks and putting them in the block index (but only if + // all the allocations succeeded). + index_t startTailIndex = this->tailIndex.load(std::memory_order_relaxed); + auto startBlock = this->tailBlock; + auto originalBlockIndexFront = pr_blockIndexFront; + auto originalBlockIndexSlotsUsed = pr_blockIndexSlotsUsed; + + Block* firstAllocatedBlock = nullptr; + + // Figure out how many blocks we'll need to allocate, and do so + size_t blockBaseDiff = ((startTailIndex + count - 1) & ~static_cast(BLOCK_SIZE - 1)) - ((startTailIndex - 1) & ~static_cast(BLOCK_SIZE - 1)); + index_t currentTailIndex = (startTailIndex - 1) & ~static_cast(BLOCK_SIZE - 1); + if (blockBaseDiff > 0) { + // Allocate as many blocks as possible from ahead + while (blockBaseDiff > 0 && this->tailBlock != nullptr && this->tailBlock->next != firstAllocatedBlock && this->tailBlock->next->ConcurrentQueue::Block::template is_empty()) { + blockBaseDiff -= static_cast(BLOCK_SIZE); + currentTailIndex += static_cast(BLOCK_SIZE); + + this->tailBlock = this->tailBlock->next; + firstAllocatedBlock = firstAllocatedBlock == nullptr ? this->tailBlock : firstAllocatedBlock; + + auto& entry = blockIndex.load(std::memory_order_relaxed)->entries[pr_blockIndexFront]; + entry.base = currentTailIndex; + entry.block = this->tailBlock; + pr_blockIndexFront = (pr_blockIndexFront + 1) & (pr_blockIndexSize - 1); + } + + // Now allocate as many blocks as necessary from the block pool + while (blockBaseDiff > 0) { + blockBaseDiff -= static_cast(BLOCK_SIZE); + currentTailIndex += static_cast(BLOCK_SIZE); + + auto head = this->headIndex.load(std::memory_order_relaxed); + assert(!details::circular_less_than(currentTailIndex, head)); + bool full = !details::circular_less_than(head, currentTailIndex + BLOCK_SIZE) || (MAX_SUBQUEUE_SIZE != details::const_numeric_max::value && (MAX_SUBQUEUE_SIZE == 0 || MAX_SUBQUEUE_SIZE - BLOCK_SIZE < currentTailIndex - head)); + if (pr_blockIndexRaw == nullptr || pr_blockIndexSlotsUsed == pr_blockIndexSize || full) { + MOODYCAMEL_CONSTEXPR_IF (allocMode == CannotAlloc) { + // Failed to allocate, undo changes (but keep injected blocks) + pr_blockIndexFront = originalBlockIndexFront; + pr_blockIndexSlotsUsed = originalBlockIndexSlotsUsed; + this->tailBlock = startBlock == nullptr ? firstAllocatedBlock : startBlock; + return false; + } + else if (full || !new_block_index(originalBlockIndexSlotsUsed)) { + // Failed to allocate, undo changes (but keep injected blocks) + pr_blockIndexFront = originalBlockIndexFront; + pr_blockIndexSlotsUsed = originalBlockIndexSlotsUsed; + this->tailBlock = startBlock == nullptr ? firstAllocatedBlock : startBlock; + return false; + } + + // pr_blockIndexFront is updated inside new_block_index, so we need to + // update our fallback value too (since we keep the new index even if we + // later fail) + originalBlockIndexFront = originalBlockIndexSlotsUsed; + } + + // Insert a new block in the circular linked list + auto newBlock = this->parent->ConcurrentQueue::template requisition_block(); + if (newBlock == nullptr) { + pr_blockIndexFront = originalBlockIndexFront; + pr_blockIndexSlotsUsed = originalBlockIndexSlotsUsed; + this->tailBlock = startBlock == nullptr ? firstAllocatedBlock : startBlock; + return false; + } + +#ifdef MCDBGQ_TRACKMEM + newBlock->owner = this; +#endif + newBlock->ConcurrentQueue::Block::template set_all_empty(); + if (this->tailBlock == nullptr) { + newBlock->next = newBlock; + } + else { + newBlock->next = this->tailBlock->next; + this->tailBlock->next = newBlock; + } + this->tailBlock = newBlock; + firstAllocatedBlock = firstAllocatedBlock == nullptr ? this->tailBlock : firstAllocatedBlock; + + ++pr_blockIndexSlotsUsed; + + auto& entry = blockIndex.load(std::memory_order_relaxed)->entries[pr_blockIndexFront]; + entry.base = currentTailIndex; + entry.block = this->tailBlock; + pr_blockIndexFront = (pr_blockIndexFront + 1) & (pr_blockIndexSize - 1); + } + + // Excellent, all allocations succeeded. Reset each block's emptiness before we fill them up, and + // publish the new block index front + auto block = firstAllocatedBlock; + while (true) { + block->ConcurrentQueue::Block::template reset_empty(); + if (block == this->tailBlock) { + break; + } + block = block->next; + } + + MOODYCAMEL_CONSTEXPR_IF (MOODYCAMEL_NOEXCEPT_CTOR(T, decltype(*itemFirst), new (static_cast(nullptr)) T(details::deref_noexcept(itemFirst)))) { + blockIndex.load(std::memory_order_relaxed)->front.store((pr_blockIndexFront - 1) & (pr_blockIndexSize - 1), std::memory_order_release); + } + } + + // Enqueue, one block at a time + index_t newTailIndex = startTailIndex + static_cast(count); + currentTailIndex = startTailIndex; + auto endBlock = this->tailBlock; + this->tailBlock = startBlock; + assert((startTailIndex & static_cast(BLOCK_SIZE - 1)) != 0 || firstAllocatedBlock != nullptr || count == 0); + if ((startTailIndex & static_cast(BLOCK_SIZE - 1)) == 0 && firstAllocatedBlock != nullptr) { + this->tailBlock = firstAllocatedBlock; + } + while (true) { + index_t stopIndex = (currentTailIndex & ~static_cast(BLOCK_SIZE - 1)) + static_cast(BLOCK_SIZE); + if (details::circular_less_than(newTailIndex, stopIndex)) { + stopIndex = newTailIndex; + } + MOODYCAMEL_CONSTEXPR_IF (MOODYCAMEL_NOEXCEPT_CTOR(T, decltype(*itemFirst), new (static_cast(nullptr)) T(details::deref_noexcept(itemFirst)))) { + while (currentTailIndex != stopIndex) { + new ((*this->tailBlock)[currentTailIndex++]) T(*itemFirst++); + } + } + else { + MOODYCAMEL_TRY { + while (currentTailIndex != stopIndex) { + // Must use copy constructor even if move constructor is available + // because we may have to revert if there's an exception. + // Sorry about the horrible templated next line, but it was the only way + // to disable moving *at compile time*, which is important because a type + // may only define a (noexcept) move constructor, and so calls to the + // cctor will not compile, even if they are in an if branch that will never + // be executed + new ((*this->tailBlock)[currentTailIndex]) T(details::nomove_if(nullptr)) T(details::deref_noexcept(itemFirst)))>::eval(*itemFirst)); + ++currentTailIndex; + ++itemFirst; + } + } + MOODYCAMEL_CATCH (...) { + // Oh dear, an exception's been thrown -- destroy the elements that + // were enqueued so far and revert the entire bulk operation (we'll keep + // any allocated blocks in our linked list for later, though). + auto constructedStopIndex = currentTailIndex; + auto lastBlockEnqueued = this->tailBlock; + + pr_blockIndexFront = originalBlockIndexFront; + pr_blockIndexSlotsUsed = originalBlockIndexSlotsUsed; + this->tailBlock = startBlock == nullptr ? firstAllocatedBlock : startBlock; + + if (!details::is_trivially_destructible::value) { + auto block = startBlock; + if ((startTailIndex & static_cast(BLOCK_SIZE - 1)) == 0) { + block = firstAllocatedBlock; + } + currentTailIndex = startTailIndex; + while (true) { + stopIndex = (currentTailIndex & ~static_cast(BLOCK_SIZE - 1)) + static_cast(BLOCK_SIZE); + if (details::circular_less_than(constructedStopIndex, stopIndex)) { + stopIndex = constructedStopIndex; + } + while (currentTailIndex != stopIndex) { + (*block)[currentTailIndex++]->~T(); + } + if (block == lastBlockEnqueued) { + break; + } + block = block->next; + } + } + MOODYCAMEL_RETHROW; + } + } + + if (this->tailBlock == endBlock) { + assert(currentTailIndex == newTailIndex); + break; + } + this->tailBlock = this->tailBlock->next; + } + + MOODYCAMEL_CONSTEXPR_IF (!MOODYCAMEL_NOEXCEPT_CTOR(T, decltype(*itemFirst), new (static_cast(nullptr)) T(details::deref_noexcept(itemFirst)))) { + if (firstAllocatedBlock != nullptr) + blockIndex.load(std::memory_order_relaxed)->front.store((pr_blockIndexFront - 1) & (pr_blockIndexSize - 1), std::memory_order_release); + } + + this->tailIndex.store(newTailIndex, std::memory_order_release); + return true; + } + + template + size_t dequeue_bulk(It& itemFirst, size_t max) + { + auto tail = this->tailIndex.load(std::memory_order_relaxed); + auto overcommit = this->dequeueOvercommit.load(std::memory_order_relaxed); + auto desiredCount = static_cast(tail - (this->dequeueOptimisticCount.load(std::memory_order_relaxed) - overcommit)); + if (details::circular_less_than(0, desiredCount)) { + desiredCount = desiredCount < max ? desiredCount : max; + std::atomic_thread_fence(std::memory_order_acquire); + + auto myDequeueCount = this->dequeueOptimisticCount.fetch_add(desiredCount, std::memory_order_relaxed); + + tail = this->tailIndex.load(std::memory_order_acquire); + auto actualCount = static_cast(tail - (myDequeueCount - overcommit)); + if (details::circular_less_than(0, actualCount)) { + actualCount = desiredCount < actualCount ? desiredCount : actualCount; + if (actualCount < desiredCount) { + this->dequeueOvercommit.fetch_add(desiredCount - actualCount, std::memory_order_release); + } + + // Get the first index. Note that since there's guaranteed to be at least actualCount elements, this + // will never exceed tail. + auto firstIndex = this->headIndex.fetch_add(actualCount, std::memory_order_acq_rel); + + // Determine which block the first element is in + auto localBlockIndex = blockIndex.load(std::memory_order_acquire); + auto localBlockIndexHead = localBlockIndex->front.load(std::memory_order_acquire); + + auto headBase = localBlockIndex->entries[localBlockIndexHead].base; + auto firstBlockBaseIndex = firstIndex & ~static_cast(BLOCK_SIZE - 1); + auto offset = static_cast(static_cast::type>(firstBlockBaseIndex - headBase) / BLOCK_SIZE); + auto indexIndex = (localBlockIndexHead + offset) & (localBlockIndex->size - 1); + + // Iterate the blocks and dequeue + auto index = firstIndex; + do { + auto firstIndexInBlock = index; + index_t endIndex = (index & ~static_cast(BLOCK_SIZE - 1)) + static_cast(BLOCK_SIZE); + endIndex = details::circular_less_than(firstIndex + static_cast(actualCount), endIndex) ? firstIndex + static_cast(actualCount) : endIndex; + auto block = localBlockIndex->entries[indexIndex].block; + if (MOODYCAMEL_NOEXCEPT_ASSIGN(T, T&&, details::deref_noexcept(itemFirst) = std::move((*(*block)[index])))) { + while (index != endIndex) { + auto& el = *((*block)[index]); + *itemFirst++ = std::move(el); + el.~T(); + ++index; + } + } + else { + MOODYCAMEL_TRY { + while (index != endIndex) { + auto& el = *((*block)[index]); + *itemFirst = std::move(el); + ++itemFirst; + el.~T(); + ++index; + } + } + MOODYCAMEL_CATCH (...) { + // It's too late to revert the dequeue, but we can make sure that all + // the dequeued objects are properly destroyed and the block index + // (and empty count) are properly updated before we propagate the exception + do { + block = localBlockIndex->entries[indexIndex].block; + while (index != endIndex) { + (*block)[index++]->~T(); + } + block->ConcurrentQueue::Block::template set_many_empty(firstIndexInBlock, static_cast(endIndex - firstIndexInBlock)); + indexIndex = (indexIndex + 1) & (localBlockIndex->size - 1); + + firstIndexInBlock = index; + endIndex = (index & ~static_cast(BLOCK_SIZE - 1)) + static_cast(BLOCK_SIZE); + endIndex = details::circular_less_than(firstIndex + static_cast(actualCount), endIndex) ? firstIndex + static_cast(actualCount) : endIndex; + } while (index != firstIndex + actualCount); + + MOODYCAMEL_RETHROW; + } + } + block->ConcurrentQueue::Block::template set_many_empty(firstIndexInBlock, static_cast(endIndex - firstIndexInBlock)); + indexIndex = (indexIndex + 1) & (localBlockIndex->size - 1); + } while (index != firstIndex + actualCount); + + return actualCount; + } + else { + // Wasn't anything to dequeue after all; make the effective dequeue count eventually consistent + this->dequeueOvercommit.fetch_add(desiredCount, std::memory_order_release); + } + } + + return 0; + } + + private: + struct BlockIndexEntry + { + index_t base; + Block* block; + }; + + struct BlockIndexHeader + { + size_t size; + std::atomic front; // Current slot (not next, like pr_blockIndexFront) + BlockIndexEntry* entries; + void* prev; + }; + + + bool new_block_index(size_t numberOfFilledSlotsToExpose) + { + auto prevBlockSizeMask = pr_blockIndexSize - 1; + + // Create the new block + pr_blockIndexSize <<= 1; + auto newRawPtr = static_cast((Traits::malloc)(sizeof(BlockIndexHeader) + std::alignment_of::value - 1 + sizeof(BlockIndexEntry) * pr_blockIndexSize)); + if (newRawPtr == nullptr) { + pr_blockIndexSize >>= 1; // Reset to allow graceful retry + return false; + } + + auto newBlockIndexEntries = reinterpret_cast(details::align_for(newRawPtr + sizeof(BlockIndexHeader))); + + // Copy in all the old indices, if any + size_t j = 0; + if (pr_blockIndexSlotsUsed != 0) { + auto i = (pr_blockIndexFront - pr_blockIndexSlotsUsed) & prevBlockSizeMask; + do { + newBlockIndexEntries[j++] = pr_blockIndexEntries[i]; + i = (i + 1) & prevBlockSizeMask; + } while (i != pr_blockIndexFront); + } + + // Update everything + auto header = new (newRawPtr) BlockIndexHeader; + header->size = pr_blockIndexSize; + header->front.store(numberOfFilledSlotsToExpose - 1, std::memory_order_relaxed); + header->entries = newBlockIndexEntries; + header->prev = pr_blockIndexRaw; // we link the new block to the old one so we can free it later + + pr_blockIndexFront = j; + pr_blockIndexEntries = newBlockIndexEntries; + pr_blockIndexRaw = newRawPtr; + blockIndex.store(header, std::memory_order_release); + + return true; + } + + private: + std::atomic blockIndex; + + // To be used by producer only -- consumer must use the ones in referenced by blockIndex + size_t pr_blockIndexSlotsUsed; + size_t pr_blockIndexSize; + size_t pr_blockIndexFront; // Next slot (not current) + BlockIndexEntry* pr_blockIndexEntries; + void* pr_blockIndexRaw; + +#ifdef MOODYCAMEL_QUEUE_INTERNAL_DEBUG + public: + ExplicitProducer* nextExplicitProducer; + private: +#endif + +#ifdef MCDBGQ_TRACKMEM + friend struct MemStats; +#endif + }; + + + ////////////////////////////////// + // Implicit queue + ////////////////////////////////// + + struct ImplicitProducer : public ProducerBase + { + ImplicitProducer(ConcurrentQueue* parent_) : + ProducerBase(parent_, false), + nextBlockIndexCapacity(IMPLICIT_INITIAL_INDEX_SIZE), + blockIndex(nullptr) + { + new_block_index(); + } + + ~ImplicitProducer() + { + // Note that since we're in the destructor we can assume that all enqueue/dequeue operations + // completed already; this means that all undequeued elements are placed contiguously across + // contiguous blocks, and that only the first and last remaining blocks can be only partially + // empty (all other remaining blocks must be completely full). + +#ifdef MOODYCAMEL_CPP11_THREAD_LOCAL_SUPPORTED + // Unregister ourselves for thread termination notification + if (!this->inactive.load(std::memory_order_relaxed)) { + details::ThreadExitNotifier::unsubscribe(&threadExitListener); + } +#endif + + // Destroy all remaining elements! + auto tail = this->tailIndex.load(std::memory_order_relaxed); + auto index = this->headIndex.load(std::memory_order_relaxed); + Block* block = nullptr; + assert(index == tail || details::circular_less_than(index, tail)); + bool forceFreeLastBlock = index != tail; // If we enter the loop, then the last (tail) block will not be freed + while (index != tail) { + if ((index & static_cast(BLOCK_SIZE - 1)) == 0 || block == nullptr) { + if (block != nullptr) { + // Free the old block + this->parent->add_block_to_free_list(block); + } + + block = get_block_index_entry_for_index(index)->value.load(std::memory_order_relaxed); + } + + ((*block)[index])->~T(); + ++index; + } + // Even if the queue is empty, there's still one block that's not on the free list + // (unless the head index reached the end of it, in which case the tail will be poised + // to create a new block). + if (this->tailBlock != nullptr && (forceFreeLastBlock || (tail & static_cast(BLOCK_SIZE - 1)) != 0)) { + this->parent->add_block_to_free_list(this->tailBlock); + } + + // Destroy block index + auto localBlockIndex = blockIndex.load(std::memory_order_relaxed); + if (localBlockIndex != nullptr) { + for (size_t i = 0; i != localBlockIndex->capacity; ++i) { + localBlockIndex->index[i]->~BlockIndexEntry(); + } + do { + auto prev = localBlockIndex->prev; + localBlockIndex->~BlockIndexHeader(); + (Traits::free)(localBlockIndex); + localBlockIndex = prev; + } while (localBlockIndex != nullptr); + } + } + + template + inline bool enqueue(U&& element) + { + index_t currentTailIndex = this->tailIndex.load(std::memory_order_relaxed); + index_t newTailIndex = 1 + currentTailIndex; + if ((currentTailIndex & static_cast(BLOCK_SIZE - 1)) == 0) { + // We reached the end of a block, start a new one + auto head = this->headIndex.load(std::memory_order_relaxed); + assert(!details::circular_less_than(currentTailIndex, head)); + if (!details::circular_less_than(head, currentTailIndex + BLOCK_SIZE) || (MAX_SUBQUEUE_SIZE != details::const_numeric_max::value && (MAX_SUBQUEUE_SIZE == 0 || MAX_SUBQUEUE_SIZE - BLOCK_SIZE < currentTailIndex - head))) { + return false; + } +#ifdef MCDBGQ_NOLOCKFREE_IMPLICITPRODBLOCKINDEX + debug::DebugLock lock(mutex); +#endif + // Find out where we'll be inserting this block in the block index + BlockIndexEntry* idxEntry; + if (!insert_block_index_entry(idxEntry, currentTailIndex)) { + return false; + } + + // Get ahold of a new block + auto newBlock = this->parent->ConcurrentQueue::template requisition_block(); + if (newBlock == nullptr) { + rewind_block_index_tail(); + idxEntry->value.store(nullptr, std::memory_order_relaxed); + return false; + } +#ifdef MCDBGQ_TRACKMEM + newBlock->owner = this; +#endif + newBlock->ConcurrentQueue::Block::template reset_empty(); + + MOODYCAMEL_CONSTEXPR_IF (!MOODYCAMEL_NOEXCEPT_CTOR(T, U, new (static_cast(nullptr)) T(std::forward(element)))) { + // May throw, try to insert now before we publish the fact that we have this new block + MOODYCAMEL_TRY { + new ((*newBlock)[currentTailIndex]) T(std::forward(element)); + } + MOODYCAMEL_CATCH (...) { + rewind_block_index_tail(); + idxEntry->value.store(nullptr, std::memory_order_relaxed); + this->parent->add_block_to_free_list(newBlock); + MOODYCAMEL_RETHROW; + } + } + + // Insert the new block into the index + idxEntry->value.store(newBlock, std::memory_order_relaxed); + + this->tailBlock = newBlock; + + MOODYCAMEL_CONSTEXPR_IF (!MOODYCAMEL_NOEXCEPT_CTOR(T, U, new (static_cast(nullptr)) T(std::forward(element)))) { + this->tailIndex.store(newTailIndex, std::memory_order_release); + return true; + } + } + + // Enqueue + new ((*this->tailBlock)[currentTailIndex]) T(std::forward(element)); + + this->tailIndex.store(newTailIndex, std::memory_order_release); + return true; + } + + template + bool dequeue(U& element) + { + // See ExplicitProducer::dequeue for rationale and explanation + index_t tail = this->tailIndex.load(std::memory_order_relaxed); + index_t overcommit = this->dequeueOvercommit.load(std::memory_order_relaxed); + if (details::circular_less_than(this->dequeueOptimisticCount.load(std::memory_order_relaxed) - overcommit, tail)) { + std::atomic_thread_fence(std::memory_order_acquire); + + index_t myDequeueCount = this->dequeueOptimisticCount.fetch_add(1, std::memory_order_relaxed); + tail = this->tailIndex.load(std::memory_order_acquire); + if ((details::likely)(details::circular_less_than(myDequeueCount - overcommit, tail))) { + index_t index = this->headIndex.fetch_add(1, std::memory_order_acq_rel); + + // Determine which block the element is in + auto entry = get_block_index_entry_for_index(index); + + // Dequeue + auto block = entry->value.load(std::memory_order_relaxed); + auto& el = *((*block)[index]); + + if (!MOODYCAMEL_NOEXCEPT_ASSIGN(T, T&&, element = std::move(el))) { +#ifdef MCDBGQ_NOLOCKFREE_IMPLICITPRODBLOCKINDEX + // Note: Acquiring the mutex with every dequeue instead of only when a block + // is released is very sub-optimal, but it is, after all, purely debug code. + debug::DebugLock lock(producer->mutex); +#endif + struct Guard { + Block* block; + index_t index; + BlockIndexEntry* entry; + ConcurrentQueue* parent; + + ~Guard() + { + (*block)[index]->~T(); + if (block->ConcurrentQueue::Block::template set_empty(index)) { + entry->value.store(nullptr, std::memory_order_relaxed); + parent->add_block_to_free_list(block); + } + } + } guard = { block, index, entry, this->parent }; + + element = std::move(el); // NOLINT + } + else { + element = std::move(el); // NOLINT + el.~T(); // NOLINT + + if (block->ConcurrentQueue::Block::template set_empty(index)) { + { +#ifdef MCDBGQ_NOLOCKFREE_IMPLICITPRODBLOCKINDEX + debug::DebugLock lock(mutex); +#endif + // Add the block back into the global free pool (and remove from block index) + entry->value.store(nullptr, std::memory_order_relaxed); + } + this->parent->add_block_to_free_list(block); // releases the above store + } + } + + return true; + } + else { + this->dequeueOvercommit.fetch_add(1, std::memory_order_release); + } + } + + return false; + } + +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable: 4706) // assignment within conditional expression +#endif + template + bool enqueue_bulk(It itemFirst, size_t count) + { + // First, we need to make sure we have enough room to enqueue all of the elements; + // this means pre-allocating blocks and putting them in the block index (but only if + // all the allocations succeeded). + + // Note that the tailBlock we start off with may not be owned by us any more; + // this happens if it was filled up exactly to the top (setting tailIndex to + // the first index of the next block which is not yet allocated), then dequeued + // completely (putting it on the free list) before we enqueue again. + + index_t startTailIndex = this->tailIndex.load(std::memory_order_relaxed); + auto startBlock = this->tailBlock; + Block* firstAllocatedBlock = nullptr; + auto endBlock = this->tailBlock; + + // Figure out how many blocks we'll need to allocate, and do so + size_t blockBaseDiff = ((startTailIndex + count - 1) & ~static_cast(BLOCK_SIZE - 1)) - ((startTailIndex - 1) & ~static_cast(BLOCK_SIZE - 1)); + index_t currentTailIndex = (startTailIndex - 1) & ~static_cast(BLOCK_SIZE - 1); + if (blockBaseDiff > 0) { +#ifdef MCDBGQ_NOLOCKFREE_IMPLICITPRODBLOCKINDEX + debug::DebugLock lock(mutex); +#endif + do { + blockBaseDiff -= static_cast(BLOCK_SIZE); + currentTailIndex += static_cast(BLOCK_SIZE); + + // Find out where we'll be inserting this block in the block index + BlockIndexEntry* idxEntry = nullptr; // initialization here unnecessary but compiler can't always tell + Block* newBlock; + bool indexInserted = false; + auto head = this->headIndex.load(std::memory_order_relaxed); + assert(!details::circular_less_than(currentTailIndex, head)); + bool full = !details::circular_less_than(head, currentTailIndex + BLOCK_SIZE) || (MAX_SUBQUEUE_SIZE != details::const_numeric_max::value && (MAX_SUBQUEUE_SIZE == 0 || MAX_SUBQUEUE_SIZE - BLOCK_SIZE < currentTailIndex - head)); + + if (full || !(indexInserted = insert_block_index_entry(idxEntry, currentTailIndex)) || (newBlock = this->parent->ConcurrentQueue::template requisition_block()) == nullptr) { + // Index allocation or block allocation failed; revert any other allocations + // and index insertions done so far for this operation + if (indexInserted) { + rewind_block_index_tail(); + idxEntry->value.store(nullptr, std::memory_order_relaxed); + } + currentTailIndex = (startTailIndex - 1) & ~static_cast(BLOCK_SIZE - 1); + for (auto block = firstAllocatedBlock; block != nullptr; block = block->next) { + currentTailIndex += static_cast(BLOCK_SIZE); + idxEntry = get_block_index_entry_for_index(currentTailIndex); + idxEntry->value.store(nullptr, std::memory_order_relaxed); + rewind_block_index_tail(); + } + this->parent->add_blocks_to_free_list(firstAllocatedBlock); + this->tailBlock = startBlock; + + return false; + } + +#ifdef MCDBGQ_TRACKMEM + newBlock->owner = this; +#endif + newBlock->ConcurrentQueue::Block::template reset_empty(); + newBlock->next = nullptr; + + // Insert the new block into the index + idxEntry->value.store(newBlock, std::memory_order_relaxed); + + // Store the chain of blocks so that we can undo if later allocations fail, + // and so that we can find the blocks when we do the actual enqueueing + if ((startTailIndex & static_cast(BLOCK_SIZE - 1)) != 0 || firstAllocatedBlock != nullptr) { + assert(this->tailBlock != nullptr); + this->tailBlock->next = newBlock; + } + this->tailBlock = newBlock; + endBlock = newBlock; + firstAllocatedBlock = firstAllocatedBlock == nullptr ? newBlock : firstAllocatedBlock; + } while (blockBaseDiff > 0); + } + + // Enqueue, one block at a time + index_t newTailIndex = startTailIndex + static_cast(count); + currentTailIndex = startTailIndex; + this->tailBlock = startBlock; + assert((startTailIndex & static_cast(BLOCK_SIZE - 1)) != 0 || firstAllocatedBlock != nullptr || count == 0); + if ((startTailIndex & static_cast(BLOCK_SIZE - 1)) == 0 && firstAllocatedBlock != nullptr) { + this->tailBlock = firstAllocatedBlock; + } + while (true) { + index_t stopIndex = (currentTailIndex & ~static_cast(BLOCK_SIZE - 1)) + static_cast(BLOCK_SIZE); + if (details::circular_less_than(newTailIndex, stopIndex)) { + stopIndex = newTailIndex; + } + MOODYCAMEL_CONSTEXPR_IF (MOODYCAMEL_NOEXCEPT_CTOR(T, decltype(*itemFirst), new (static_cast(nullptr)) T(details::deref_noexcept(itemFirst)))) { + while (currentTailIndex != stopIndex) { + new ((*this->tailBlock)[currentTailIndex++]) T(*itemFirst++); + } + } + else { + MOODYCAMEL_TRY { + while (currentTailIndex != stopIndex) { + new ((*this->tailBlock)[currentTailIndex]) T(details::nomove_if(nullptr)) T(details::deref_noexcept(itemFirst)))>::eval(*itemFirst)); + ++currentTailIndex; + ++itemFirst; + } + } + MOODYCAMEL_CATCH (...) { + auto constructedStopIndex = currentTailIndex; + auto lastBlockEnqueued = this->tailBlock; + + if (!details::is_trivially_destructible::value) { + auto block = startBlock; + if ((startTailIndex & static_cast(BLOCK_SIZE - 1)) == 0) { + block = firstAllocatedBlock; + } + currentTailIndex = startTailIndex; + while (true) { + stopIndex = (currentTailIndex & ~static_cast(BLOCK_SIZE - 1)) + static_cast(BLOCK_SIZE); + if (details::circular_less_than(constructedStopIndex, stopIndex)) { + stopIndex = constructedStopIndex; + } + while (currentTailIndex != stopIndex) { + (*block)[currentTailIndex++]->~T(); + } + if (block == lastBlockEnqueued) { + break; + } + block = block->next; + } + } + + currentTailIndex = (startTailIndex - 1) & ~static_cast(BLOCK_SIZE - 1); + for (auto block = firstAllocatedBlock; block != nullptr; block = block->next) { + currentTailIndex += static_cast(BLOCK_SIZE); + auto idxEntry = get_block_index_entry_for_index(currentTailIndex); + idxEntry->value.store(nullptr, std::memory_order_relaxed); + rewind_block_index_tail(); + } + this->parent->add_blocks_to_free_list(firstAllocatedBlock); + this->tailBlock = startBlock; + MOODYCAMEL_RETHROW; + } + } + + if (this->tailBlock == endBlock) { + assert(currentTailIndex == newTailIndex); + break; + } + this->tailBlock = this->tailBlock->next; + } + this->tailIndex.store(newTailIndex, std::memory_order_release); + return true; + } +#ifdef _MSC_VER +#pragma warning(pop) +#endif + + template + size_t dequeue_bulk(It& itemFirst, size_t max) + { + auto tail = this->tailIndex.load(std::memory_order_relaxed); + auto overcommit = this->dequeueOvercommit.load(std::memory_order_relaxed); + auto desiredCount = static_cast(tail - (this->dequeueOptimisticCount.load(std::memory_order_relaxed) - overcommit)); + if (details::circular_less_than(0, desiredCount)) { + desiredCount = desiredCount < max ? desiredCount : max; + std::atomic_thread_fence(std::memory_order_acquire); + + auto myDequeueCount = this->dequeueOptimisticCount.fetch_add(desiredCount, std::memory_order_relaxed); + + tail = this->tailIndex.load(std::memory_order_acquire); + auto actualCount = static_cast(tail - (myDequeueCount - overcommit)); + if (details::circular_less_than(0, actualCount)) { + actualCount = desiredCount < actualCount ? desiredCount : actualCount; + if (actualCount < desiredCount) { + this->dequeueOvercommit.fetch_add(desiredCount - actualCount, std::memory_order_release); + } + + // Get the first index. Note that since there's guaranteed to be at least actualCount elements, this + // will never exceed tail. + auto firstIndex = this->headIndex.fetch_add(actualCount, std::memory_order_acq_rel); + + // Iterate the blocks and dequeue + auto index = firstIndex; + BlockIndexHeader* localBlockIndex; + auto indexIndex = get_block_index_index_for_index(index, localBlockIndex); + do { + auto blockStartIndex = index; + index_t endIndex = (index & ~static_cast(BLOCK_SIZE - 1)) + static_cast(BLOCK_SIZE); + endIndex = details::circular_less_than(firstIndex + static_cast(actualCount), endIndex) ? firstIndex + static_cast(actualCount) : endIndex; + + auto entry = localBlockIndex->index[indexIndex]; + auto block = entry->value.load(std::memory_order_relaxed); + if (MOODYCAMEL_NOEXCEPT_ASSIGN(T, T&&, details::deref_noexcept(itemFirst) = std::move((*(*block)[index])))) { + while (index != endIndex) { + auto& el = *((*block)[index]); + *itemFirst++ = std::move(el); + el.~T(); + ++index; + } + } + else { + MOODYCAMEL_TRY { + while (index != endIndex) { + auto& el = *((*block)[index]); + *itemFirst = std::move(el); + ++itemFirst; + el.~T(); + ++index; + } + } + MOODYCAMEL_CATCH (...) { + do { + entry = localBlockIndex->index[indexIndex]; + block = entry->value.load(std::memory_order_relaxed); + while (index != endIndex) { + (*block)[index++]->~T(); + } + + if (block->ConcurrentQueue::Block::template set_many_empty(blockStartIndex, static_cast(endIndex - blockStartIndex))) { +#ifdef MCDBGQ_NOLOCKFREE_IMPLICITPRODBLOCKINDEX + debug::DebugLock lock(mutex); +#endif + entry->value.store(nullptr, std::memory_order_relaxed); + this->parent->add_block_to_free_list(block); + } + indexIndex = (indexIndex + 1) & (localBlockIndex->capacity - 1); + + blockStartIndex = index; + endIndex = (index & ~static_cast(BLOCK_SIZE - 1)) + static_cast(BLOCK_SIZE); + endIndex = details::circular_less_than(firstIndex + static_cast(actualCount), endIndex) ? firstIndex + static_cast(actualCount) : endIndex; + } while (index != firstIndex + actualCount); + + MOODYCAMEL_RETHROW; + } + } + if (block->ConcurrentQueue::Block::template set_many_empty(blockStartIndex, static_cast(endIndex - blockStartIndex))) { + { +#ifdef MCDBGQ_NOLOCKFREE_IMPLICITPRODBLOCKINDEX + debug::DebugLock lock(mutex); +#endif + // Note that the set_many_empty above did a release, meaning that anybody who acquires the block + // we're about to free can use it safely since our writes (and reads!) will have happened-before then. + entry->value.store(nullptr, std::memory_order_relaxed); + } + this->parent->add_block_to_free_list(block); // releases the above store + } + indexIndex = (indexIndex + 1) & (localBlockIndex->capacity - 1); + } while (index != firstIndex + actualCount); + + return actualCount; + } + else { + this->dequeueOvercommit.fetch_add(desiredCount, std::memory_order_release); + } + } + + return 0; + } + + private: + // The block size must be > 1, so any number with the low bit set is an invalid block base index + static const index_t INVALID_BLOCK_BASE = 1; + + struct BlockIndexEntry + { + std::atomic key; + std::atomic value; + }; + + struct BlockIndexHeader + { + size_t capacity; + std::atomic tail; + BlockIndexEntry* entries; + BlockIndexEntry** index; + BlockIndexHeader* prev; + }; + + template + inline bool insert_block_index_entry(BlockIndexEntry*& idxEntry, index_t blockStartIndex) + { + auto localBlockIndex = blockIndex.load(std::memory_order_relaxed); // We're the only writer thread, relaxed is OK + if (localBlockIndex == nullptr) { + return false; // this can happen if new_block_index failed in the constructor + } + size_t newTail = (localBlockIndex->tail.load(std::memory_order_relaxed) + 1) & (localBlockIndex->capacity - 1); + idxEntry = localBlockIndex->index[newTail]; + if (idxEntry->key.load(std::memory_order_relaxed) == INVALID_BLOCK_BASE || + idxEntry->value.load(std::memory_order_relaxed) == nullptr) { + + idxEntry->key.store(blockStartIndex, std::memory_order_relaxed); + localBlockIndex->tail.store(newTail, std::memory_order_release); + return true; + } + + // No room in the old block index, try to allocate another one! + MOODYCAMEL_CONSTEXPR_IF (allocMode == CannotAlloc) { + return false; + } + else if (!new_block_index()) { + return false; + } + localBlockIndex = blockIndex.load(std::memory_order_relaxed); + newTail = (localBlockIndex->tail.load(std::memory_order_relaxed) + 1) & (localBlockIndex->capacity - 1); + idxEntry = localBlockIndex->index[newTail]; + assert(idxEntry->key.load(std::memory_order_relaxed) == INVALID_BLOCK_BASE); + idxEntry->key.store(blockStartIndex, std::memory_order_relaxed); + localBlockIndex->tail.store(newTail, std::memory_order_release); + return true; + } + + inline void rewind_block_index_tail() + { + auto localBlockIndex = blockIndex.load(std::memory_order_relaxed); + localBlockIndex->tail.store((localBlockIndex->tail.load(std::memory_order_relaxed) - 1) & (localBlockIndex->capacity - 1), std::memory_order_relaxed); + } + + inline BlockIndexEntry* get_block_index_entry_for_index(index_t index) const + { + BlockIndexHeader* localBlockIndex; + auto idx = get_block_index_index_for_index(index, localBlockIndex); + return localBlockIndex->index[idx]; + } + + inline size_t get_block_index_index_for_index(index_t index, BlockIndexHeader*& localBlockIndex) const + { +#ifdef MCDBGQ_NOLOCKFREE_IMPLICITPRODBLOCKINDEX + debug::DebugLock lock(mutex); +#endif + index &= ~static_cast(BLOCK_SIZE - 1); + localBlockIndex = blockIndex.load(std::memory_order_acquire); + auto tail = localBlockIndex->tail.load(std::memory_order_acquire); + auto tailBase = localBlockIndex->index[tail]->key.load(std::memory_order_relaxed); + assert(tailBase != INVALID_BLOCK_BASE); + // Note: Must use division instead of shift because the index may wrap around, causing a negative + // offset, whose negativity we want to preserve + auto offset = static_cast(static_cast::type>(index - tailBase) / BLOCK_SIZE); + size_t idx = (tail + offset) & (localBlockIndex->capacity - 1); + assert(localBlockIndex->index[idx]->key.load(std::memory_order_relaxed) == index && localBlockIndex->index[idx]->value.load(std::memory_order_relaxed) != nullptr); + return idx; + } + + bool new_block_index() + { + auto prev = blockIndex.load(std::memory_order_relaxed); + size_t prevCapacity = prev == nullptr ? 0 : prev->capacity; + auto entryCount = prev == nullptr ? nextBlockIndexCapacity : prevCapacity; + auto raw = static_cast((Traits::malloc)( + sizeof(BlockIndexHeader) + + std::alignment_of::value - 1 + sizeof(BlockIndexEntry) * entryCount + + std::alignment_of::value - 1 + sizeof(BlockIndexEntry*) * nextBlockIndexCapacity)); + if (raw == nullptr) { + return false; + } + + auto header = new (raw) BlockIndexHeader; + auto entries = reinterpret_cast(details::align_for(raw + sizeof(BlockIndexHeader))); + auto index = reinterpret_cast(details::align_for(reinterpret_cast(entries) + sizeof(BlockIndexEntry) * entryCount)); + if (prev != nullptr) { + auto prevTail = prev->tail.load(std::memory_order_relaxed); + auto prevPos = prevTail; + size_t i = 0; + do { + prevPos = (prevPos + 1) & (prev->capacity - 1); + index[i++] = prev->index[prevPos]; + } while (prevPos != prevTail); + assert(i == prevCapacity); + } + for (size_t i = 0; i != entryCount; ++i) { + new (entries + i) BlockIndexEntry; + entries[i].key.store(INVALID_BLOCK_BASE, std::memory_order_relaxed); + index[prevCapacity + i] = entries + i; + } + header->prev = prev; + header->entries = entries; + header->index = index; + header->capacity = nextBlockIndexCapacity; + header->tail.store((prevCapacity - 1) & (nextBlockIndexCapacity - 1), std::memory_order_relaxed); + + blockIndex.store(header, std::memory_order_release); + + nextBlockIndexCapacity <<= 1; + + return true; + } + + private: + size_t nextBlockIndexCapacity; + std::atomic blockIndex; + +#ifdef MOODYCAMEL_CPP11_THREAD_LOCAL_SUPPORTED + public: + details::ThreadExitListener threadExitListener; + private: +#endif + +#ifdef MOODYCAMEL_QUEUE_INTERNAL_DEBUG + public: + ImplicitProducer* nextImplicitProducer; + private: +#endif + +#ifdef MCDBGQ_NOLOCKFREE_IMPLICITPRODBLOCKINDEX + mutable debug::DebugMutex mutex; +#endif +#ifdef MCDBGQ_TRACKMEM + friend struct MemStats; +#endif + }; + + + ////////////////////////////////// + // Block pool manipulation + ////////////////////////////////// + + void populate_initial_block_list(size_t blockCount) + { + initialBlockPoolSize = blockCount; + if (initialBlockPoolSize == 0) { + initialBlockPool = nullptr; + return; + } + + initialBlockPool = create_array(blockCount); + if (initialBlockPool == nullptr) { + initialBlockPoolSize = 0; + } + for (size_t i = 0; i < initialBlockPoolSize; ++i) { + initialBlockPool[i].dynamicallyAllocated = false; + } + } + + inline Block* try_get_block_from_initial_pool() + { + if (initialBlockPoolIndex.load(std::memory_order_relaxed) >= initialBlockPoolSize) { + return nullptr; + } + + auto index = initialBlockPoolIndex.fetch_add(1, std::memory_order_relaxed); + + return index < initialBlockPoolSize ? (initialBlockPool + index) : nullptr; + } + + inline void add_block_to_free_list(Block* block) + { +#ifdef MCDBGQ_TRACKMEM + block->owner = nullptr; +#endif + freeList.add(block); + } + + inline void add_blocks_to_free_list(Block* block) + { + while (block != nullptr) { + auto next = block->next; + add_block_to_free_list(block); + block = next; + } + } + + inline Block* try_get_block_from_free_list() + { + return freeList.try_get(); + } + + // Gets a free block from one of the memory pools, or allocates a new one (if applicable) + template + Block* requisition_block() + { + auto block = try_get_block_from_initial_pool(); + if (block != nullptr) { + return block; + } + + block = try_get_block_from_free_list(); + if (block != nullptr) { + return block; + } + + MOODYCAMEL_CONSTEXPR_IF (canAlloc == CanAlloc) { + return create(); + } + else { + return nullptr; + } + } + + +#ifdef MCDBGQ_TRACKMEM + public: + struct MemStats { + size_t allocatedBlocks; + size_t usedBlocks; + size_t freeBlocks; + size_t ownedBlocksExplicit; + size_t ownedBlocksImplicit; + size_t implicitProducers; + size_t explicitProducers; + size_t elementsEnqueued; + size_t blockClassBytes; + size_t queueClassBytes; + size_t implicitBlockIndexBytes; + size_t explicitBlockIndexBytes; + + friend class ConcurrentQueue; + + private: + static MemStats getFor(ConcurrentQueue* q) + { + MemStats stats = { 0 }; + + stats.elementsEnqueued = q->size_approx(); + + auto block = q->freeList.head_unsafe(); + while (block != nullptr) { + ++stats.allocatedBlocks; + ++stats.freeBlocks; + block = block->freeListNext.load(std::memory_order_relaxed); + } + + for (auto ptr = q->producerListTail.load(std::memory_order_acquire); ptr != nullptr; ptr = ptr->next_prod()) { + bool implicit = dynamic_cast(ptr) != nullptr; + stats.implicitProducers += implicit ? 1 : 0; + stats.explicitProducers += implicit ? 0 : 1; + + if (implicit) { + auto prod = static_cast(ptr); + stats.queueClassBytes += sizeof(ImplicitProducer); + auto head = prod->headIndex.load(std::memory_order_relaxed); + auto tail = prod->tailIndex.load(std::memory_order_relaxed); + auto hash = prod->blockIndex.load(std::memory_order_relaxed); + if (hash != nullptr) { + for (size_t i = 0; i != hash->capacity; ++i) { + if (hash->index[i]->key.load(std::memory_order_relaxed) != ImplicitProducer::INVALID_BLOCK_BASE && hash->index[i]->value.load(std::memory_order_relaxed) != nullptr) { + ++stats.allocatedBlocks; + ++stats.ownedBlocksImplicit; + } + } + stats.implicitBlockIndexBytes += hash->capacity * sizeof(typename ImplicitProducer::BlockIndexEntry); + for (; hash != nullptr; hash = hash->prev) { + stats.implicitBlockIndexBytes += sizeof(typename ImplicitProducer::BlockIndexHeader) + hash->capacity * sizeof(typename ImplicitProducer::BlockIndexEntry*); + } + } + for (; details::circular_less_than(head, tail); head += BLOCK_SIZE) { + //auto block = prod->get_block_index_entry_for_index(head); + ++stats.usedBlocks; + } + } + else { + auto prod = static_cast(ptr); + stats.queueClassBytes += sizeof(ExplicitProducer); + auto tailBlock = prod->tailBlock; + bool wasNonEmpty = false; + if (tailBlock != nullptr) { + auto block = tailBlock; + do { + ++stats.allocatedBlocks; + if (!block->ConcurrentQueue::Block::template is_empty() || wasNonEmpty) { + ++stats.usedBlocks; + wasNonEmpty = wasNonEmpty || block != tailBlock; + } + ++stats.ownedBlocksExplicit; + block = block->next; + } while (block != tailBlock); + } + auto index = prod->blockIndex.load(std::memory_order_relaxed); + while (index != nullptr) { + stats.explicitBlockIndexBytes += sizeof(typename ExplicitProducer::BlockIndexHeader) + index->size * sizeof(typename ExplicitProducer::BlockIndexEntry); + index = static_cast(index->prev); + } + } + } + + auto freeOnInitialPool = q->initialBlockPoolIndex.load(std::memory_order_relaxed) >= q->initialBlockPoolSize ? 0 : q->initialBlockPoolSize - q->initialBlockPoolIndex.load(std::memory_order_relaxed); + stats.allocatedBlocks += freeOnInitialPool; + stats.freeBlocks += freeOnInitialPool; + + stats.blockClassBytes = sizeof(Block) * stats.allocatedBlocks; + stats.queueClassBytes += sizeof(ConcurrentQueue); + + return stats; + } + }; + + // For debugging only. Not thread-safe. + MemStats getMemStats() + { + return MemStats::getFor(this); + } + private: + friend struct MemStats; +#endif + + + ////////////////////////////////// + // Producer list manipulation + ////////////////////////////////// + + ProducerBase* recycle_or_create_producer(bool isExplicit) + { + bool recycled; + return recycle_or_create_producer(isExplicit, recycled); + } + + ProducerBase* recycle_or_create_producer(bool isExplicit, bool& recycled) + { +#ifdef MCDBGQ_NOLOCKFREE_IMPLICITPRODHASH + debug::DebugLock lock(implicitProdMutex); +#endif + // Try to re-use one first + for (auto ptr = producerListTail.load(std::memory_order_acquire); ptr != nullptr; ptr = ptr->next_prod()) { + if (ptr->inactive.load(std::memory_order_relaxed) && ptr->isExplicit == isExplicit) { + bool expected = true; + if (ptr->inactive.compare_exchange_strong(expected, /* desired */ false, std::memory_order_acquire, std::memory_order_relaxed)) { + // We caught one! It's been marked as activated, the caller can have it + recycled = true; + return ptr; + } + } + } + + recycled = false; + return add_producer(isExplicit ? static_cast(create(this)) : create(this)); + } + + ProducerBase* add_producer(ProducerBase* producer) + { + // Handle failed memory allocation + if (producer == nullptr) { + return nullptr; + } + + producerCount.fetch_add(1, std::memory_order_relaxed); + + // Add it to the lock-free list + auto prevTail = producerListTail.load(std::memory_order_relaxed); + do { + producer->next = prevTail; + } while (!producerListTail.compare_exchange_weak(prevTail, producer, std::memory_order_release, std::memory_order_relaxed)); + +#ifdef MOODYCAMEL_QUEUE_INTERNAL_DEBUG + if (producer->isExplicit) { + auto prevTailExplicit = explicitProducers.load(std::memory_order_relaxed); + do { + static_cast(producer)->nextExplicitProducer = prevTailExplicit; + } while (!explicitProducers.compare_exchange_weak(prevTailExplicit, static_cast(producer), std::memory_order_release, std::memory_order_relaxed)); + } + else { + auto prevTailImplicit = implicitProducers.load(std::memory_order_relaxed); + do { + static_cast(producer)->nextImplicitProducer = prevTailImplicit; + } while (!implicitProducers.compare_exchange_weak(prevTailImplicit, static_cast(producer), std::memory_order_release, std::memory_order_relaxed)); + } +#endif + + return producer; + } + + void reown_producers() + { + // After another instance is moved-into/swapped-with this one, all the + // producers we stole still think their parents are the other queue. + // So fix them up! + for (auto ptr = producerListTail.load(std::memory_order_relaxed); ptr != nullptr; ptr = ptr->next_prod()) { + ptr->parent = this; + } + } + + + ////////////////////////////////// + // Implicit producer hash + ////////////////////////////////// + + struct ImplicitProducerKVP + { + std::atomic key; + ImplicitProducer* value; // No need for atomicity since it's only read by the thread that sets it in the first place + + ImplicitProducerKVP() : value(nullptr) { } + + ImplicitProducerKVP(ImplicitProducerKVP&& other) MOODYCAMEL_NOEXCEPT + { + key.store(other.key.load(std::memory_order_relaxed), std::memory_order_relaxed); + value = other.value; + } + + inline ImplicitProducerKVP& operator=(ImplicitProducerKVP&& other) MOODYCAMEL_NOEXCEPT + { + swap(other); + return *this; + } + + inline void swap(ImplicitProducerKVP& other) MOODYCAMEL_NOEXCEPT + { + if (this != &other) { + details::swap_relaxed(key, other.key); + std::swap(value, other.value); + } + } + }; + + template + friend void moodycamel::swap(typename ConcurrentQueue::ImplicitProducerKVP&, typename ConcurrentQueue::ImplicitProducerKVP&) MOODYCAMEL_NOEXCEPT; + + struct ImplicitProducerHash + { + size_t capacity; + ImplicitProducerKVP* entries; + ImplicitProducerHash* prev; + }; + + inline void populate_initial_implicit_producer_hash() + { + MOODYCAMEL_CONSTEXPR_IF (INITIAL_IMPLICIT_PRODUCER_HASH_SIZE == 0) { + return; + } + else { + implicitProducerHashCount.store(0, std::memory_order_relaxed); + auto hash = &initialImplicitProducerHash; + hash->capacity = INITIAL_IMPLICIT_PRODUCER_HASH_SIZE; + hash->entries = &initialImplicitProducerHashEntries[0]; + for (size_t i = 0; i != INITIAL_IMPLICIT_PRODUCER_HASH_SIZE; ++i) { + initialImplicitProducerHashEntries[i].key.store(details::invalid_thread_id, std::memory_order_relaxed); + } + hash->prev = nullptr; + implicitProducerHash.store(hash, std::memory_order_relaxed); + } + } + + void swap_implicit_producer_hashes(ConcurrentQueue& other) + { + MOODYCAMEL_CONSTEXPR_IF (INITIAL_IMPLICIT_PRODUCER_HASH_SIZE == 0) { + return; + } + else { + // Swap (assumes our implicit producer hash is initialized) + initialImplicitProducerHashEntries.swap(other.initialImplicitProducerHashEntries); + initialImplicitProducerHash.entries = &initialImplicitProducerHashEntries[0]; + other.initialImplicitProducerHash.entries = &other.initialImplicitProducerHashEntries[0]; + + details::swap_relaxed(implicitProducerHashCount, other.implicitProducerHashCount); + + details::swap_relaxed(implicitProducerHash, other.implicitProducerHash); + if (implicitProducerHash.load(std::memory_order_relaxed) == &other.initialImplicitProducerHash) { + implicitProducerHash.store(&initialImplicitProducerHash, std::memory_order_relaxed); + } + else { + ImplicitProducerHash* hash; + for (hash = implicitProducerHash.load(std::memory_order_relaxed); hash->prev != &other.initialImplicitProducerHash; hash = hash->prev) { + continue; + } + hash->prev = &initialImplicitProducerHash; + } + if (other.implicitProducerHash.load(std::memory_order_relaxed) == &initialImplicitProducerHash) { + other.implicitProducerHash.store(&other.initialImplicitProducerHash, std::memory_order_relaxed); + } + else { + ImplicitProducerHash* hash; + for (hash = other.implicitProducerHash.load(std::memory_order_relaxed); hash->prev != &initialImplicitProducerHash; hash = hash->prev) { + continue; + } + hash->prev = &other.initialImplicitProducerHash; + } + } + } + + // Only fails (returns nullptr) if memory allocation fails + ImplicitProducer* get_or_add_implicit_producer() + { + // Note that since the data is essentially thread-local (key is thread ID), + // there's a reduced need for fences (memory ordering is already consistent + // for any individual thread), except for the current table itself. + + // Start by looking for the thread ID in the current and all previous hash tables. + // If it's not found, it must not be in there yet, since this same thread would + // have added it previously to one of the tables that we traversed. + + // Code and algorithm adapted from http://preshing.com/20130605/the-worlds-simplest-lock-free-hash-table + +#ifdef MCDBGQ_NOLOCKFREE_IMPLICITPRODHASH + debug::DebugLock lock(implicitProdMutex); +#endif + + auto id = details::thread_id(); + auto hashedId = details::hash_thread_id(id); + + auto mainHash = implicitProducerHash.load(std::memory_order_acquire); + assert(mainHash != nullptr); // silence clang-tidy and MSVC warnings (hash cannot be null) + for (auto hash = mainHash; hash != nullptr; hash = hash->prev) { + // Look for the id in this hash + auto index = hashedId; + while (true) { // Not an infinite loop because at least one slot is free in the hash table + index &= hash->capacity - 1; + + auto probedKey = hash->entries[index].key.load(std::memory_order_relaxed); + if (probedKey == id) { + // Found it! If we had to search several hashes deep, though, we should lazily add it + // to the current main hash table to avoid the extended search next time. + // Note there's guaranteed to be room in the current hash table since every subsequent + // table implicitly reserves space for all previous tables (there's only one + // implicitProducerHashCount). + auto value = hash->entries[index].value; + if (hash != mainHash) { + index = hashedId; + while (true) { + index &= mainHash->capacity - 1; + probedKey = mainHash->entries[index].key.load(std::memory_order_relaxed); + auto empty = details::invalid_thread_id; +#ifdef MOODYCAMEL_CPP11_THREAD_LOCAL_SUPPORTED + auto reusable = details::invalid_thread_id2; + if ((probedKey == empty && mainHash->entries[index].key.compare_exchange_strong(empty, id, std::memory_order_relaxed, std::memory_order_relaxed)) || + (probedKey == reusable && mainHash->entries[index].key.compare_exchange_strong(reusable, id, std::memory_order_acquire, std::memory_order_acquire))) { +#else + if ((probedKey == empty && mainHash->entries[index].key.compare_exchange_strong(empty, id, std::memory_order_relaxed, std::memory_order_relaxed))) { +#endif + mainHash->entries[index].value = value; + break; + } + ++index; + } + } + + return value; + } + if (probedKey == details::invalid_thread_id) { + break; // Not in this hash table + } + ++index; + } + } + + // Insert! + auto newCount = 1 + implicitProducerHashCount.fetch_add(1, std::memory_order_relaxed); + while (true) { + // NOLINTNEXTLINE(clang-analyzer-core.NullDereference) + if (newCount >= (mainHash->capacity >> 1) && !implicitProducerHashResizeInProgress.test_and_set(std::memory_order_acquire)) { + // We've acquired the resize lock, try to allocate a bigger hash table. + // Note the acquire fence synchronizes with the release fence at the end of this block, and hence when + // we reload implicitProducerHash it must be the most recent version (it only gets changed within this + // locked block). + mainHash = implicitProducerHash.load(std::memory_order_acquire); + if (newCount >= (mainHash->capacity >> 1)) { + auto newCapacity = mainHash->capacity << 1; + while (newCount >= (newCapacity >> 1)) { + newCapacity <<= 1; + } + auto raw = static_cast((Traits::malloc)(sizeof(ImplicitProducerHash) + std::alignment_of::value - 1 + sizeof(ImplicitProducerKVP) * newCapacity)); + if (raw == nullptr) { + // Allocation failed + implicitProducerHashCount.fetch_sub(1, std::memory_order_relaxed); + implicitProducerHashResizeInProgress.clear(std::memory_order_relaxed); + return nullptr; + } + + auto newHash = new (raw) ImplicitProducerHash; + newHash->capacity = static_cast(newCapacity); + newHash->entries = reinterpret_cast(details::align_for(raw + sizeof(ImplicitProducerHash))); + for (size_t i = 0; i != newCapacity; ++i) { + new (newHash->entries + i) ImplicitProducerKVP; + newHash->entries[i].key.store(details::invalid_thread_id, std::memory_order_relaxed); + } + newHash->prev = mainHash; + implicitProducerHash.store(newHash, std::memory_order_release); + implicitProducerHashResizeInProgress.clear(std::memory_order_release); + mainHash = newHash; + } + else { + implicitProducerHashResizeInProgress.clear(std::memory_order_release); + } + } + + // If it's < three-quarters full, add to the old one anyway so that we don't have to wait for the next table + // to finish being allocated by another thread (and if we just finished allocating above, the condition will + // always be true) + if (newCount < (mainHash->capacity >> 1) + (mainHash->capacity >> 2)) { + bool recycled; + auto producer = static_cast(recycle_or_create_producer(false, recycled)); + if (producer == nullptr) { + implicitProducerHashCount.fetch_sub(1, std::memory_order_relaxed); + return nullptr; + } + if (recycled) { + implicitProducerHashCount.fetch_sub(1, std::memory_order_relaxed); + } + +#ifdef MOODYCAMEL_CPP11_THREAD_LOCAL_SUPPORTED + producer->threadExitListener.callback = &ConcurrentQueue::implicit_producer_thread_exited_callback; + producer->threadExitListener.userData = producer; + details::ThreadExitNotifier::subscribe(&producer->threadExitListener); +#endif + + auto index = hashedId; + while (true) { + index &= mainHash->capacity - 1; + auto probedKey = mainHash->entries[index].key.load(std::memory_order_relaxed); + + auto empty = details::invalid_thread_id; +#ifdef MOODYCAMEL_CPP11_THREAD_LOCAL_SUPPORTED + auto reusable = details::invalid_thread_id2; + if ((probedKey == empty && mainHash->entries[index].key.compare_exchange_strong(empty, id, std::memory_order_relaxed, std::memory_order_relaxed)) || + (probedKey == reusable && mainHash->entries[index].key.compare_exchange_strong(reusable, id, std::memory_order_acquire, std::memory_order_acquire))) { +#else + if ((probedKey == empty && mainHash->entries[index].key.compare_exchange_strong(empty, id, std::memory_order_relaxed, std::memory_order_relaxed))) { +#endif + mainHash->entries[index].value = producer; + break; + } + ++index; + } + return producer; + } + + // Hmm, the old hash is quite full and somebody else is busy allocating a new one. + // We need to wait for the allocating thread to finish (if it succeeds, we add, if not, + // we try to allocate ourselves). + mainHash = implicitProducerHash.load(std::memory_order_acquire); + } + } + +#ifdef MOODYCAMEL_CPP11_THREAD_LOCAL_SUPPORTED + void implicit_producer_thread_exited(ImplicitProducer* producer) + { + // Remove from thread exit listeners + details::ThreadExitNotifier::unsubscribe(&producer->threadExitListener); + + // Remove from hash +#ifdef MCDBGQ_NOLOCKFREE_IMPLICITPRODHASH + debug::DebugLock lock(implicitProdMutex); +#endif + auto hash = implicitProducerHash.load(std::memory_order_acquire); + assert(hash != nullptr); // The thread exit listener is only registered if we were added to a hash in the first place + auto id = details::thread_id(); + auto hashedId = details::hash_thread_id(id); + details::thread_id_t probedKey; + + // We need to traverse all the hashes just in case other threads aren't on the current one yet and are + // trying to add an entry thinking there's a free slot (because they reused a producer) + for (; hash != nullptr; hash = hash->prev) { + auto index = hashedId; + do { + index &= hash->capacity - 1; + probedKey = hash->entries[index].key.load(std::memory_order_relaxed); + if (probedKey == id) { + hash->entries[index].key.store(details::invalid_thread_id2, std::memory_order_release); + break; + } + ++index; + } while (probedKey != details::invalid_thread_id); // Can happen if the hash has changed but we weren't put back in it yet, or if we weren't added to this hash in the first place + } + + // Mark the queue as being recyclable + producer->inactive.store(true, std::memory_order_release); + } + + static void implicit_producer_thread_exited_callback(void* userData) + { + auto producer = static_cast(userData); + auto queue = producer->parent; + queue->implicit_producer_thread_exited(producer); + } +#endif + + ////////////////////////////////// + // Utility functions + ////////////////////////////////// + + template + static inline void* aligned_malloc(size_t size) + { + MOODYCAMEL_CONSTEXPR_IF (std::alignment_of::value <= std::alignment_of::value) + return (Traits::malloc)(size); + else { + size_t alignment = std::alignment_of::value; + void* raw = (Traits::malloc)(size + alignment - 1 + sizeof(void*)); + if (!raw) + return nullptr; + char* ptr = details::align_for(reinterpret_cast(raw) + sizeof(void*)); + *(reinterpret_cast(ptr) - 1) = raw; + return ptr; + } + } + + template + static inline void aligned_free(void* ptr) + { + MOODYCAMEL_CONSTEXPR_IF (std::alignment_of::value <= std::alignment_of::value) + return (Traits::free)(ptr); + else + (Traits::free)(ptr ? *(reinterpret_cast(ptr) - 1) : nullptr); + } + + template + static inline U* create_array(size_t count) + { + assert(count > 0); + U* p = static_cast(aligned_malloc(sizeof(U) * count)); + if (p == nullptr) + return nullptr; + + for (size_t i = 0; i != count; ++i) + new (p + i) U(); + return p; + } + + template + static inline void destroy_array(U* p, size_t count) + { + if (p != nullptr) { + assert(count > 0); + for (size_t i = count; i != 0; ) + (p + --i)->~U(); + } + aligned_free(p); + } + + template + static inline U* create() + { + void* p = aligned_malloc(sizeof(U)); + return p != nullptr ? new (p) U : nullptr; + } + + template + static inline U* create(A1&& a1) + { + void* p = aligned_malloc(sizeof(U)); + return p != nullptr ? new (p) U(std::forward(a1)) : nullptr; + } + + template + static inline void destroy(U* p) + { + if (p != nullptr) + p->~U(); + aligned_free(p); + } + +private: + std::atomic producerListTail; + std::atomic producerCount; + + std::atomic initialBlockPoolIndex; + Block* initialBlockPool; + size_t initialBlockPoolSize; + +#ifndef MCDBGQ_USEDEBUGFREELIST + FreeList freeList; +#else + debug::DebugFreeList freeList; +#endif + + std::atomic implicitProducerHash; + std::atomic implicitProducerHashCount; // Number of slots logically used + ImplicitProducerHash initialImplicitProducerHash; + std::array initialImplicitProducerHashEntries; + std::atomic_flag implicitProducerHashResizeInProgress; + + std::atomic nextExplicitConsumerId; + std::atomic globalExplicitConsumerOffset; + +#ifdef MCDBGQ_NOLOCKFREE_IMPLICITPRODHASH + debug::DebugMutex implicitProdMutex; +#endif + +#ifdef MOODYCAMEL_QUEUE_INTERNAL_DEBUG + std::atomic explicitProducers; + std::atomic implicitProducers; +#endif +}; + + +template +ProducerToken::ProducerToken(ConcurrentQueue& queue) + : producer(queue.recycle_or_create_producer(true)) +{ + if (producer != nullptr) { + producer->token = this; + } +} + +template +ProducerToken::ProducerToken(BlockingConcurrentQueue& queue) + : producer(reinterpret_cast*>(&queue)->recycle_or_create_producer(true)) +{ + if (producer != nullptr) { + producer->token = this; + } +} + +template +ConsumerToken::ConsumerToken(ConcurrentQueue& queue) + : itemsConsumedFromCurrent(0), currentProducer(nullptr), desiredProducer(nullptr) +{ + initialOffset = queue.nextExplicitConsumerId.fetch_add(1, std::memory_order_release); + lastKnownGlobalOffset = static_cast(-1); +} + +template +ConsumerToken::ConsumerToken(BlockingConcurrentQueue& queue) + : itemsConsumedFromCurrent(0), currentProducer(nullptr), desiredProducer(nullptr) +{ + initialOffset = reinterpret_cast*>(&queue)->nextExplicitConsumerId.fetch_add(1, std::memory_order_release); + lastKnownGlobalOffset = static_cast(-1); +} + +template +inline void swap(ConcurrentQueue& a, ConcurrentQueue& b) MOODYCAMEL_NOEXCEPT +{ + a.swap(b); +} + +inline void swap(ProducerToken& a, ProducerToken& b) MOODYCAMEL_NOEXCEPT +{ + a.swap(b); +} + +inline void swap(ConsumerToken& a, ConsumerToken& b) MOODYCAMEL_NOEXCEPT +{ + a.swap(b); +} + +template +inline void swap(typename ConcurrentQueue::ImplicitProducerKVP& a, typename ConcurrentQueue::ImplicitProducerKVP& b) MOODYCAMEL_NOEXCEPT +{ + a.swap(b); +} + +} + +#if defined(_MSC_VER) && (!defined(_HAS_CXX17) || !_HAS_CXX17) +#pragma warning(pop) +#endif + +#if defined(__GNUC__) && !defined(__INTEL_COMPILER) +#pragma GCC diagnostic pop +#endif diff --git a/indra/llcommon/fstelemetry.cpp b/indra/llcommon/fstelemetry.cpp index c2bc80b66a..7be6e4b6bb 100644 --- a/indra/llcommon/fstelemetry.cpp +++ b/indra/llcommon/fstelemetry.cpp @@ -28,4 +28,5 @@ namespace FSTelemetry { bool active{false}; + } \ No newline at end of file diff --git a/indra/llcommon/fstelemetry.h b/indra/llcommon/fstelemetry.h index 9a0cdd5e18..37f9cc9a51 100644 --- a/indra/llcommon/fstelemetry.h +++ b/indra/llcommon/fstelemetry.h @@ -43,9 +43,15 @@ #define FSZoneN( name ) ZoneNamedN( ___tracy_scoped_zone, name, FSTelemetry::active) #define FSZoneC( color ) ZoneNamedC( ___tracy_scoped_zone, color, FSTelemetry::active) #define FSZoneNC( name, color ) ZoneNamedNC( ___tracy_scoped_zone, name, color, FSTelemetry::active) +#define FSZoneText( text, size ) ZoneText( text, size ) +#define FSZoneValue( num_uint64 ) ZoneValue( num_uint64 ) #define FSPlot( name, value ) TracyPlot( name, value) +#define FSPlotSq( name, lastval, newval ) TracyPlot( name, lastval);TracyPlot( name, newval); #define FSFrameMark FrameMark +#define FSFrameMarkStart( name ) FrameMarkStart( name ) +#define FSFrameMarkEnd( name ) FrameMarkEnd( name ) #define FSThreadName( name ) tracy::SetThreadName( name ) +#define FSMessageL ( message ) tracy::Profiler::Message( message, 0 ) #define FSTelemetryIsConnected TracyIsConnected #else // (no telemetry) @@ -57,15 +63,26 @@ #define FSZoneN( name ) #define FSZoneC( color ) #define FSZoneNC( name, color ) +#define FSZoneText( text, size ) +#define FSZoneValue( num_uint64 ) #define FSPlot( name, value ) +#define FSPlotSq( name, lastval, newval ) #define FSFrameMark +#define FSFrameMarkStart( name ) +#define FSFrameMarkEnd( name ) #define FSThreadName( name ) +#define FSMessageL( message ) #define FSTelemetryIsConnected #endif // TRACY_ENABLE +#include +#include +#include + namespace FSTelemetry { extern bool active; -} + +}// namespace FSTelemetry #endif \ No newline at end of file diff --git a/indra/llcommon/lightweightsemaphore.h b/indra/llcommon/lightweightsemaphore.h new file mode 100644 index 0000000000..b0f24e1cd8 --- /dev/null +++ b/indra/llcommon/lightweightsemaphore.h @@ -0,0 +1,411 @@ +// Provides an efficient implementation of a semaphore (LightweightSemaphore). +// This is an extension of Jeff Preshing's sempahore implementation (licensed +// under the terms of its separate zlib license) that has been adapted and +// extended by Cameron Desrochers. + +#pragma once + +#include // For std::size_t +#include +#include // For std::make_signed + +#if defined(_WIN32) +// Avoid including windows.h in a header; we only need a handful of +// items, so we'll redeclare them here (this is relatively safe since +// the API generally has to remain stable between Windows versions). +// I know this is an ugly hack but it still beats polluting the global +// namespace with thousands of generic names or adding a .cpp for nothing. +extern "C" { + struct _SECURITY_ATTRIBUTES; + __declspec(dllimport) void* __stdcall CreateSemaphoreW(_SECURITY_ATTRIBUTES* lpSemaphoreAttributes, long lInitialCount, long lMaximumCount, const wchar_t* lpName); + __declspec(dllimport) int __stdcall CloseHandle(void* hObject); + __declspec(dllimport) unsigned long __stdcall WaitForSingleObject(void* hHandle, unsigned long dwMilliseconds); + __declspec(dllimport) int __stdcall ReleaseSemaphore(void* hSemaphore, long lReleaseCount, long* lpPreviousCount); +} +#elif defined(__MACH__) +#include +#elif defined(__unix__) +#include +#endif + +namespace moodycamel +{ +namespace details +{ + +// Code in the mpmc_sema namespace below is an adaptation of Jeff Preshing's +// portable + lightweight semaphore implementations, originally from +// https://github.com/preshing/cpp11-on-multicore/blob/master/common/sema.h +// LICENSE: +// Copyright (c) 2015 Jeff Preshing +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgement in the product documentation would be +// appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source distribution. +#if defined(_WIN32) +class Semaphore +{ +private: + void* m_hSema; + + Semaphore(const Semaphore& other) MOODYCAMEL_DELETE_FUNCTION; + Semaphore& operator=(const Semaphore& other) MOODYCAMEL_DELETE_FUNCTION; + +public: + Semaphore(int initialCount = 0) + { + assert(initialCount >= 0); + const long maxLong = 0x7fffffff; + m_hSema = CreateSemaphoreW(nullptr, initialCount, maxLong, nullptr); + assert(m_hSema); + } + + ~Semaphore() + { + CloseHandle(m_hSema); + } + + bool wait() + { + const unsigned long infinite = 0xffffffff; + return WaitForSingleObject(m_hSema, infinite) == 0; + } + + bool try_wait() + { + return WaitForSingleObject(m_hSema, 0) == 0; + } + + bool timed_wait(std::uint64_t usecs) + { + return WaitForSingleObject(m_hSema, (unsigned long)(usecs / 1000)) == 0; + } + + void signal(int count = 1) + { + while (!ReleaseSemaphore(m_hSema, count, nullptr)); + } +}; +#elif defined(__MACH__) +//--------------------------------------------------------- +// Semaphore (Apple iOS and OSX) +// Can't use POSIX semaphores due to http://lists.apple.com/archives/darwin-kernel/2009/Apr/msg00010.html +//--------------------------------------------------------- +class Semaphore +{ +private: + semaphore_t m_sema; + + Semaphore(const Semaphore& other) MOODYCAMEL_DELETE_FUNCTION; + Semaphore& operator=(const Semaphore& other) MOODYCAMEL_DELETE_FUNCTION; + +public: + Semaphore(int initialCount = 0) + { + assert(initialCount >= 0); + kern_return_t rc = semaphore_create(mach_task_self(), &m_sema, SYNC_POLICY_FIFO, initialCount); + assert(rc == KERN_SUCCESS); + (void)rc; + } + + ~Semaphore() + { + semaphore_destroy(mach_task_self(), m_sema); + } + + bool wait() + { + return semaphore_wait(m_sema) == KERN_SUCCESS; + } + + bool try_wait() + { + return timed_wait(0); + } + + bool timed_wait(std::uint64_t timeout_usecs) + { + mach_timespec_t ts; + ts.tv_sec = static_cast(timeout_usecs / 1000000); + ts.tv_nsec = static_cast((timeout_usecs % 1000000) * 1000); + + // added in OSX 10.10: https://developer.apple.com/library/prerelease/mac/documentation/General/Reference/APIDiffsMacOSX10_10SeedDiff/modules/Darwin.html + kern_return_t rc = semaphore_timedwait(m_sema, ts); + return rc == KERN_SUCCESS; + } + + void signal() + { + while (semaphore_signal(m_sema) != KERN_SUCCESS); + } + + void signal(int count) + { + while (count-- > 0) + { + while (semaphore_signal(m_sema) != KERN_SUCCESS); + } + } +}; +#elif defined(__unix__) +//--------------------------------------------------------- +// Semaphore (POSIX, Linux) +//--------------------------------------------------------- +class Semaphore +{ +private: + sem_t m_sema; + + Semaphore(const Semaphore& other) MOODYCAMEL_DELETE_FUNCTION; + Semaphore& operator=(const Semaphore& other) MOODYCAMEL_DELETE_FUNCTION; + +public: + Semaphore(int initialCount = 0) + { + assert(initialCount >= 0); + int rc = sem_init(&m_sema, 0, static_cast(initialCount)); + assert(rc == 0); + (void)rc; + } + + ~Semaphore() + { + sem_destroy(&m_sema); + } + + bool wait() + { + // http://stackoverflow.com/questions/2013181/gdb-causes-sem-wait-to-fail-with-eintr-error + int rc; + do { + rc = sem_wait(&m_sema); + } while (rc == -1 && errno == EINTR); + return rc == 0; + } + + bool try_wait() + { + int rc; + do { + rc = sem_trywait(&m_sema); + } while (rc == -1 && errno == EINTR); + return rc == 0; + } + + bool timed_wait(std::uint64_t usecs) + { + struct timespec ts; + const int usecs_in_1_sec = 1000000; + const int nsecs_in_1_sec = 1000000000; + clock_gettime(CLOCK_REALTIME, &ts); + ts.tv_sec += (time_t)(usecs / usecs_in_1_sec); + ts.tv_nsec += (long)(usecs % usecs_in_1_sec) * 1000; + // sem_timedwait bombs if you have more than 1e9 in tv_nsec + // so we have to clean things up before passing it in + if (ts.tv_nsec >= nsecs_in_1_sec) { + ts.tv_nsec -= nsecs_in_1_sec; + ++ts.tv_sec; + } + + int rc; + do { + rc = sem_timedwait(&m_sema, &ts); + } while (rc == -1 && errno == EINTR); + return rc == 0; + } + + void signal() + { + while (sem_post(&m_sema) == -1); + } + + void signal(int count) + { + while (count-- > 0) + { + while (sem_post(&m_sema) == -1); + } + } +}; +#else +#error Unsupported platform! (No semaphore wrapper available) +#endif + +} // end namespace details + + +//--------------------------------------------------------- +// LightweightSemaphore +//--------------------------------------------------------- +class LightweightSemaphore +{ +public: + typedef std::make_signed::type ssize_t; + +private: + std::atomic m_count; + details::Semaphore m_sema; + int m_maxSpins; + + bool waitWithPartialSpinning(std::int64_t timeout_usecs = -1) + { + ssize_t oldCount; + int spin = m_maxSpins; + while (--spin >= 0) + { + oldCount = m_count.load(std::memory_order_relaxed); + if ((oldCount > 0) && m_count.compare_exchange_strong(oldCount, oldCount - 1, std::memory_order_acquire, std::memory_order_relaxed)) + return true; + std::atomic_signal_fence(std::memory_order_acquire); // Prevent the compiler from collapsing the loop. + } + oldCount = m_count.fetch_sub(1, std::memory_order_acquire); + if (oldCount > 0) + return true; + if (timeout_usecs < 0) + { + if (m_sema.wait()) + return true; + } + if (timeout_usecs > 0 && m_sema.timed_wait((std::uint64_t)timeout_usecs)) + return true; + // At this point, we've timed out waiting for the semaphore, but the + // count is still decremented indicating we may still be waiting on + // it. So we have to re-adjust the count, but only if the semaphore + // wasn't signaled enough times for us too since then. If it was, we + // need to release the semaphore too. + while (true) + { + oldCount = m_count.load(std::memory_order_acquire); + if (oldCount >= 0 && m_sema.try_wait()) + return true; + if (oldCount < 0 && m_count.compare_exchange_strong(oldCount, oldCount + 1, std::memory_order_relaxed, std::memory_order_relaxed)) + return false; + } + } + + ssize_t waitManyWithPartialSpinning(ssize_t max, std::int64_t timeout_usecs = -1) + { + assert(max > 0); + ssize_t oldCount; + int spin = m_maxSpins; + while (--spin >= 0) + { + oldCount = m_count.load(std::memory_order_relaxed); + if (oldCount > 0) + { + ssize_t newCount = oldCount > max ? oldCount - max : 0; + if (m_count.compare_exchange_strong(oldCount, newCount, std::memory_order_acquire, std::memory_order_relaxed)) + return oldCount - newCount; + } + std::atomic_signal_fence(std::memory_order_acquire); + } + oldCount = m_count.fetch_sub(1, std::memory_order_acquire); + if (oldCount <= 0) + { + if ((timeout_usecs == 0) || (timeout_usecs < 0 && !m_sema.wait()) || (timeout_usecs > 0 && !m_sema.timed_wait((std::uint64_t)timeout_usecs))) + { + while (true) + { + oldCount = m_count.load(std::memory_order_acquire); + if (oldCount >= 0 && m_sema.try_wait()) + break; + if (oldCount < 0 && m_count.compare_exchange_strong(oldCount, oldCount + 1, std::memory_order_relaxed, std::memory_order_relaxed)) + return 0; + } + } + } + if (max > 1) + return 1 + tryWaitMany(max - 1); + return 1; + } + +public: + LightweightSemaphore(ssize_t initialCount = 0, int maxSpins = 10000) : m_count(initialCount), m_maxSpins(maxSpins) + { + assert(initialCount >= 0); + assert(maxSpins >= 0); + } + + bool tryWait() + { + ssize_t oldCount = m_count.load(std::memory_order_relaxed); + while (oldCount > 0) + { + if (m_count.compare_exchange_weak(oldCount, oldCount - 1, std::memory_order_acquire, std::memory_order_relaxed)) + return true; + } + return false; + } + + bool wait() + { + return tryWait() || waitWithPartialSpinning(); + } + + bool wait(std::int64_t timeout_usecs) + { + return tryWait() || waitWithPartialSpinning(timeout_usecs); + } + + // Acquires between 0 and (greedily) max, inclusive + ssize_t tryWaitMany(ssize_t max) + { + assert(max >= 0); + ssize_t oldCount = m_count.load(std::memory_order_relaxed); + while (oldCount > 0) + { + ssize_t newCount = oldCount > max ? oldCount - max : 0; + if (m_count.compare_exchange_weak(oldCount, newCount, std::memory_order_acquire, std::memory_order_relaxed)) + return oldCount - newCount; + } + return 0; + } + + // Acquires at least one, and (greedily) at most max + ssize_t waitMany(ssize_t max, std::int64_t timeout_usecs) + { + assert(max >= 0); + ssize_t result = tryWaitMany(max); + if (result == 0 && max > 0) + result = waitManyWithPartialSpinning(max, timeout_usecs); + return result; + } + + ssize_t waitMany(ssize_t max) + { + ssize_t result = waitMany(max, -1); + assert(result > 0); + return result; + } + + void signal(ssize_t count = 1) + { + assert(count >= 0); + ssize_t oldCount = m_count.fetch_add(count, std::memory_order_release); + ssize_t toRelease = -oldCount < count ? -oldCount : count; + if (toRelease > 0) + { + m_sema.signal((int)toRelease); + } + } + + std::size_t availableApprox() const + { + ssize_t count = m_count.load(std::memory_order_relaxed); + return count > 0 ? static_cast(count) : 0; + } +}; + +} // end namespace moodycamel diff --git a/indra/llcommon/llapp.cpp b/indra/llcommon/llapp.cpp index 1999b4916f..c00df59756 100644 --- a/indra/llcommon/llapp.cpp +++ b/indra/llcommon/llapp.cpp @@ -47,8 +47,6 @@ #include "llstring.h" #include "lleventtimer.h" -#include "google_breakpad/exception_handler.h" - #include "stringize.h" #include "llcleanup.h" #include "llevents.h" @@ -64,12 +62,6 @@ LONG WINAPI default_windows_exception_handler(struct _EXCEPTION_POINTERS *exception_infop); BOOL ConsoleCtrlHandler(DWORD fdwCtrlType); -bool windows_post_minidump_callback(const wchar_t* dump_path, - const wchar_t* minidump_id, - void* context, - EXCEPTION_POINTERS* exinfo, - MDRawAssertionInfo* assertion, - bool succeeded); #else # include # include // for fork() @@ -77,10 +69,6 @@ void setup_signals(); void default_unix_signal_handler(int signum, siginfo_t *info, void *); #if LL_LINUX -#include "google_breakpad/minidump_descriptor.h" -static bool unix_minidump_callback(const google_breakpad::MinidumpDescriptor& minidump_desc, - void* context, - bool succeeded); #else // Called by breakpad exception handler after the minidump has been generated. bool unix_post_minidump_callback(const char *dump_dir, @@ -115,7 +103,8 @@ BOOL LLApp::sDisableCrashlogger = FALSE; BOOL LLApp::sLogInSignal = FALSE; // static -LLApp::EAppStatus LLApp::sStatus = LLApp::APP_STATUS_STOPPED; // Keeps track of application status +// Keeps track of application status +LLScalarCond LLApp::sStatus{LLApp::APP_STATUS_STOPPED}; LLAppErrorHandler LLApp::sErrorHandler = NULL; BOOL LLApp::sErrorThreadRunning = FALSE; @@ -148,8 +137,6 @@ void LLApp::commonCtor() // Set the application to this instance. sApplication = this; - - mExceptionHandler = 0; // initialize the buffer to write the minidump filename to // (this is used to avoid allocating memory in the crash handler) @@ -179,8 +166,6 @@ LLApp::~LLApp() delete mThreadErrorp; mThreadErrorp = NULL; } - - if(mExceptionHandler != 0) delete mExceptionHandler; SUBSYSTEM_CLEANUP_DBG(LLCommon); } @@ -396,140 +381,18 @@ void LLApp::setupErrorHandling(bool second_instance) #if LL_WINDOWS -#if LL_SEND_CRASH_REPORTS && ! defined(LL_BUGSPLAT) - EnableCrashingOnCrashes(); - - // This sets a callback to handle w32 signals to the console window. - // The viewer shouldn't be affected, sicne its a windowed app. - SetConsoleCtrlHandler( (PHANDLER_ROUTINE) ConsoleCtrlHandler, TRUE); - - // Install the Google Breakpad crash handler for Windows - if(mExceptionHandler == 0) - { - if ( second_instance ) //BUG-5707 Firing teleport from a web browser causes second - { - mExceptionHandler = new google_breakpad::ExceptionHandler( - L"C:\\Temp\\", - 0, //No filter - windows_post_minidump_callback, - 0, - google_breakpad::ExceptionHandler::HANDLER_ALL); //No custom client info. - } - else - { - LL_WARNS() << "adding breakpad exception handler" << LL_ENDL; - - std::wstring wpipe_name; - wpipe_name = mCrashReportPipeStr + wstringize(getPid()); - - const std::wstring wdump_path(utf8str_to_utf16str(mDumpPath)); - - int retries = 30; - for (; retries > 0; --retries) - { - if (mExceptionHandler != 0) delete mExceptionHandler; - U32 maskMiniDumpType = MiniDumpNormal | MiniDumpFilterModulePaths; - mExceptionHandler = new google_breakpad::ExceptionHandler( - wdump_path, - NULL, //No filter - windows_post_minidump_callback, - 0, - google_breakpad::ExceptionHandler::HANDLER_ALL, - // MiniDumpNormal, //Generate a 'normal' minidump. - (MINIDUMP_TYPE)maskMiniDumpType, // Pass custom minidump type from prefs to breakpad. - wpipe_name.c_str(), - NULL); //No custom client info. - if (mExceptionHandler->IsOutOfProcess()) - { - LL_INFOS("CRASHREPORT") << "Successfully attached to Out of Process exception handler." << LL_ENDL; - break; - } - else - { - LL_WARNS("CRASHREPORT") << "Unable to attach to Out of Process exception handler. " << retries << " retries remaining." << LL_ENDL; - ::Sleep(100); //Wait a tick and try again. - } - } - - if (retries == 0) LL_WARNS("CRASHREPORT") << "Unable to attach to Out of Process exception handler." << LL_ENDL; - } - - if (mExceptionHandler) - { - mExceptionHandler->set_handle_debug_exceptions(true); - } - } -#endif // LL_SEND_CRASH_REPORTS && ! defined(LL_BUGSPLAT) #else // ! LL_WINDOWS -#if defined(LL_BUGSPLAT) - // Don't install our own signal handlers -- BugSplat needs to hook them, - // or it's completely ineffectual. - bool installHandler = false; - -#else // ! LL_BUGSPLAT - // - // Start up signal handling. - // - // There are two different classes of signals. Synchronous signals are delivered to a specific - // thread, asynchronous signals can be delivered to any thread (in theory) - // - setup_signals(); - - // Add google breakpad exception handler configured for Darwin/Linux. - bool installHandler = true; +#if ! defined(LL_BUGSPLAT) + // + // Start up signal handling. + // + // There are two different classes of signals. Synchronous signals are delivered to a specific + // thread, asynchronous signals can be delivered to any thread (in theory) + // + setup_signals(); #endif // ! LL_BUGSPLAT -#if LL_DARWIN - // For the special case of Darwin, we do not want to install the handler if - // the process is being debugged as the app will exit with value ABRT (6) if - // we do. Unfortunately, the code below which performs that test relies on - // the structure kinfo_proc which has been tagged by apple as an unstable - // API. We disable this test for shipping versions to avoid conflicts with - // future releases of Darwin. This test is really only needed for developers - // starting the app from a debugger anyway. - #ifndef LL_RELEASE_FOR_DOWNLOAD - int mib[4]; - mib[0] = CTL_KERN; - mib[1] = KERN_PROC; - mib[2] = KERN_PROC_PID; - mib[3] = getpid(); - - struct kinfo_proc info; - memset(&info, 0, sizeof(info)); - - size_t size = sizeof(info); - int result = sysctl(mib, sizeof(mib) / sizeof(*mib), &info, &size, NULL, 0); - if((result == 0) || (errno == ENOMEM)) - { - // P_TRACED flag is set, so this process is being debugged; do not install - // the handler - if(info.kp_proc.p_flag & P_TRACED) installHandler = false; - } - else - { - // Failed to discover if the process is being debugged; default to - // installing the handler. - installHandler = true; - } - #endif // ! LL_RELEASE_FOR_DOWNLOAD - - if(installHandler && (mExceptionHandler == 0)) - { - mExceptionHandler = new google_breakpad::ExceptionHandler(mDumpPath, 0, &unix_post_minidump_callback, 0, true, 0); - } -#elif LL_LINUX - if(installHandler && (mExceptionHandler == 0)) - { - if (mDumpPath.empty()) - { - mDumpPath = "/tmp"; - } - google_breakpad::MinidumpDescriptor desc(mDumpPath); - mExceptionHandler = new google_breakpad::ExceptionHandler(desc, NULL, unix_minidump_callback, NULL, true, -1); - } -#endif // LL_LINUX - #endif // ! LL_WINDOWS #ifdef LL_BUGSPLAT @@ -587,7 +450,8 @@ static std::map statusDesc // static void LLApp::setStatus(EAppStatus status) { - sStatus = status; + // notify everyone waiting on sStatus any time its value changes + sStatus.set_all(status); // This can also happen very late in the application lifecycle -- don't // resurrect a deleted LLSingleton @@ -617,29 +481,10 @@ void LLApp::setError() setStatus(APP_STATUS_ERROR); } -void LLApp::setMiniDumpDir(const std::string &path) +// static +bool LLApp::sleep(F32Milliseconds duration) { - if (path.empty()) - { - mDumpPath = "/tmp"; - } - else - { - mDumpPath = path; - } - - if(mExceptionHandler == 0) return; -#ifdef LL_WINDOWS - std::wstring buffer(utf8str_to_utf16str(mDumpPath)); - if (buffer.size() > MAX_MINDUMP_PATH_LENGTH) buffer.resize(MAX_MINDUMP_PATH_LENGTH); - mExceptionHandler->set_dump_path(buffer); -#elif LL_LINUX - //google_breakpad::MinidumpDescriptor desc("/tmp"); //path works in debug fails in production inside breakpad lib so linux gets a little less stack reporting until it is patched. - google_breakpad::MinidumpDescriptor desc(mDumpPath); //path works in debug fails in production inside breakpad lib so linux gets a little less stack reporting until it is patched. - mExceptionHandler->set_minidump_descriptor(desc); -#else - mExceptionHandler->set_dump_path(mDumpPath); -#endif + return ! sStatus.wait_for_unequal(duration, APP_STATUS_RUNNING); } void LLApp::setDebugFileNames(const std::string &path) @@ -650,8 +495,6 @@ void LLApp::setDebugFileNames(const std::string &path) void LLApp::writeMiniDump() { - if(mExceptionHandler == 0) return; - mExceptionHandler->WriteMinidump(); } // static @@ -676,28 +519,28 @@ void LLApp::setStopped() // static bool LLApp::isStopped() { - return (APP_STATUS_STOPPED == sStatus); + return (APP_STATUS_STOPPED == sStatus.get()); } // static bool LLApp::isRunning() { - return (APP_STATUS_RUNNING == sStatus); + return (APP_STATUS_RUNNING == sStatus.get()); } // static bool LLApp::isError() { - return (APP_STATUS_ERROR == sStatus); + return (APP_STATUS_ERROR == sStatus.get()); } // static bool LLApp::isQuitting() { - return (APP_STATUS_QUITTING == sStatus); + return (APP_STATUS_QUITTING == sStatus.get()); } // static @@ -708,13 +551,6 @@ bool LLApp::isExiting() void LLApp::disableCrashlogger() { - // Disable Breakpad exception handler. - if (mExceptionHandler != 0) - { - delete mExceptionHandler; - mExceptionHandler = 0; - } - sDisableCrashlogger = TRUE; } @@ -1022,48 +858,6 @@ void default_unix_signal_handler(int signum, siginfo_t *info, void *) } } -#if LL_LINUX -bool unix_minidump_callback(const google_breakpad::MinidumpDescriptor& minidump_desc, void* context, bool succeeded) -{ - // Copy minidump file path into fixed buffer in the app instance to avoid - // heap allocations in a crash handler. - - // path format: /.dmp - - //HACK: *path points to the buffer in getMiniDumpFilename which has already allocated space - //to avoid doing allocation during crash. - char * path = LLApp::instance()->getMiniDumpFilename(); - int dir_path_len = strlen(path); - - // The path must not be truncated. - S32 remaining = LLApp::MAX_MINDUMP_PATH_LENGTH - dir_path_len; - - llassert( (remaining - strlen(minidump_desc.path())) > 5); - - path += dir_path_len; - - if (dir_path_len > 0 && path[-1] != '/') - { - *path++ = '/'; - --remaining; - } - - strncpy(path, minidump_desc.path(), remaining); - - LL_INFOS("CRASHREPORT") << "generated minidump: " << LLApp::instance()->getMiniDumpFilename() << LL_ENDL; - LLApp::runErrorHandler(); - -#ifndef LL_RELEASE_FOR_DOWNLOAD - clear_signals(); - return false; -#else - return true; -#endif - -} -#endif - - bool unix_post_minidump_callback(const char *dump_dir, const char *minidump_id, void *context, bool succeeded) @@ -1108,129 +902,3 @@ bool unix_post_minidump_callback(const char *dump_dir, } #endif // !WINDOWS -#ifdef LL_WINDOWS - -// Helper function to convert a wchar_t string into an UTF8 buffer -namespace nd -{ - namespace strings - { - inline bool convertString( wchar_t const *aIn, char *&aOut, S32 &aLen ) - { - char tmpBuffer[8]; - S32 i(0), j(0); - - while( *aIn ) - { - i = wchar_to_utf8chars( *aIn++, tmpBuffer ); - - if( i < aLen ) - { - j = 0; - while( j < i ) - { - *aOut++ = tmpBuffer[ j++ ]; - --aLen; - } - } - else - return true; - } - - return false; - } - } -} - -// - -bool windows_post_minidump_callback(const wchar_t* dump_path, - const wchar_t* minidump_id, - void* context, - EXCEPTION_POINTERS* exinfo, - MDRawAssertionInfo* assertion, - bool succeeded) -{ - // Convert all path to UTF8 and not MBCS. Having some path in MBCS and some in UTF8 is a source of great joy - // and bugs. Stick with one standard, that is UTF8. - - // char * path = LLApp::instance()->getMiniDumpFilename(); - // S32 remaining = LLApp::MAX_MINDUMP_PATH_LENGTH; - // size_t bytesUsed; - - // LL_INFOS("MINIDUMPCALLBACK") << "Dump file was generated." << LL_ENDL; - // bytesUsed = wcstombs(path, dump_path, static_cast(remaining)); - // remaining -= bytesUsed; - // path += bytesUsed; - // if(remaining > 0 && bytesUsed > 0 && path[-1] != '\\') - // { - // *path++ = '\\'; - // --remaining; - // } - // if(remaining > 0) - // { - // bytesUsed = wcstombs(path, minidump_id, static_cast(remaining)); - // remaining -= bytesUsed; - // path += bytesUsed; - // } - // if(remaining > 0) - // { - // strncpy(path, ".dmp", remaining); - // } - - char *pOut( LLApp::instance()->getMiniDumpFilename() ); - bool hasOverflow( false ); - S32 bufferLength( LLApp::MAX_MINDUMP_PATH_LENGTH ); - - hasOverflow = nd::strings::convertString( dump_path, pOut, bufferLength ); - if( !hasOverflow && bufferLength < LLApp::MAX_MINDUMP_PATH_LENGTH && bufferLength > 1 && pOut[-1] != '\\' && pOut[-1] != '/' ) - { - *pOut++ = '\\'; - --bufferLength; - } - - if( !hasOverflow ) - hasOverflow = nd::strings::convertString( minidump_id, pOut, bufferLength ); - - if( !hasOverflow && bufferLength >= 5 ) - { - pOut[0] = '.'; - pOut[1] = 'd'; - pOut[2] = 'm'; - pOut[3] = 'p'; - pOut[4] = 0; - } - else if( hasOverflow ) - LLApp::instance()->getMiniDumpFilename()[ 0 ] = 0; - - // - - LL_INFOS("CRASHREPORT") << "generated minidump: " << LLApp::instance()->getMiniDumpFilename() << LL_ENDL; - // *NOTE:Mani - this code is stolen from LLApp, where its never actually used. - //OSMessageBox("Attach Debugger Now", "Error", OSMB_OK); - // *TODO: Translate the signals/exceptions into cross-platform stuff - // Windows implementation - LL_INFOS() << "Entering Windows Exception Handler..." << LL_ENDL; - - if (LLApp::isError()) - { - LL_WARNS() << "Got another fatal signal while in the error handler, die now!" << LL_ENDL; - } - - // Flag status to error, so thread_error starts its work - LLApp::setError(); - - // Block in the exception handler until the app has stopped - // This is pretty sketchy, but appears to work just fine - while (!LLApp::isStopped()) - { - ms_sleep(10); - } - -#ifndef LL_RELEASE_FOR_DOWNLOAD - return false; -#else - return true; -#endif -} -#endif diff --git a/indra/llcommon/llapp.h b/indra/llcommon/llapp.h index 5fa91b8bf5..c65fe21c9c 100644 --- a/indra/llcommon/llapp.h +++ b/indra/llcommon/llapp.h @@ -28,9 +28,11 @@ #define LL_LLAPP_H #include +#include "llcond.h" #include "llrun.h" #include "llsd.h" #include +#include // Forward declarations class LLErrorThread; class LLLiveFile; @@ -49,10 +51,6 @@ void clear_signals(); #endif -namespace google_breakpad { - class ExceptionHandler; // See exception_handler.h -} - class LL_COMMON_API LLApp { friend class LLErrorThread; @@ -211,6 +209,36 @@ public: static bool isExiting(); // Either quitting or error (app is exiting, cleanly or not) static int getPid(); + // + // Sleep for specified time while still running + // + // For use by a coroutine or thread that performs some maintenance on a + // periodic basis. (See also LLEventTimer.) This method supports the + // pattern of an "infinite" loop that sleeps for some time, performs some + // action, then sleeps again. The trouble with literally sleeping a worker + // thread is that it could potentially sleep right through attempted + // application shutdown. This method avoids that by returning false as + // soon as the application status changes away from APP_STATUS_RUNNING + // (isRunning()). + // + // sleep() returns true if it sleeps undisturbed for the entire specified + // duration. The idea is that you can code 'while sleep(duration) ...', + // which will break the loop once shutdown begins. + // + // Since any time-based LLUnit should be implicitly convertible to + // F32Milliseconds, accept that specific type as a proxy. + static bool sleep(F32Milliseconds duration); + // Allow any duration defined in terms of . + // One can imagine a wonderfully general bidirectional conversion system + // between any type derived from LLUnits::LLUnit and + // any std::chrono::duration -- but that doesn't yet exist. + template + bool sleep(const std::chrono::duration& duration) + { + // wait_for_unequal() has the opposite bool return convention + return ! sStatus.wait_for_unequal(duration, APP_STATUS_RUNNING); + } + /** @name Error handling methods */ //@{ /** @@ -236,13 +264,12 @@ public: static const U32 MAX_MINDUMP_PATH_LENGTH = 256; // change the directory where Breakpad minidump files are written to - void setMiniDumpDir(const std::string &path); void setDebugFileNames(const std::string &path); // Return the Google Breakpad minidump filename after a crash. char *getMiniDumpFilename() { return mMinidumpPath; } - std::string* getStaticDebugFile() { return &mStaticDebugFileName; } - std::string* getDynamicDebugFile() { return &mDynamicDebugFileName; } + std::string* getStaticDebugFile() { return &mStaticDebugFileName; } + std::string* getDynamicDebugFile() { return &mDynamicDebugFileName; } // Write out a Google Breakpad minidump file. void writeMiniDump(); @@ -270,7 +297,7 @@ public: protected: static void setStatus(EAppStatus status); // Use this to change the application status. - static EAppStatus sStatus; // Reflects current application status + static LLScalarCond sStatus; // Reflects current application status static BOOL sErrorThreadRunning; // Set while the error thread is running static BOOL sDisableCrashlogger; // Let the OS handle crashes for us. std::wstring mCrashReportPipeStr; //Name of pipe to use for crash reporting. @@ -316,9 +343,6 @@ private: private: // the static application instance if it was created. static LLApp* sApplication; - - google_breakpad::ExceptionHandler * mExceptionHandler; - #if !LL_WINDOWS friend void default_unix_signal_handler(int signum, siginfo_t *info, void *); diff --git a/indra/llcommon/llcoros.cpp b/indra/llcommon/llcoros.cpp index 3a7ab0901e..2042051dd9 100644 --- a/indra/llcommon/llcoros.cpp +++ b/indra/llcommon/llcoros.cpp @@ -134,6 +134,13 @@ LLCoros::LLCoros(): LLCoros::~LLCoros() { +} + +void LLCoros::cleanupSingleton() +{ + // Some of the coroutines (like voice) will depend onto + // origin singletons, so clean coros before deleting those + printActiveCoroutines("at entry to ~LLCoros()"); // Other LLApp status-change listeners do things like close // work queues and inject the Stop exception into pending @@ -149,6 +156,8 @@ LLCoros::~LLCoros() { // don't use llcoro::suspend() because that module depends // on this one + // This will yield current(main) thread and will let active + // corutines run once boost::this_fiber::yield(); } printActiveCoroutines("after pumping"); diff --git a/indra/llcommon/llcoros.h b/indra/llcommon/llcoros.h index 6c0bec3ef9..a94cfca19f 100644 --- a/indra/llcommon/llcoros.h +++ b/indra/llcommon/llcoros.h @@ -89,6 +89,8 @@ class LL_COMMON_API LLCoros: public LLSingleton { LLSINGLETON(LLCoros); ~LLCoros(); + + void cleanupSingleton(); public: /// The viewer's use of the term "coroutine" became deeply embedded before /// the industry term "fiber" emerged to distinguish userland threads from diff --git a/indra/llcommon/llerror.cpp b/indra/llcommon/llerror.cpp index 2741209706..41c4e5d97c 100644 --- a/indra/llcommon/llerror.cpp +++ b/indra/llcommon/llerror.cpp @@ -481,6 +481,62 @@ namespace typedef std::vector Recorders; typedef std::vector CallSiteVector; + class SettingsConfig : public LLRefCount + { + friend class Globals; + + public: + virtual ~SettingsConfig(); + + LLError::ELevel mDefaultLevel; + + bool mLogAlwaysFlush; + + U32 mEnabledLogTypesMask; + + LevelMap mFunctionLevelMap; + LevelMap mClassLevelMap; + LevelMap mFileLevelMap; + LevelMap mTagLevelMap; + std::map mUniqueLogMessages; + + LLError::FatalFunction mCrashFunction; + LLError::TimeFunction mTimeFunction; + + Recorders mRecorders; + LLMutex mRecorderMutex; + + int mShouldLogCallCounter; + + private: + SettingsConfig(); + }; + + typedef LLPointer SettingsConfigPtr; + + SettingsConfig::SettingsConfig() + : LLRefCount(), + mDefaultLevel(LLError::LEVEL_DEBUG), + mLogAlwaysFlush(true), + mEnabledLogTypesMask(255), + mFunctionLevelMap(), + mClassLevelMap(), + mFileLevelMap(), + mTagLevelMap(), + mUniqueLogMessages(), + mCrashFunction(NULL), + mTimeFunction(NULL), + mRecorders(), + mRecorderMutex(), + mShouldLogCallCounter(0) + { + } + + SettingsConfig::~SettingsConfig() + { + mRecorders.clear(); + } + class Globals { public: @@ -488,16 +544,28 @@ namespace protected: Globals(); public: + std::ostringstream messageStream; + bool messageStreamInUse; std::string mFatalMessage; void addCallSite(LLError::CallSite&); void invalidateCallSites(); + SettingsConfigPtr getSettingsConfig(); + + void resetSettingsConfig(); + LLError::SettingsStoragePtr saveAndResetSettingsConfig(); + void restore(LLError::SettingsStoragePtr pSettingsStorage); private: CallSiteVector callSites; + SettingsConfigPtr mSettingsConfig; }; - Globals::Globals() {} + Globals::Globals() + : mSettingsConfig(new SettingsConfig()) + { + } + Globals* Globals::getInstance() { @@ -525,120 +593,31 @@ namespace callSites.clear(); } -} -namespace LLError -{ - class SettingsConfig : public LLRefCount - { - friend class Settings; - - public: - virtual ~SettingsConfig(); - - LLError::ELevel mDefaultLevel; - - bool mLogAlwaysFlush; - - U32 mEnabledLogTypesMask; - - LevelMap mFunctionLevelMap; - LevelMap mClassLevelMap; - LevelMap mFileLevelMap; - LevelMap mTagLevelMap; - std::map mUniqueLogMessages; - - LLError::FatalFunction mCrashFunction; - LLError::TimeFunction mTimeFunction; - - Recorders mRecorders; - - int mShouldLogCallCounter; - - private: - SettingsConfig(); - }; - - typedef LLPointer SettingsConfigPtr; - - class Settings - { - public: - static Settings* getInstance(); - protected: - Settings(); - public: - SettingsConfigPtr getSettingsConfig(); - - void reset(); - SettingsStoragePtr saveAndReset(); - void restore(SettingsStoragePtr pSettingsStorage); - - private: - SettingsConfigPtr mSettingsConfig; - }; - - SettingsConfig::SettingsConfig() - : LLRefCount(), - mDefaultLevel(LLError::LEVEL_DEBUG), - mLogAlwaysFlush(true), - mEnabledLogTypesMask(255), - mFunctionLevelMap(), - mClassLevelMap(), - mFileLevelMap(), - mTagLevelMap(), - mUniqueLogMessages(), - mCrashFunction([](const std::string&){}), - mTimeFunction(NULL), - mRecorders(), - mShouldLogCallCounter(0) - { - } - - SettingsConfig::~SettingsConfig() - { - mRecorders.clear(); - } - - Settings::Settings(): - mSettingsConfig(new SettingsConfig()) - { - } - - Settings* Settings::getInstance() + SettingsConfigPtr Globals::getSettingsConfig() { - // According to C++11 Function-Local Initialization - // of static variables is supposed to be thread safe - // without risk of deadlocks. - static Settings inst; - - return &inst; + return mSettingsConfig; } - SettingsConfigPtr Settings::getSettingsConfig() - { - return mSettingsConfig; - } + void Globals::resetSettingsConfig() + { + invalidateCallSites(); + mSettingsConfig = new SettingsConfig(); + } - void Settings::reset() - { - Globals::getInstance()->invalidateCallSites(); - mSettingsConfig = new SettingsConfig(); - } + LLError::SettingsStoragePtr Globals::saveAndResetSettingsConfig() + { + LLError::SettingsStoragePtr oldSettingsConfig(mSettingsConfig.get()); + resetSettingsConfig(); + return oldSettingsConfig; + } - SettingsStoragePtr Settings::saveAndReset() - { - SettingsStoragePtr oldSettingsConfig(mSettingsConfig.get()); - reset(); - return oldSettingsConfig; - } - - void Settings::restore(SettingsStoragePtr pSettingsStorage) - { - Globals::getInstance()->invalidateCallSites(); - SettingsConfigPtr newSettingsConfig(dynamic_cast(pSettingsStorage.get())); - mSettingsConfig = newSettingsConfig; - } + void Globals::restore(LLError::SettingsStoragePtr pSettingsStorage) + { + invalidateCallSites(); + SettingsConfigPtr newSettingsConfig(dynamic_cast(pSettingsStorage.get())); + mSettingsConfig = newSettingsConfig; + } } namespace LLError @@ -768,7 +747,7 @@ namespace void commonInit(const std::string& user_dir, const std::string& app_dir, bool log_to_stderr = true) { - LLError::Settings::getInstance()->reset(); + Globals::getInstance()->resetSettingsConfig(); LLError::setDefaultLevel(LLError::LEVEL_INFO); LLError::setAlwaysFlush(true); @@ -809,13 +788,13 @@ namespace LLError void setFatalFunction(const FatalFunction& f) { - SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig(); + SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig(); s->mCrashFunction = f; } FatalFunction getFatalFunction() { - SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig(); + SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig(); return s->mCrashFunction; } @@ -826,72 +805,77 @@ namespace LLError void setTimeFunction(TimeFunction f) { - SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig(); + SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig(); s->mTimeFunction = f; } void setDefaultLevel(ELevel level) { - Globals::getInstance()->invalidateCallSites(); - SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig(); + Globals *g = Globals::getInstance(); + g->invalidateCallSites(); + SettingsConfigPtr s = g->getSettingsConfig(); s->mDefaultLevel = level; } ELevel getDefaultLevel() { - SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig(); + SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig(); return s->mDefaultLevel; } void setAlwaysFlush(bool flush) { - SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig(); + SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig(); s->mLogAlwaysFlush = flush; } bool getAlwaysFlush() { - SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig(); + SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig(); return s->mLogAlwaysFlush; } void setEnabledLogTypesMask(U32 mask) { - SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig(); + SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig(); s->mEnabledLogTypesMask = mask; } U32 getEnabledLogTypesMask() { - SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig(); + SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig(); return s->mEnabledLogTypesMask; } void setFunctionLevel(const std::string& function_name, ELevel level) { - Globals::getInstance()->invalidateCallSites(); - SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig(); + Globals *g = Globals::getInstance(); + g->invalidateCallSites(); + SettingsConfigPtr s = g->getSettingsConfig(); s->mFunctionLevelMap[function_name] = level; } void setClassLevel(const std::string& class_name, ELevel level) { - Globals::getInstance()->invalidateCallSites(); - SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig(); + Globals *g = Globals::getInstance(); + g->invalidateCallSites(); + SettingsConfigPtr s = g->getSettingsConfig(); s->mClassLevelMap[class_name] = level; } void setFileLevel(const std::string& file_name, ELevel level) { - Globals::getInstance()->invalidateCallSites(); - SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig(); + Globals *g = Globals::getInstance(); + g->invalidateCallSites(); + SettingsConfigPtr s = g->getSettingsConfig(); s->mFileLevelMap[file_name] = level; } void setTagLevel(const std::string& tag_name, ELevel level) { - Globals::getInstance()->invalidateCallSites(); - SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig(); + Globals *g = Globals::getInstance(); + g->invalidateCallSites(); + SettingsConfigPtr s = g->getSettingsConfig(); s->mTagLevelMap[tag_name] = level; } @@ -936,8 +920,9 @@ namespace LLError { void configure(const LLSD& config) { - Globals::getInstance()->invalidateCallSites(); - SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig(); + Globals *g = Globals::getInstance(); + g->invalidateCallSites(); + SettingsConfigPtr s = g->getSettingsConfig(); s->mFunctionLevelMap.clear(); s->mClassLevelMap.clear(); @@ -1064,7 +1049,8 @@ namespace LLError { return; } - SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig(); + SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig(); + LLMutexLock lock(&s->mRecorderMutex); s->mRecorders.push_back(recorder); } @@ -1074,7 +1060,8 @@ namespace LLError { return; } - SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig(); + SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig(); + LLMutexLock lock(&s->mRecorderMutex); s->mRecorders.erase(std::remove(s->mRecorders.begin(), s->mRecorders.end(), recorder), s->mRecorders.end()); } @@ -1086,11 +1073,12 @@ namespace LLError // with a Recorders::iterator indicating the position of that entry in // mRecorders. The shared_ptr might be empty (operator!() returns true) if // there was no such RECORDER subclass instance in mRecorders. + // + // NOTE!!! Requires external mutex lock!!! template std::pair, Recorders::iterator> - findRecorderPos() + findRecorderPos(SettingsConfigPtr &s) { - SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig(); // Since we promise to return an iterator, use a classic iterator // loop. auto end{s->mRecorders.end()}; @@ -1121,7 +1109,9 @@ namespace LLError template boost::shared_ptr findRecorder() { - return findRecorderPos().first; + SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig(); + LLMutexLock lock(&s->mRecorderMutex); + return findRecorderPos(s).first; } // Remove an entry from SettingsConfig::mRecorders whose RecorderPtr @@ -1130,10 +1120,11 @@ namespace LLError template bool removeRecorder() { - auto found = findRecorderPos(); + SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig(); + LLMutexLock lock(&s->mRecorderMutex); + auto found = findRecorderPos(s); if (found.first) { - SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig(); s->mRecorders.erase(found.second); } return bool(found.first); @@ -1231,10 +1222,11 @@ namespace void writeToRecorders(const LLError::CallSite& site, const std::string& message) { LLError::ELevel level = site.mLevel; - LLError::SettingsConfigPtr s = LLError::Settings::getInstance()->getSettingsConfig(); + SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig(); std::string escaped_message; - + + LLMutexLock lock(&s->mRecorderMutex); for (Recorders::const_iterator i = s->mRecorders.begin(); i != s->mRecorders.end(); ++i) @@ -1376,7 +1368,8 @@ namespace LLError return false; } - SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig(); + Globals *g = Globals::getInstance(); + SettingsConfigPtr s = g->getSettingsConfig(); s->mShouldLogCallCounter++; @@ -1406,7 +1399,7 @@ namespace LLError : false); site.mCached = true; - Globals::getInstance()->addCallSite(site); + g->addCallSite(site); return site.mShouldLog = site.mLevel >= compareLevel; } @@ -1420,7 +1413,7 @@ namespace LLError } Globals* g = Globals::getInstance(); - SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig(); + SettingsConfigPtr s = g->getSettingsConfig(); std::string message = out.str(); @@ -1465,12 +1458,12 @@ namespace LLError { SettingsStoragePtr saveAndResetSettings() { - return Settings::getInstance()->saveAndReset(); + return Globals::getInstance()->saveAndResetSettingsConfig(); } void restoreSettings(SettingsStoragePtr pSettingsStorage) { - return Settings::getInstance()->restore(pSettingsStorage); + return Globals::getInstance()->restore(pSettingsStorage); } std::string removePrefix(std::string& s, const std::string& p) @@ -1516,7 +1509,7 @@ namespace LLError int shouldLogCallCount() { - SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig(); + SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig(); return s->mShouldLogCallCounter; } @@ -1628,8 +1621,8 @@ bool debugLoggingEnabled(const std::string& tag) { return false; } - - LLError::SettingsConfigPtr s = LLError::Settings::getInstance()->getSettingsConfig(); + + SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig(); LLError::ELevel level = LLError::LEVEL_DEBUG; bool res = checkLevelMap(s->mTagLevelMap, tag, level); return res; diff --git a/indra/llcommon/llevents.cpp b/indra/llcommon/llevents.cpp index 64fb985951..0a213bddef 100644 --- a/indra/llcommon/llevents.cpp +++ b/indra/llcommon/llevents.cpp @@ -45,7 +45,6 @@ #include // external library headers #include -#include #if LL_WINDOWS #pragma warning (push) #pragma warning (disable : 4701) // compiler thinks might use uninitialized var, but no @@ -285,7 +284,7 @@ LLEventPump::LLEventPump(const std::string& name, bool tweak): // Register every new instance with LLEventPumps mRegistry(LLEventPumps::instance().getHandle()), mName(mRegistry.get()->registerNew(*this, name, tweak)), - mSignal(boost::make_shared()), + mSignal(std::make_shared()), mEnabled(true) {} @@ -317,14 +316,24 @@ void LLEventPump::clear() { // Destroy the original LLStandardSignal instance, replacing it with a // whole new one. - mSignal = boost::make_shared(); + mSignal = std::make_shared(); mConnections.clear(); } void LLEventPump::reset() { - mSignal.reset(); + // Resetting mSignal is supposed to disconnect everything on its own + // But due to crash on 'reset' added explicit cleanup to get more data + ConnectionMap::const_iterator iter = mConnections.begin(); + ConnectionMap::const_iterator end = mConnections.end(); + while (iter!=end) + { + iter->second.disconnect(); + iter++; + } mConnections.clear(); + + mSignal.reset(); //mDeps.clear(); } @@ -543,7 +552,7 @@ bool LLEventStream::post(const LLSD& event) // *stack* instance of the shared_ptr, ensuring that our heap // LLStandardSignal object will live at least until post() returns, even // if 'this' gets destroyed during the call. - boost::shared_ptr signal(mSignal); + std::shared_ptr signal(mSignal); // Let caller know if any one listener handled the event. This is mostly // useful when using LLEventStream as a listener for an upstream // LLEventPump. diff --git a/indra/llcommon/llevents.h b/indra/llcommon/llevents.h index e380c108f4..ae6e5aabc9 100644 --- a/indra/llcommon/llevents.h +++ b/indra/llcommon/llevents.h @@ -49,8 +49,6 @@ #endif #include -#include -#include #include // noncopyable #include #include @@ -571,7 +569,7 @@ protected: const NameList& before); /// implement the dispatching - boost::shared_ptr mSignal; + std::shared_ptr mSignal; /// valve open? bool mEnabled; @@ -745,14 +743,4 @@ private: LL_COMMON_API bool sendReply(const LLSD& reply, const LLSD& request, const std::string& replyKey="reply"); -// Somewhat to my surprise, passing boost::bind(...boost::weak_ptr...) to -// listen() fails in Boost code trying to instantiate LLEventListener (i.e. -// LLStandardSignal::slot_type) because the boost::get_pointer() utility function isn't -// specialized for boost::weak_ptr. This remedies that omission. -namespace boost -{ - template - T* get_pointer(const weak_ptr& ptr) { return shared_ptr(ptr).get(); } -} - #endif /* ! defined(LL_LLEVENTS_H) */ diff --git a/indra/llcommon/llpreprocessor.h b/indra/llcommon/llpreprocessor.h index 26197cb692..95c9543751 100644 --- a/indra/llcommon/llpreprocessor.h +++ b/indra/llcommon/llpreprocessor.h @@ -40,6 +40,12 @@ #define LL_BIG_ENDIAN 1 #endif +// FIRE-31221 workaround for newer glibc versions, patch from Lance Corrimal +// Figure out GLIBC version - 2.34 needs an additional include as a build fix +#if (__GLIBC__*1000 + __GLIBC_MINOR__) >= 2034 +#include +#endif +// // Per-compiler switches diff --git a/indra/llcommon/llregex.h b/indra/llcommon/llregex.h new file mode 100644 index 0000000000..2b7f5e47c2 --- /dev/null +++ b/indra/llcommon/llregex.h @@ -0,0 +1,89 @@ +/** + * @file llregex.h + * + * $LicenseInfo:firstyear=2021&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2021, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LLREGEX_H +#define LLREGEX_H +#include + +template +LL_COMMON_API bool ll_regex_match(const S& string, M& match, const R& regex) +{ + try + { + return boost::regex_match(string, match, regex); + } + catch (const std::runtime_error& e) + { + LL_WARNS() << "error matching with '" << regex.str() << "': " + << e.what() << ":\n'" << string << "'" << LL_ENDL; + return false; + } +} + +template +LL_COMMON_API bool ll_regex_match(const S& string, const R& regex) +{ + try + { + return boost::regex_match(string, regex); + } + catch (const std::runtime_error& e) + { + LL_WARNS() << "error matching with '" << regex.str() << "': " + << e.what() << ":\n'" << string << "'" << LL_ENDL; + return false; + } +} + +template +bool ll_regex_search(const S& string, M& match, const R& regex) +{ + try + { + return boost::regex_search(string, match, regex); + } + catch (const std::runtime_error& e) + { + LL_WARNS() << "error searching with '" << regex.str() << "': " + << e.what() << ":\n'" << string << "'" << LL_ENDL; + return false; + } +} + +template +bool ll_regex_search(const S& string, const R& regex) +{ + try + { + return boost::regex_search(string, regex); + } + catch (const std::runtime_error& e) + { + LL_WARNS() << "error searching with '" << regex.str() << "': " + << e.what() << ":\n'" << string << "'" << LL_ENDL; + return false; + } +} +#endif // LLREGEX_H diff --git a/indra/llcommon/llsys.cpp b/indra/llcommon/llsys.cpp index dc4e6eda01..f69bfc4a54 100644 --- a/indra/llcommon/llsys.cpp +++ b/indra/llcommon/llsys.cpp @@ -43,12 +43,12 @@ #include "llerrorcontrol.h" #include "llevents.h" #include "llformat.h" +#include "llregex.h" #include "lltimer.h" #include "llsdserialize.h" #include "llsdutil.h" #include #include -#include #include #include #include @@ -101,39 +101,6 @@ static const F32 MEM_INFO_THROTTLE = 20; // dropped below the login framerate, we'd have very little additional data. static const F32 MEM_INFO_WINDOW = 10*60; -// Wrap boost::regex_match() with a function that doesn't throw. -template -static bool regex_match_no_exc(const S& string, M& match, const R& regex) -{ - try - { - return boost::regex_match(string, match, regex); - } - catch (const std::runtime_error& e) - { - LL_WARNS("LLMemoryInfo") << "error matching with '" << regex.str() << "': " - << e.what() << ":\n'" << string << "'" << LL_ENDL; - return false; - } -} - -// Wrap boost::regex_search() with a function that doesn't throw. -template -static bool regex_search_no_exc(const S& string, M& match, const R& regex) -{ - try - { - return boost::regex_search(string, match, regex); - } - catch (const std::runtime_error& e) - { - LL_WARNS("LLMemoryInfo") << "error searching with '" << regex.str() << "': " - << e.what() << ":\n'" << string << "'" << LL_ENDL; - return false; - } -} - - LLOSInfo::LLOSInfo() : mMajorVer(0), mMinorVer(0), mBuild(0), mOSVersionString("") { @@ -384,7 +351,7 @@ LLOSInfo::LLOSInfo() : boost::smatch matched; std::string glibc_version(gnu_get_libc_version()); - if ( regex_match_no_exc(glibc_version, matched, os_version_parse) ) + if ( ll_regex_match(glibc_version, matched, os_version_parse) ) { LL_INFOS("AppInit") << "Using glibc version '" << glibc_version << "' as OS version" << LL_ENDL; @@ -1061,7 +1028,7 @@ LLSD LLMemoryInfo::loadStatsMap() while (std::getline(meminfo, line)) { LL_DEBUGS("LLMemoryInfo") << line << LL_ENDL; - if (regex_match_no_exc(line, matched, stat_rx)) + if (ll_regex_match(line, matched, stat_rx)) { // e.g. "MemTotal: 4108424 kB" LLSD::String key(matched[1].first, matched[1].second); diff --git a/indra/llcommon/llthread.h b/indra/llcommon/llthread.h index 118c60d7a6..613431ee6a 100644 --- a/indra/llcommon/llthread.h +++ b/indra/llcommon/llthread.h @@ -27,7 +27,6 @@ #ifndef LL_LLTHREAD_H #define LL_LLTHREAD_H -#include "llapp.h" #include "llapr.h" #include "boost/intrusive_ptr.hpp" #include "llrefcount.h" diff --git a/indra/llcommon/lltracerecording.h b/indra/llcommon/lltracerecording.h index d0b4a842a6..2af5273d70 100644 --- a/indra/llcommon/lltracerecording.h +++ b/indra/llcommon/lltracerecording.h @@ -580,6 +580,31 @@ namespace LLTrace return typename RelatedTypes::fractional_t(getPeriodMeanPerSec(static_cast&>(stat), num_periods)); } + template + typename RelatedTypes::fractional_t getPeriodMedianPerSec(const StatType& stat, S32 num_periods = S32_MAX) + { + num_periods = llmin(num_periods, getNumRecordedPeriods()); + + std::vector ::fractional_t> buf; + for (S32 i = 1; i <= num_periods; i++) + { + Recording& recording = getPrevRecording(i); + if (recording.getDuration() > (F32Seconds)0.f) + { + buf.push_back(recording.getPerSec(stat)); + } + } + std::sort(buf.begin(), buf.end()); + + return typename RelatedTypes::fractional_t((buf.size() % 2 == 0) ? (buf[buf.size() / 2 - 1] + buf[buf.size() / 2]) / 2 : buf[buf.size() / 2]); + } + + template + typename RelatedTypes::fractional_t getPeriodMedianPerSec(const CountStatHandle& stat, S32 num_periods = S32_MAX) + { + return typename RelatedTypes::fractional_t(getPeriodMedianPerSec(static_cast&>(stat), num_periods)); + } + // // PERIODIC STANDARD DEVIATION // diff --git a/indra/llcommon/lluuid.cpp b/indra/llcommon/lluuid.cpp index 7ff040a602..94991373a8 100644 --- a/indra/llcommon/lluuid.cpp +++ b/indra/llcommon/lluuid.cpp @@ -33,6 +33,7 @@ #include #endif +#include "llapp.h" #include "lldefs.h" #include "llerror.h" @@ -44,7 +45,7 @@ #include "lltimer.h" #include "llthread.h" #include "llmutex.h" - +#include "fstelemetry.h" const LLUUID LLUUID::null; const LLTransactionID LLTransactionID::tnull; @@ -155,6 +156,7 @@ U32 janky_fast_random_seeded_bytes(U32 seed, U32 val) // Common to all UUID implementations void LLUUID::toString(std::string& out) const { + FSZone; out = llformat( "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x", (U8)(mData[0]), @@ -217,6 +219,7 @@ BOOL LLUUID::set(const char* in_string, BOOL emit) BOOL LLUUID::set(const std::string& in_string, BOOL emit) { + FSZone; BOOL broken_format = FALSE; // empty strings should make NULL uuid @@ -1027,6 +1030,7 @@ LLUUID::LLUUID() // Copy constructor LLUUID::LLUUID(const LLUUID& rhs) { + FSZone; // Fix for misaligned unsigned ints in LLUUID; by Sovereign Engineer / Shyotl Kuhr //U32 *tmp = (U32 *)mData; //U32 *rhstmp = (U32 *)rhs.mData; @@ -1045,6 +1049,7 @@ LLUUID::LLUUID() // Assignment LLUUID& LLUUID::operator=(const LLUUID& rhs) { + FSZone; // Fix for misaligned unsigned ints in LLUUID; by Sovereign Engineer / Shyotl Kuhr //// No need to check the case where this==&rhs. The branch is slower than the write. //U32 *tmp = (U32 *)mData; diff --git a/indra/llcommon/lluuid.h b/indra/llcommon/lluuid.h index b6399ad094..32f8b6c7c2 100644 --- a/indra/llcommon/lluuid.h +++ b/indra/llcommon/lluuid.h @@ -29,10 +29,11 @@ #include #include #include +#include // for std::memmove #include "stdtypes.h" #include "llpreprocessor.h" #include - +#include "fstelemetry.h" class LLMutex; const S32 UUID_BYTES = 16; @@ -56,7 +57,9 @@ public: explicit LLUUID(const char *in_string); // Convert from string. explicit LLUUID(const std::string& in_string); // Convert from string. LLUUID(const LLUUID &in); + LLUUID(LLUUID&& rhs) noexcept { FSZone; std::memmove(mData, rhs.mData, sizeof(mData));}; LLUUID &operator=(const LLUUID &rhs); + LLUUID &operator=(LLUUID &&rhs) noexcept {FSZone; std::memmove(mData, rhs.mData, sizeof(mData));return *this;}; ~LLUUID(); @@ -112,6 +115,61 @@ public: void toString(std::string& out) const; void toCompressedString(char *out) const; // Does not allocate memory, needs 17 characters (including \0) void toCompressedString(std::string& out) const; + + // last 4 chars for quick ref - Very lightweight, no nul-term added - provide your own, ensure min 4 bytes. +# define hexnybl(N) (N)>9?((N)-10)+'a':(N)+'0' + inline char * toShortString(char *out) const + { + FSZone; + out[0] = hexnybl(mData[14]>>4); + out[1] = hexnybl(mData[14]&15); + out[2] = hexnybl(mData[15]>>4); + out[3] = hexnybl(mData[15]&15); + return out; + } + // full uuid - Much lighterweight than default, no allocation, or nul-term added - provide your own, ensure min 36 bytes. + inline char * toStringFast(char *out) const + { + FSZone; + out[0] = hexnybl(mData[0]>>4); + out[1] = hexnybl(mData[0]&15); + out[2] = hexnybl(mData[1]>>4); + out[3] = hexnybl(mData[1]&15); + out[4] = hexnybl(mData[2]>>4); + out[5] = hexnybl(mData[2]&15); + out[6] = hexnybl(mData[3]>>4); + out[7] = hexnybl(mData[3]&15); + out[8] = '-'; + out[9] = hexnybl(mData[4]>>4); + out[10] = hexnybl(mData[4]&15); + out[11] = hexnybl(mData[5]>>4); + out[12] = hexnybl(mData[5]&15); + out[13] = '-'; + out[14] = hexnybl(mData[6]>>4); + out[15] = hexnybl(mData[6]&15); + out[16] = hexnybl(mData[7]>>4); + out[17] = hexnybl(mData[7]&15); + out[18] = '-'; + out[19] = hexnybl(mData[8]>>4); + out[20] = hexnybl(mData[8]&15); + out[21] = hexnybl(mData[9]>>4); + out[22] = hexnybl(mData[9]&15); + out[23] = '-'; + out[24] = hexnybl(mData[10]>>4); + out[25] = hexnybl(mData[10]&15); + out[26] = hexnybl(mData[11]>>4); + out[27] = hexnybl(mData[11]&15); + out[28] = hexnybl(mData[12]>>4); + out[29] = hexnybl(mData[12]&15); + out[30] = hexnybl(mData[13]>>4); + out[31] = hexnybl(mData[13]&15); + out[32] = hexnybl(mData[14]>>4); + out[33] = hexnybl(mData[14]&15); + out[34] = hexnybl(mData[15]>>4); + out[35] = hexnybl(mData[15]&15); + return out; + } + std::string asString() const; std::string getString() const; diff --git a/indra/llcorehttp/CMakeLists.txt b/indra/llcorehttp/CMakeLists.txt index 2f27c127cd..17d72a73d2 100644 --- a/indra/llcorehttp/CMakeLists.txt +++ b/indra/llcorehttp/CMakeLists.txt @@ -181,7 +181,6 @@ if (DARWIN) set(copy_dylibs libapr-1.0.dylib libaprutil-1.0.dylib - libexception_handler.dylib libnghttp2*.dylib liburiparser*.dylib ${EXPAT_COPY} diff --git a/indra/llcorehttp/_thread.h b/indra/llcorehttp/_thread.h index 22b7750bad..b784adfa85 100644 --- a/indra/llcorehttp/_thread.h +++ b/indra/llcorehttp/_thread.h @@ -35,6 +35,7 @@ #include "apr.h" // thread-related functions #include "_refcounted.h" +#include "fstelemetry.h" namespace LLCoreInt { @@ -54,6 +55,10 @@ private: void run() { // THREAD CONTEXT + // - Add threadnames + LL_INFOS("THREAD") << "Started unnamed HTTP thread " << LL_ENDL; + FSThreadName( "HTTP" ); + // // Take out additional reference for the at_exit handler addRef(); diff --git a/indra/llcorehttp/httpcommon.cpp b/indra/llcorehttp/httpcommon.cpp index e37a38b05f..61ba83594e 100644 --- a/indra/llcorehttp/httpcommon.cpp +++ b/indra/llcorehttp/httpcommon.cpp @@ -23,13 +23,6 @@ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ -#if LL_WINDOWS -#define SAFE_SSL 1 -#elif LL_DARWIN -#define SAFE_SSL 1 -#else -#define SAFE_SSL 1 -#endif #include "linden_common.h" // Modifies curl/curl.h interfaces #include "httpcommon.h" @@ -38,10 +31,6 @@ #include #include #include -#if SAFE_SSL -#include -#include // std::hash -#endif namespace LLCore @@ -281,9 +270,6 @@ namespace LLHttp { namespace { -typedef boost::shared_ptr LLMutex_ptr; -std::vector sSSLMutex; - CURL *getCurlTemplateHandle() { static CURL *curlpTemplateHandle = NULL; @@ -348,34 +334,6 @@ void deallocateEasyCurl(CURL *curlp) } -#if SAFE_SSL -//static -void ssl_locking_callback(int mode, int type, const char *file, int line) -{ - if (type >= sSSLMutex.size()) - { - LL_WARNS() << "Attempt to get unknown MUTEX in SSL Lock." << LL_ENDL; - } - - if (mode & CRYPTO_LOCK) - { - sSSLMutex[type]->lock(); - } - else - { - sSSLMutex[type]->unlock(); - } -} - -//static -unsigned long ssl_thread_id(void) -{ - // std::thread::id is very deliberately opaque, but we can hash it - return std::hash()(LLThread::currentID()); -} -#endif - - } void initialize() @@ -387,27 +345,11 @@ void initialize() check_curl_code(code, CURL_GLOBAL_ALL); -#if SAFE_SSL - S32 mutex_count = CRYPTO_num_locks(); - for (S32 i = 0; i < mutex_count; i++) - { - sSSLMutex.push_back(LLMutex_ptr(new LLMutex())); - } - CRYPTO_set_id_callback(&ssl_thread_id); - CRYPTO_set_locking_callback(&ssl_locking_callback); -#endif - } void cleanup() { -#if SAFE_SSL - CRYPTO_set_id_callback(NULL); - CRYPTO_set_locking_callback(NULL); - sSSLMutex.clear(); -#endif - curl_global_cleanup(); } diff --git a/indra/llcrashlogger/llcrashlogger.cpp b/indra/llcrashlogger/llcrashlogger.cpp index 9d3ad8b3b9..b18f6341cc 100644 --- a/indra/llcrashlogger/llcrashlogger.cpp +++ b/indra/llcrashlogger/llcrashlogger.cpp @@ -726,7 +726,7 @@ bool LLCrashLogger::init() #if LL_WINDOWS Sleep(1000); #else - sleep(1); + ::sleep(1); #endif locked = mKeyMaster.checkMaster(); } @@ -785,7 +785,7 @@ void LLCrashLogger::init_curl() } CRYPTO_set_locking_callback(ssl_locking_callback); - CRYPTO_THREADID_set_callback(ssl_thread_id_callback); + (void)CRYPTO_THREADID_set_callback(ssl_thread_id_callback); } } diff --git a/indra/llfilesystem/lldir.cpp b/indra/llfilesystem/lldir.cpp index 0a1dd3a8d5..9580c846fc 100644 --- a/indra/llfilesystem/lldir.cpp +++ b/indra/llfilesystem/lldir.cpp @@ -343,6 +343,11 @@ const std::string &LLDir::getDumpDir() const return LLDir::sDumpDir; } +bool LLDir::dumpDirExists() const +{ + return !sDumpDir.empty(); +} + const std::string &LLDir::getPerAccountChatLogsDir() const { return mPerAccountChatLogsDir; @@ -953,6 +958,11 @@ std::string LLDir::getScrubbedFileName(const std::string uncleanFileName) return name; } +std::string LLDir::getDumpLogsDirPath(const std::string &file_name) +{ + return gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "dump_logs", file_name); +} + // static std::string LLDir::getForbiddenFileChars() { diff --git a/indra/llfilesystem/lldir.h b/indra/llfilesystem/lldir.h index 5e9ad015eb..230a21ee9a 100644 --- a/indra/llfilesystem/lldir.h +++ b/indra/llfilesystem/lldir.h @@ -128,6 +128,7 @@ class LLDir const std::string &getLindenUserDir() const; // Location of the Linden user dir. const std::string &getChatLogsDir() const; // Location of the chat logs dir. const std::string &getDumpDir() const; // Location of the per-run dump dir. + bool dumpDirExists() const; const std::string &getPerAccountChatLogsDir() const; // Location of the per account chat logs dir. const std::string &getTempDir() const; // Common temporary directory const std::string getCacheDir(bool get_default = false) const; // Location of the cache. @@ -218,6 +219,8 @@ class LLDir // random filename in common temporary directory std::string getTempFilename() const; + static std::string getDumpLogsDirPath(const std::string &file_name = ""); + // For producing safe download file names from potentially unsafe ones static std::string getScrubbedFileName(const std::string uncleanFileName); static std::string getForbiddenFileChars(); diff --git a/indra/llfilesystem/lldiriterator.cpp b/indra/llfilesystem/lldiriterator.cpp index 3eb64e69d9..f57bf4ebc6 100644 --- a/indra/llfilesystem/lldiriterator.cpp +++ b/indra/llfilesystem/lldiriterator.cpp @@ -27,8 +27,8 @@ #include "lldiriterator.h" #include "fix_macros.h" +#include "llregex.h" #include -#include namespace fs = boost::filesystem; @@ -131,7 +131,7 @@ bool LLDirIterator::Impl::next(std::string &fname) { boost::smatch match; std::string name = mIter->path().filename().string(); - found = boost::regex_match(name, match, mFilterExp); + found = ll_regex_match(name, match, mFilterExp); if (found) { fname = name; diff --git a/indra/llfilesystem/lldiskcache.cpp b/indra/llfilesystem/lldiskcache.cpp index 589213733a..1ef3b0410c 100644 --- a/indra/llfilesystem/lldiskcache.cpp +++ b/indra/llfilesystem/lldiskcache.cpp @@ -31,6 +31,7 @@ */ #include "linden_common.h" +#include "llapp.h" #include "llassettype.h" #include "lldir.h" #include @@ -43,8 +44,6 @@ static const char* subdirs = "0123456789abcdef"; LLDiskCache::LLDiskCache(const std::string cache_dir, - // Fix integer overflow - //const int max_size_bytes, const uintmax_t max_size_bytes, const bool enable_cache_debug_info) : mCacheDir(cache_dir), @@ -69,6 +68,34 @@ LLDiskCache::LLDiskCache(const std::string cache_dir, // } +// WARNING: purge() is called by LLPurgeDiskCacheThread. As such it must +// NOT touch any LLDiskCache data without introducing and locking a mutex! + +// Interaction through the filesystem itself should be safe. Let’s say thread +// A is accessing the cache file for reading/writing and thread B is trimming +// the cache. Let’s also assume using llifstream to open a file and +// boost::filesystem::remove are not atomic (which will be pretty much the +// case). + +// Now, A is trying to open the file using llifstream ctor. It does some +// checks if the file exists and whatever else it might be doing, but has not +// issued the call to the OS to actually open the file yet. Now B tries to +// delete the file: If the file has been already marked as in use by the OS, +// deleting the file will fail and B will continue with the next file. A can +// safely continue opening the file. If the file has not yet been marked as in +// use, B will delete the file. Now A actually wants to open it, operation +// will fail, subsequent check via llifstream.is_open will fail, asset will +// have to be re-requested. (Assuming here the viewer will actually handle +// this situation properly, that can also happen if there is a file containing +// garbage.) + +// Other situation: B is trimming the cache and A wants to read a file that is +// about to get deleted. boost::filesystem::remove does whatever it is doing +// before actually deleting the file. If A opens the file before the file is +// actually gone, the OS call from B to delete the file will fail since the OS +// will prevent this. B continues with the next file. If the file is already +// gone before A finally gets to open it, this operation will fail and the +// asset will have to be re-requested. void LLDiskCache::purge() { if (mEnableCacheDebugInfo) @@ -151,15 +178,12 @@ void LLDiskCache::purge() { del++; // Extra accounting to track the retention of static assets // - // Do not crash if we cannot delete the file for some reason - //boost::filesystem::remove(entry.second.second); boost::filesystem::remove(entry.second.second, ec); if (ec.failed()) { LL_WARNS() << "Failed to delete cache file " << entry.second.second << ": " << ec.message() << LL_ENDL; } } - // } else { @@ -431,8 +455,6 @@ void LLDiskCache::clearCache() { if (remove_entry.string().find(mCacheFilenamePrefix) != std::string::npos) { - // Do not crash if we cannot delete the file for some reason - //boost::filesystem::remove(entry); const boost::filesystem::path remove_path = remove_entry; ++entry; boost::filesystem::remove(remove_path, ec); @@ -440,7 +462,6 @@ void LLDiskCache::clearCache() { LL_WARNS() << "Failed to delete cache file " << remove_path.string() << ": " << ec.message() << LL_ENDL; } - // } else { @@ -502,26 +523,17 @@ uintmax_t LLDiskCache::dirFileSize(const std::string dir) return total_file_size; } -// Regular disk cache cleanup -FSPurgeDiskCacheThread::FSPurgeDiskCacheThread() : +LLPurgeDiskCacheThread::LLPurgeDiskCacheThread() : LLThread("PurgeDiskCacheThread", nullptr) { } -void FSPurgeDiskCacheThread::run() +void LLPurgeDiskCacheThread::run() { - constexpr F64 CHECK_INTERVAL = 60; - mTimer.setTimerExpirySec(CHECK_INTERVAL); - mTimer.start(); + constexpr std::chrono::seconds CHECK_INTERVAL{60}; - do + while (LLApp::instance()->sleep(CHECK_INTERVAL)) { - if (mTimer.checkExpirationAndReset(CHECK_INTERVAL)) - { - LLDiskCache::instance().purge(); - } - - ms_sleep(100); - } while (!isQuitting()); + LLDiskCache::instance().purge(); + } } -// diff --git a/indra/llfilesystem/lldiskcache.h b/indra/llfilesystem/lldiskcache.h index 1164b428e0..0624c95700 100644 --- a/indra/llfilesystem/lldiskcache.h +++ b/indra/llfilesystem/lldiskcache.h @@ -86,8 +86,6 @@ class LLDiskCache : * The maximum size of the cache in bytes - Based on the * setting at 'CacheSize' and 'DiskCachePercentOfTotal' */ - // Fix integer overflow - //const int max_size_bytes, const uintmax_t max_size_bytes, /** * A flag that enables extra cache debugging so that @@ -128,6 +126,13 @@ class LLDiskCache : /** * Purge the oldest items in the cache so that the combined size of all files * is no bigger than mMaxSizeBytes. + * + * WARNING: purge() is called by LLPurgeDiskCacheThread. As such it must + * NOT touch any LLDiskCache data without introducing and locking a mutex! + * + * Purging the disk cache involves nontrivial work on the viewer's + * filesystem. If called on the main thread, this causes a noticeable + * freeze. */ void purge(); @@ -200,17 +205,12 @@ class LLDiskCache : std::vector mSkipList; // Vector of "static" untouchable assets that should never be purged }; -// Regular disk cache cleanup -class FSPurgeDiskCacheThread : public LLThread +class LLPurgeDiskCacheThread : public LLThread { public: - FSPurgeDiskCacheThread(); + LLPurgeDiskCacheThread(); protected: void run() override; - -private: - LLTimer mTimer; }; -// #endif // _LLDISKCACHE diff --git a/indra/llfilesystem/llfilesystem.cpp b/indra/llfilesystem/llfilesystem.cpp index a64070eb9d..61cc7756de 100644 --- a/indra/llfilesystem/llfilesystem.cpp +++ b/indra/llfilesystem/llfilesystem.cpp @@ -48,6 +48,28 @@ LLFileSystem::LLFileSystem(const LLUUID& file_id, const LLAssetType::EType file_ mPosition = 0; mBytesRead = 0; mMode = mode; + + // This block of code was originally called in the read() method but after comments here: + // https://bitbucket.org/lindenlab/viewer/commits/e28c1b46e9944f0215a13cab8ee7dded88d7fc90#comment-10537114 + // we decided to follow Henri's suggestion and move the code to update the last access time here. + if (mode == LLFileSystem::READ) + { + // build the filename (TODO: we do this in a few places - perhaps we should factor into a single function) + std::string id; + mFileID.toString(id); + const std::string extra_info = ""; + const std::string filename = LLDiskCache::getInstance()->metaDataToFilepath(id, mFileType, extra_info); + + // update the last access time for the file if it exists - this is required + // even though we are reading and not writing because this is the + // way the cache works - it relies on a valid "last accessed time" for + // each file so it knows how to remove the oldest, unused files + bool exists = gDirUtilp->fileExists(filename); + if (exists) + { + LLDiskCache::getInstance()->updateFileAccessTime(filename); + } + } } LLFileSystem::~LLFileSystem() @@ -153,8 +175,6 @@ S32 LLFileSystem::getFileSize(const LLUUID& file_id, const LLAssetType::EType fi BOOL LLFileSystem::read(U8* buffer, S32 bytes) { FSZoneC(tracy::Color::Gold); // measure cache performance - // Cache fixes - //BOOL success = TRUE; BOOL success = FALSE; std::string id; @@ -182,9 +202,9 @@ BOOL LLFileSystem::read(U8* buffer, S32 bytes) // file.close(); // mPosition += mBytesRead; - // if (!mBytesRead) + // if (mBytesRead) // { - // success = FALSE; + // success = TRUE; // } //} LLFILE* file = LLFile::fopen(filename, "rb"); @@ -206,12 +226,6 @@ BOOL LLFileSystem::read(U8* buffer, S32 bytes) } // - // update the last access time for the file - this is required - // even though we are reading and not writing because this is the - // way the cache works - it relies on a valid "last accessed time" for - // each file so it knows how to remove the oldest, unused files - LLDiskCache::getInstance()->updateFileAccessTime(filename); - return success; } diff --git a/indra/llimage/llimage.cpp b/indra/llimage/llimage.cpp index 7f87551b9e..4655923f99 100644 --- a/indra/llimage/llimage.cpp +++ b/indra/llimage/llimage.cpp @@ -1498,7 +1498,7 @@ bool LLImageRaw::scale( S32 new_width, S32 new_height, bool scale_image_data ) setDataAndSize(new_data, new_width, new_height, components); } } - else + else try { // copy out existing image data S32 temp_data_size = old_width * old_height * components; @@ -1532,6 +1532,11 @@ bool LLImageRaw::scale( S32 new_width, S32 new_height, bool scale_image_data ) } } } + catch (std::bad_alloc&) // for temp_buffer + { + LL_WARNS() << "Failed to allocate temporary image buffer" << LL_ENDL; + return false; + } return true ; } diff --git a/indra/llinventory/llsettingsbase.cpp b/indra/llinventory/llsettingsbase.cpp index 61b59e35aa..8a8e2bb340 100644 --- a/indra/llinventory/llsettingsbase.cpp +++ b/indra/llinventory/llsettingsbase.cpp @@ -395,7 +395,7 @@ bool LLSettingsBase::validate() LLSD LLSettingsBase::settingValidation(LLSD &settings, validation_list_t &validations, bool partial) { - static Validator validateName(SETTING_NAME, false, LLSD::TypeString, boost::bind(&Validator::verifyStringLength, _1, 63)); + static Validator validateName(SETTING_NAME, false, LLSD::TypeString, boost::bind(&Validator::verifyStringLength, _1, _2, 63)); static Validator validateId(SETTING_ID, false, LLSD::TypeUUID); static Validator validateHash(SETTING_HASH, false, LLSD::TypeInteger); static Validator validateType(SETTING_TYPE, false, LLSD::TypeString); @@ -534,7 +534,7 @@ bool LLSettingsBase::Validator::verify(LLSD &data, U32 flags) return false; } - if (!mVerify.empty() && !mVerify(data[mName])) + if (!mVerify.empty() && !mVerify(data[mName], flags)) { LL_WARNS("SETTINGS") << "Setting '" << mName << "' fails validation." << LL_ENDL; return false; @@ -543,17 +543,17 @@ bool LLSettingsBase::Validator::verify(LLSD &data, U32 flags) return true; } -bool LLSettingsBase::Validator::verifyColor(LLSD &value) +bool LLSettingsBase::Validator::verifyColor(LLSD &value, U32) { return (value.size() == 3 || value.size() == 4); } -bool LLSettingsBase::Validator::verifyVector(LLSD &value, S32 length) +bool LLSettingsBase::Validator::verifyVector(LLSD &value, U32, S32 length) { return (value.size() == length); } -bool LLSettingsBase::Validator::verifyVectorNormalized(LLSD &value, S32 length) +bool LLSettingsBase::Validator::verifyVectorNormalized(LLSD &value, U32, S32 length) { if (value.size() != length) return false; @@ -596,7 +596,7 @@ bool LLSettingsBase::Validator::verifyVectorNormalized(LLSD &value, S32 length) return true; } -bool LLSettingsBase::Validator::verifyVectorMinMax(LLSD &value, LLSD minvals, LLSD maxvals) +bool LLSettingsBase::Validator::verifyVectorMinMax(LLSD &value, U32, LLSD minvals, LLSD maxvals) { for (S32 index = 0; index < value.size(); ++index) { @@ -619,12 +619,12 @@ bool LLSettingsBase::Validator::verifyVectorMinMax(LLSD &value, LLSD minvals, LL return true; } -bool LLSettingsBase::Validator::verifyQuaternion(LLSD &value) +bool LLSettingsBase::Validator::verifyQuaternion(LLSD &value, U32) { return (value.size() == 4); } -bool LLSettingsBase::Validator::verifyQuaternionNormal(LLSD &value) +bool LLSettingsBase::Validator::verifyQuaternionNormal(LLSD &value, U32) { if (value.size() != 4) return false; @@ -642,7 +642,7 @@ bool LLSettingsBase::Validator::verifyQuaternionNormal(LLSD &value) return true; } -bool LLSettingsBase::Validator::verifyFloatRange(LLSD &value, LLSD range) +bool LLSettingsBase::Validator::verifyFloatRange(LLSD &value, U32, LLSD range) { F64 real = value.asReal(); @@ -655,7 +655,7 @@ bool LLSettingsBase::Validator::verifyFloatRange(LLSD &value, LLSD range) return true; } -bool LLSettingsBase::Validator::verifyIntegerRange(LLSD &value, LLSD range) +bool LLSettingsBase::Validator::verifyIntegerRange(LLSD &value, U32, LLSD range) { S32 ival = value.asInteger(); @@ -668,7 +668,7 @@ bool LLSettingsBase::Validator::verifyIntegerRange(LLSD &value, LLSD range) return true; } -bool LLSettingsBase::Validator::verifyStringLength(LLSD &value, S32 length) +bool LLSettingsBase::Validator::verifyStringLength(LLSD &value, U32, S32 length) { std::string sval = value.asString(); diff --git a/indra/llinventory/llsettingsbase.h b/indra/llinventory/llsettingsbase.h index f7a9d5b7cd..1f0589f571 100644 --- a/indra/llinventory/llsettingsbase.h +++ b/indra/llinventory/llsettingsbase.h @@ -270,7 +270,7 @@ public: public: static const U32 VALIDATION_PARTIAL; - typedef boost::function verify_pr; + typedef boost::function verify_pr; Validator(std::string name, bool required, LLSD::Type type, verify_pr verify = verify_pr(), LLSD defval = LLSD()) : mName(name), @@ -287,15 +287,15 @@ public: bool verify(LLSD &data, U32 flags); // Some basic verifications - static bool verifyColor(LLSD &value); - static bool verifyVector(LLSD &value, S32 length); - static bool verifyVectorMinMax(LLSD &value, LLSD minvals, LLSD maxvals); - static bool verifyVectorNormalized(LLSD &value, S32 length); - static bool verifyQuaternion(LLSD &value); - static bool verifyQuaternionNormal(LLSD &value); - static bool verifyFloatRange(LLSD &value, LLSD range); - static bool verifyIntegerRange(LLSD &value, LLSD range); - static bool verifyStringLength(LLSD &value, S32 length); + static bool verifyColor(LLSD &value, U32 flags); + static bool verifyVector(LLSD &value, U32 flags, S32 length); + static bool verifyVectorMinMax(LLSD &value, U32 flags, LLSD minvals, LLSD maxvals); + static bool verifyVectorNormalized(LLSD &value, U32 flags, S32 length); + static bool verifyQuaternion(LLSD &value, U32 flags); + static bool verifyQuaternionNormal(LLSD &value, U32 flags); + static bool verifyFloatRange(LLSD &value, U32 flags, LLSD range); + static bool verifyIntegerRange(LLSD &value, U32 flags, LLSD range); + static bool verifyStringLength(LLSD &value, U32 flags, S32 length); private: std::string mName; diff --git a/indra/llinventory/llsettingsdaycycle.cpp b/indra/llinventory/llsettingsdaycycle.cpp index d8bb7411a4..1bde690421 100644 --- a/indra/llinventory/llsettingsdaycycle.cpp +++ b/indra/llinventory/llsettingsdaycycle.cpp @@ -461,7 +461,7 @@ void LLSettingsDay::blend(const LLSettingsBase::ptr_t &other, F64 mix) namespace { - bool validateDayCycleTrack(LLSD &value) + bool validateDayCycleTrack(LLSD &value, U32 flags) { // Trim extra tracks. while (value.size() > LLSettingsDay::TRACK_MAX) @@ -532,7 +532,7 @@ namespace return true; } - bool validateDayCycleFrames(LLSD &value) + bool validateDayCycleFrames(LLSD &value, U32 flags) { bool hasSky(false); bool hasWater(false); @@ -545,7 +545,7 @@ namespace if (ftype == "sky") { LLSettingsSky::validation_list_t valid_sky = LLSettingsSky::validationList(); - LLSD res_sky = LLSettingsBase::settingValidation(frame, valid_sky); + LLSD res_sky = LLSettingsBase::settingValidation(frame, valid_sky, flags); if (res_sky["success"].asInteger() == 0) { @@ -558,7 +558,7 @@ namespace else if (ftype == "water") { LLSettingsWater::validation_list_t valid_h2o = LLSettingsWater::validationList(); - LLSD res_h2o = LLSettingsBase::settingValidation(frame, valid_h2o); + LLSD res_h2o = LLSettingsBase::settingValidation(frame, valid_h2o, flags); if (res_h2o["success"].asInteger() == 0) { LL_WARNS("SETTINGS") << "Water setting named '" << (*itf).first << "' validation failed!: " << res_h2o << LL_ENDL; @@ -574,18 +574,20 @@ namespace } } - if (!hasSky) + if ((flags & LLSettingsBase::Validator::VALIDATION_PARTIAL) == 0) { - LL_WARNS("SETTINGS") << "No skies defined." << LL_ENDL; - return false; - } + if (!hasSky) + { + LL_WARNS("SETTINGS") << "No skies defined." << LL_ENDL; + return false; + } - if (!hasWater) - { - LL_WARNS("SETTINGS") << "No waters defined." << LL_ENDL; - return false; + if (!hasWater) + { + LL_WARNS("SETTINGS") << "No waters defined." << LL_ENDL; + return false; + } } - return true; } } diff --git a/indra/llinventory/llsettingssky.cpp b/indra/llinventory/llsettingssky.cpp index 5e03064708..41c684b8df 100644 --- a/indra/llinventory/llsettingssky.cpp +++ b/indra/llinventory/llsettingssky.cpp @@ -156,29 +156,29 @@ LLSettingsSky::validation_list_t legacyHazeValidationList() if (legacyHazeValidation.empty()) { legacyHazeValidation.push_back(LLSettingsBase::Validator(LLSettingsSky::SETTING_AMBIENT, false, LLSD::TypeArray, - boost::bind(&LLSettingsBase::Validator::verifyVectorMinMax, _1, + boost::bind(&LLSettingsBase::Validator::verifyVectorMinMax, _1, _2, LLSD(LLSDArray(0.0f)(0.0f)(0.0f)("*")), LLSD(LLSDArray(3.0f)(3.0f)(3.0f)("*"))))); legacyHazeValidation.push_back(LLSettingsBase::Validator(LLSettingsSky::SETTING_BLUE_DENSITY, false, LLSD::TypeArray, - boost::bind(&LLSettingsBase::Validator::verifyVectorMinMax, _1, + boost::bind(&LLSettingsBase::Validator::verifyVectorMinMax, _1, _2, LLSD(LLSDArray(0.0f)(0.0f)(0.0f)("*")), LLSD(LLSDArray(3.0f)(3.0f)(3.0f)("*"))))); legacyHazeValidation.push_back(LLSettingsBase::Validator(LLSettingsSky::SETTING_BLUE_HORIZON, false, LLSD::TypeArray, - boost::bind(&LLSettingsBase::Validator::verifyVectorMinMax, _1, + boost::bind(&LLSettingsBase::Validator::verifyVectorMinMax, _1, _2, LLSD(LLSDArray(0.0f)(0.0f)(0.0f)("*")), LLSD(LLSDArray(3.0f)(3.0f)(3.0f)("*"))))); legacyHazeValidation.push_back(LLSettingsBase::Validator(LLSettingsSky::SETTING_HAZE_DENSITY, false, LLSD::TypeReal, - boost::bind(&LLSettingsBase::Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.0f)(5.0f))))); + boost::bind(&LLSettingsBase::Validator::verifyFloatRange, _1, _2, LLSD(LLSDArray(0.0f)(5.0f))))); legacyHazeValidation.push_back(LLSettingsBase::Validator(LLSettingsSky::SETTING_HAZE_HORIZON, false, LLSD::TypeReal, - boost::bind(&LLSettingsBase::Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.0f)(5.0f))))); + boost::bind(&LLSettingsBase::Validator::verifyFloatRange, _1, _2, LLSD(LLSDArray(0.0f)(5.0f))))); // FIRE-29682 Allow full range density multipliers // legacyHazeValidation.push_back(LLSettingsBase::Validator(LLSettingsSky::SETTING_DENSITY_MULTIPLIER, false, LLSD::TypeReal, - // boost::bind(&LLSettingsBase::Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.0001f)(2.0f))))); + // boost::bind(&LLSettingsBase::Validator::verifyFloatRange, _1, _2, LLSD(LLSDArray(0.0001f)(2.0f))))); legacyHazeValidation.push_back(LLSettingsBase::Validator(LLSettingsSky::SETTING_DENSITY_MULTIPLIER, false, LLSD::TypeReal, - boost::bind(&LLSettingsBase::Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.0000001f)(2.0f))))); + boost::bind(&LLSettingsBase::Validator::verifyFloatRange, _1, _2, LLSD(LLSDArray(0.0000001f)(2.0f))))); // legacyHazeValidation.push_back(LLSettingsBase::Validator(LLSettingsSky::SETTING_DISTANCE_MULTIPLIER, false, LLSD::TypeReal, - boost::bind(&LLSettingsBase::Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.0001f)(1000.0f))))); + boost::bind(&LLSettingsBase::Validator::verifyFloatRange, _1, _2, LLSD(LLSDArray(0.0001f)(1000.0f))))); } return legacyHazeValidation; } @@ -189,19 +189,19 @@ LLSettingsSky::validation_list_t rayleighValidationList() if (rayleighValidation.empty()) { rayleighValidation.push_back(LLSettingsBase::Validator(LLSettingsSky::SETTING_DENSITY_PROFILE_WIDTH, false, LLSD::TypeReal, - boost::bind(&LLSettingsBase::Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.0f)(32768.0f))))); + boost::bind(&LLSettingsBase::Validator::verifyFloatRange, _1, _2, LLSD(LLSDArray(0.0f)(32768.0f))))); rayleighValidation.push_back(LLSettingsBase::Validator(LLSettingsSky::SETTING_DENSITY_PROFILE_EXP_TERM, false, LLSD::TypeReal, - boost::bind(&LLSettingsBase::Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.0f)(2.0f))))); + boost::bind(&LLSettingsBase::Validator::verifyFloatRange, _1, _2, LLSD(LLSDArray(0.0f)(2.0f))))); rayleighValidation.push_back(LLSettingsBase::Validator(LLSettingsSky::SETTING_DENSITY_PROFILE_EXP_SCALE_FACTOR, false, LLSD::TypeReal, - boost::bind(&LLSettingsBase::Validator::verifyFloatRange, _1, LLSD(LLSDArray(-1.0f)(1.0f))))); + boost::bind(&LLSettingsBase::Validator::verifyFloatRange, _1, _2, LLSD(LLSDArray(-1.0f)(1.0f))))); rayleighValidation.push_back(LLSettingsBase::Validator(LLSettingsSky::SETTING_DENSITY_PROFILE_LINEAR_TERM, false, LLSD::TypeReal, - boost::bind(&LLSettingsBase::Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.0f)(2.0f))))); + boost::bind(&LLSettingsBase::Validator::verifyFloatRange, _1, _2, LLSD(LLSDArray(0.0f)(2.0f))))); rayleighValidation.push_back(LLSettingsBase::Validator(LLSettingsSky::SETTING_DENSITY_PROFILE_CONSTANT_TERM, false, LLSD::TypeReal, - boost::bind(&LLSettingsBase::Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.0f)(1.0f))))); + boost::bind(&LLSettingsBase::Validator::verifyFloatRange, _1, _2, LLSD(LLSDArray(0.0f)(1.0f))))); } return rayleighValidation; } @@ -212,19 +212,19 @@ LLSettingsSky::validation_list_t absorptionValidationList() if (absorptionValidation.empty()) { absorptionValidation.push_back(LLSettingsBase::Validator(LLSettingsSky::SETTING_DENSITY_PROFILE_WIDTH, false, LLSD::TypeReal, - boost::bind(&LLSettingsBase::Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.0f)(32768.0f))))); + boost::bind(&LLSettingsBase::Validator::verifyFloatRange, _1, _2, LLSD(LLSDArray(0.0f)(32768.0f))))); absorptionValidation.push_back(LLSettingsBase::Validator(LLSettingsSky::SETTING_DENSITY_PROFILE_EXP_TERM, false, LLSD::TypeReal, - boost::bind(&LLSettingsBase::Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.0f)(2.0f))))); + boost::bind(&LLSettingsBase::Validator::verifyFloatRange, _1, _2, LLSD(LLSDArray(0.0f)(2.0f))))); absorptionValidation.push_back(LLSettingsBase::Validator(LLSettingsSky::SETTING_DENSITY_PROFILE_EXP_SCALE_FACTOR, false, LLSD::TypeReal, - boost::bind(&LLSettingsBase::Validator::verifyFloatRange, _1, LLSD(LLSDArray(-1.0f)(1.0f))))); + boost::bind(&LLSettingsBase::Validator::verifyFloatRange, _1, _2, LLSD(LLSDArray(-1.0f)(1.0f))))); absorptionValidation.push_back(LLSettingsBase::Validator(LLSettingsSky::SETTING_DENSITY_PROFILE_LINEAR_TERM, false, LLSD::TypeReal, - boost::bind(&LLSettingsBase::Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.0f)(2.0f))))); + boost::bind(&LLSettingsBase::Validator::verifyFloatRange, _1, _2, LLSD(LLSDArray(0.0f)(2.0f))))); absorptionValidation.push_back(LLSettingsBase::Validator(LLSettingsSky::SETTING_DENSITY_PROFILE_CONSTANT_TERM, false, LLSD::TypeReal, - boost::bind(&LLSettingsBase::Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.0f)(1.0f))))); + boost::bind(&LLSettingsBase::Validator::verifyFloatRange, _1, _2, LLSD(LLSDArray(0.0f)(1.0f))))); } return absorptionValidation; } @@ -235,31 +235,31 @@ LLSettingsSky::validation_list_t mieValidationList() if (mieValidation.empty()) { mieValidation.push_back(LLSettingsBase::Validator(LLSettingsSky::SETTING_DENSITY_PROFILE_WIDTH, false, LLSD::TypeReal, - boost::bind(&LLSettingsBase::Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.0f)(32768.0f))))); + boost::bind(&LLSettingsBase::Validator::verifyFloatRange, _1, _2, LLSD(LLSDArray(0.0f)(32768.0f))))); mieValidation.push_back(LLSettingsBase::Validator(LLSettingsSky::SETTING_DENSITY_PROFILE_EXP_TERM, false, LLSD::TypeReal, - boost::bind(&LLSettingsBase::Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.0f)(2.0f))))); + boost::bind(&LLSettingsBase::Validator::verifyFloatRange, _1, _2, LLSD(LLSDArray(0.0f)(2.0f))))); mieValidation.push_back(LLSettingsBase::Validator(LLSettingsSky::SETTING_DENSITY_PROFILE_EXP_SCALE_FACTOR, false, LLSD::TypeReal, - boost::bind(&LLSettingsBase::Validator::verifyFloatRange, _1, LLSD(LLSDArray(-1.0f)(1.0f))))); + boost::bind(&LLSettingsBase::Validator::verifyFloatRange, _1, _2, LLSD(LLSDArray(-1.0f)(1.0f))))); mieValidation.push_back(LLSettingsBase::Validator(LLSettingsSky::SETTING_DENSITY_PROFILE_LINEAR_TERM, false, LLSD::TypeReal, - boost::bind(&LLSettingsBase::Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.0f)(2.0f))))); + boost::bind(&LLSettingsBase::Validator::verifyFloatRange, _1, _2, LLSD(LLSDArray(0.0f)(2.0f))))); mieValidation.push_back(LLSettingsBase::Validator(LLSettingsSky::SETTING_DENSITY_PROFILE_CONSTANT_TERM, false, LLSD::TypeReal, - boost::bind(&LLSettingsBase::Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.0f)(1.0f))))); + boost::bind(&LLSettingsBase::Validator::verifyFloatRange, _1, _2, LLSD(LLSDArray(0.0f)(1.0f))))); mieValidation.push_back(LLSettingsBase::Validator(LLSettingsSky::SETTING_MIE_ANISOTROPY_FACTOR, false, LLSD::TypeReal, - boost::bind(&LLSettingsBase::Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.0f)(1.0f))))); + boost::bind(&LLSettingsBase::Validator::verifyFloatRange, _1, _2, LLSD(LLSDArray(0.0f)(1.0f))))); } return mieValidation; } -bool validateLegacyHaze(LLSD &value) +bool validateLegacyHaze(LLSD &value, U32 flags) { LLSettingsSky::validation_list_t legacyHazeValidations = legacyHazeValidationList(); llassert(value.type() == LLSD::TypeMap); - LLSD result = LLSettingsBase::settingValidation(value, legacyHazeValidations); + LLSD result = LLSettingsBase::settingValidation(value, legacyHazeValidations, flags); if (result["errors"].size() > 0) { LL_WARNS("SETTINGS") << "Legacy Haze Config Validation errors: " << result["errors"] << LL_ENDL; @@ -273,7 +273,7 @@ bool validateLegacyHaze(LLSD &value) return true; } -bool validateRayleighLayers(LLSD &value) +bool validateRayleighLayers(LLSD &value, U32 flags) { LLSettingsSky::validation_list_t rayleighValidations = rayleighValidationList(); if (value.isArray()) @@ -284,24 +284,24 @@ bool validateRayleighLayers(LLSD &value) LLSD& layerConfig = (*itf); if (layerConfig.type() == LLSD::TypeMap) { - if (!validateRayleighLayers(layerConfig)) + if (!validateRayleighLayers(layerConfig, flags)) { allGood = false; } } else if (layerConfig.type() == LLSD::TypeArray) { - return validateRayleighLayers(layerConfig); + return validateRayleighLayers(layerConfig, flags); } else { - return LLSettingsBase::settingValidation(value, rayleighValidations); + return LLSettingsBase::settingValidation(value, rayleighValidations, flags); } } return allGood; } llassert(value.type() == LLSD::TypeMap); - LLSD result = LLSettingsBase::settingValidation(value, rayleighValidations); + LLSD result = LLSettingsBase::settingValidation(value, rayleighValidations, flags); if (result["errors"].size() > 0) { LL_WARNS("SETTINGS") << "Rayleigh Config Validation errors: " << result["errors"] << LL_ENDL; @@ -315,7 +315,7 @@ bool validateRayleighLayers(LLSD &value) return true; } -bool validateAbsorptionLayers(LLSD &value) +bool validateAbsorptionLayers(LLSD &value, U32 flags) { LLSettingsBase::validation_list_t absorptionValidations = absorptionValidationList(); if (value.isArray()) @@ -326,24 +326,24 @@ bool validateAbsorptionLayers(LLSD &value) LLSD& layerConfig = (*itf); if (layerConfig.type() == LLSD::TypeMap) { - if (!validateAbsorptionLayers(layerConfig)) + if (!validateAbsorptionLayers(layerConfig, flags)) { allGood = false; } } else if (layerConfig.type() == LLSD::TypeArray) { - return validateAbsorptionLayers(layerConfig); + return validateAbsorptionLayers(layerConfig, flags); } else { - return LLSettingsBase::settingValidation(value, absorptionValidations); + return LLSettingsBase::settingValidation(value, absorptionValidations, flags); } } return allGood; } llassert(value.type() == LLSD::TypeMap); - LLSD result = LLSettingsBase::settingValidation(value, absorptionValidations); + LLSD result = LLSettingsBase::settingValidation(value, absorptionValidations, flags); if (result["errors"].size() > 0) { LL_WARNS("SETTINGS") << "Absorption Config Validation errors: " << result["errors"] << LL_ENDL; @@ -357,7 +357,7 @@ bool validateAbsorptionLayers(LLSD &value) return true; } -bool validateMieLayers(LLSD &value) +bool validateMieLayers(LLSD &value, U32 flags) { LLSettingsBase::validation_list_t mieValidations = mieValidationList(); if (value.isArray()) @@ -368,23 +368,23 @@ bool validateMieLayers(LLSD &value) LLSD& layerConfig = (*itf); if (layerConfig.type() == LLSD::TypeMap) { - if (!validateMieLayers(layerConfig)) + if (!validateMieLayers(layerConfig, flags)) { allGood = false; } } else if (layerConfig.type() == LLSD::TypeArray) { - return validateMieLayers(layerConfig); + return validateMieLayers(layerConfig, flags); } else { - return LLSettingsBase::settingValidation(value, mieValidations); + return LLSettingsBase::settingValidation(value, mieValidations, flags); } } return allGood; } - LLSD result = LLSettingsBase::settingValidation(value, mieValidations); + LLSD result = LLSettingsBase::settingValidation(value, mieValidations, flags); if (result["errors"].size() > 0) { LL_WARNS("SETTINGS") << "Mie Config Validation errors: " << result["errors"] << LL_ENDL; @@ -563,80 +563,80 @@ LLSettingsSky::validation_list_t LLSettingsSky::validationList() validation.push_back(Validator(SETTING_HALO_TEXTUREID, false, LLSD::TypeUUID)); validation.push_back(Validator(SETTING_CLOUD_COLOR, true, LLSD::TypeArray, - boost::bind(&Validator::verifyVectorMinMax, _1, + boost::bind(&Validator::verifyVectorMinMax, _1, _2, LLSD(LLSDArray(0.0f)(0.0f)(0.0f)("*")), LLSD(LLSDArray(1.0f)(1.0f)(1.0f)("*"))))); validation.push_back(Validator(SETTING_CLOUD_POS_DENSITY1, true, LLSD::TypeArray, - boost::bind(&Validator::verifyVectorMinMax, _1, + boost::bind(&Validator::verifyVectorMinMax, _1, _2, LLSD(LLSDArray(0.0f)(0.0f)(0.0f)("*")), LLSD(LLSDArray(1.0f)(1.0f)(3.0f)("*"))))); validation.push_back(Validator(SETTING_CLOUD_POS_DENSITY2, true, LLSD::TypeArray, - boost::bind(&Validator::verifyVectorMinMax, _1, + boost::bind(&Validator::verifyVectorMinMax, _1, _2, LLSD(LLSDArray(0.0f)(0.0f)(0.0f)("*")), LLSD(LLSDArray(1.0f)(1.0f)(1.0f)("*"))))); validation.push_back(Validator(SETTING_CLOUD_SCALE, true, LLSD::TypeReal, - boost::bind(&Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.001f)(3.0f))))); + boost::bind(&Validator::verifyFloatRange, _1, _2, LLSD(LLSDArray(0.001f)(3.0f))))); validation.push_back(Validator(SETTING_CLOUD_SCROLL_RATE, true, LLSD::TypeArray, - boost::bind(&Validator::verifyVectorMinMax, _1, + boost::bind(&Validator::verifyVectorMinMax, _1, _2, LLSD(LLSDArray(-50.0f)(-50.0f)), LLSD(LLSDArray(50.0f)(50.0f))))); validation.push_back(Validator(SETTING_CLOUD_SHADOW, true, LLSD::TypeReal, - boost::bind(&Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.0f)(1.0f))))); + boost::bind(&Validator::verifyFloatRange, _1, _2, LLSD(LLSDArray(0.0f)(1.0f))))); validation.push_back(Validator(SETTING_CLOUD_TEXTUREID, false, LLSD::TypeUUID)); validation.push_back(Validator(SETTING_CLOUD_VARIANCE, false, LLSD::TypeReal, - boost::bind(&Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.0f)(1.0f))))); + boost::bind(&Validator::verifyFloatRange, _1, _2, LLSD(LLSDArray(0.0f)(1.0f))))); validation.push_back(Validator(SETTING_DOME_OFFSET, false, LLSD::TypeReal, - boost::bind(&Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.0f)(1.0f))))); + boost::bind(&Validator::verifyFloatRange, _1, _2, LLSD(LLSDArray(0.0f)(1.0f))))); validation.push_back(Validator(SETTING_DOME_RADIUS, false, LLSD::TypeReal, - boost::bind(&Validator::verifyFloatRange, _1, LLSD(LLSDArray(1000.0f)(2000.0f))))); + boost::bind(&Validator::verifyFloatRange, _1, _2, LLSD(LLSDArray(1000.0f)(2000.0f))))); validation.push_back(Validator(SETTING_GAMMA, true, LLSD::TypeReal, - boost::bind(&Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.0f)(20.0f))))); + boost::bind(&Validator::verifyFloatRange, _1, _2, LLSD(LLSDArray(0.0f)(20.0f))))); validation.push_back(Validator(SETTING_GLOW, true, LLSD::TypeArray, - boost::bind(&Validator::verifyVectorMinMax, _1, + boost::bind(&Validator::verifyVectorMinMax, _1, _2, LLSD(LLSDArray(0.2f)("*")(-10.0f)("*")), LLSD(LLSDArray(40.0f)("*")(10.0f)("*"))))); validation.push_back(Validator(SETTING_MAX_Y, true, LLSD::TypeReal, - boost::bind(&Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.0f)(10000.0f))))); + boost::bind(&Validator::verifyFloatRange, _1, _2, LLSD(LLSDArray(0.0f)(10000.0f))))); validation.push_back(Validator(SETTING_MOON_ROTATION, true, LLSD::TypeArray, &Validator::verifyQuaternionNormal)); validation.push_back(Validator(SETTING_MOON_SCALE, false, LLSD::TypeReal, - boost::bind(&Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.25f)(20.0f))), LLSD::Real(1.0))); + boost::bind(&Validator::verifyFloatRange, _1, _2, LLSD(LLSDArray(0.25f)(20.0f))), LLSD::Real(1.0))); validation.push_back(Validator(SETTING_MOON_TEXTUREID, false, LLSD::TypeUUID)); validation.push_back(Validator(SETTING_MOON_BRIGHTNESS, false, LLSD::TypeReal, - boost::bind(&Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.0f)(1.0f))))); + boost::bind(&Validator::verifyFloatRange, _1, _2, LLSD(LLSDArray(0.0f)(1.0f))))); validation.push_back(Validator(SETTING_STAR_BRIGHTNESS, true, LLSD::TypeReal, - boost::bind(&Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.0f)(500.0f))))); + boost::bind(&Validator::verifyFloatRange, _1, _2, LLSD(LLSDArray(0.0f)(500.0f))))); validation.push_back(Validator(SETTING_SUNLIGHT_COLOR, true, LLSD::TypeArray, - boost::bind(&Validator::verifyVectorMinMax, _1, + boost::bind(&Validator::verifyVectorMinMax, _1, _2, LLSD(LLSDArray(0.0f)(0.0f)(0.0f)("*")), LLSD(LLSDArray(3.0f)(3.0f)(3.0f)("*"))))); validation.push_back(Validator(SETTING_SUN_ROTATION, true, LLSD::TypeArray, &Validator::verifyQuaternionNormal)); validation.push_back(Validator(SETTING_SUN_SCALE, false, LLSD::TypeReal, - boost::bind(&Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.25f)(20.0f))), LLSD::Real(1.0))); + boost::bind(&Validator::verifyFloatRange, _1, _2, LLSD(LLSDArray(0.25f)(20.0f))), LLSD::Real(1.0))); validation.push_back(Validator(SETTING_SUN_TEXTUREID, false, LLSD::TypeUUID)); validation.push_back(Validator(SETTING_PLANET_RADIUS, true, LLSD::TypeReal, - boost::bind(&Validator::verifyFloatRange, _1, LLSD(LLSDArray(1000.0f)(32768.0f))))); + boost::bind(&Validator::verifyFloatRange, _1, _2, LLSD(LLSDArray(1000.0f)(32768.0f))))); validation.push_back(Validator(SETTING_SKY_BOTTOM_RADIUS, true, LLSD::TypeReal, - boost::bind(&Validator::verifyFloatRange, _1, LLSD(LLSDArray(1000.0f)(32768.0f))))); + boost::bind(&Validator::verifyFloatRange, _1, _2, LLSD(LLSDArray(1000.0f)(32768.0f))))); validation.push_back(Validator(SETTING_SKY_TOP_RADIUS, true, LLSD::TypeReal, - boost::bind(&Validator::verifyFloatRange, _1, LLSD(LLSDArray(1000.0f)(32768.0f))))); + boost::bind(&Validator::verifyFloatRange, _1, _2, LLSD(LLSDArray(1000.0f)(32768.0f))))); validation.push_back(Validator(SETTING_SUN_ARC_RADIANS, true, LLSD::TypeReal, - boost::bind(&Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.0f)(0.1f))))); + boost::bind(&Validator::verifyFloatRange, _1, _2, LLSD(LLSDArray(0.0f)(0.1f))))); validation.push_back(Validator(SETTING_SKY_MOISTURE_LEVEL, false, LLSD::TypeReal, - boost::bind(&Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.0f)(1.0f))))); + boost::bind(&Validator::verifyFloatRange, _1, _2, LLSD(LLSDArray(0.0f)(1.0f))))); validation.push_back(Validator(SETTING_SKY_DROPLET_RADIUS, false, LLSD::TypeReal, - boost::bind(&Validator::verifyFloatRange, _1, LLSD(LLSDArray(5.0f)(1000.0f))))); + boost::bind(&Validator::verifyFloatRange, _1, _2, LLSD(LLSDArray(5.0f)(1000.0f))))); validation.push_back(Validator(SETTING_SKY_ICE_LEVEL, false, LLSD::TypeReal, - boost::bind(&Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.0f)(1.0f))))); + boost::bind(&Validator::verifyFloatRange, _1, _2, LLSD(LLSDArray(0.0f)(1.0f))))); validation.push_back(Validator(SETTING_RAYLEIGH_CONFIG, true, LLSD::TypeArray, &validateRayleighLayers)); validation.push_back(Validator(SETTING_ABSORPTION_CONFIG, true, LLSD::TypeArray, &validateAbsorptionLayers)); diff --git a/indra/llinventory/llsettingswater.cpp b/indra/llinventory/llsettingswater.cpp index 0eb95dcd89..1ae8d78b22 100644 --- a/indra/llinventory/llsettingswater.cpp +++ b/indra/llinventory/llsettingswater.cpp @@ -236,34 +236,34 @@ LLSettingsWater::validation_list_t LLSettingsWater::validationList() // in deeply nested arrays like this [[[[[[[[[[v1,v2,v3]]]]]]]]]] validation.push_back(Validator(SETTING_BLUR_MULTIPLIER, true, LLSD::TypeReal, - boost::bind(&Validator::verifyFloatRange, _1, LLSD(LLSDArray(-0.5f)(0.5f))))); + boost::bind(&Validator::verifyFloatRange, _1, _2, LLSD(LLSDArray(-0.5f)(0.5f))))); validation.push_back(Validator(SETTING_FOG_COLOR, true, LLSD::TypeArray, - boost::bind(&Validator::verifyVectorMinMax, _1, + boost::bind(&Validator::verifyVectorMinMax, _1, _2, LLSD(LLSDArray(0.0f)(0.0f)(0.0f)(1.0f)), LLSD(LLSDArray(1.0f)(1.0f)(1.0f)(1.0f))))); validation.push_back(Validator(SETTING_FOG_DENSITY, true, LLSD::TypeReal, - boost::bind(&Validator::verifyFloatRange, _1, LLSD(LLSDArray(-10.0f)(10.0f))))); + boost::bind(&Validator::verifyFloatRange, _1, _2, LLSD(LLSDArray(-10.0f)(10.0f))))); validation.push_back(Validator(SETTING_FOG_MOD, true, LLSD::TypeReal, - boost::bind(&Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.0f)(20.0f))))); + boost::bind(&Validator::verifyFloatRange, _1, _2, LLSD(LLSDArray(0.0f)(20.0f))))); validation.push_back(Validator(SETTING_FRESNEL_OFFSET, true, LLSD::TypeReal, - boost::bind(&Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.0f)(1.0f))))); + boost::bind(&Validator::verifyFloatRange, _1, _2, LLSD(LLSDArray(0.0f)(1.0f))))); validation.push_back(Validator(SETTING_FRESNEL_SCALE, true, LLSD::TypeReal, - boost::bind(&Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.0f)(1.0f))))); + boost::bind(&Validator::verifyFloatRange, _1, _2, LLSD(LLSDArray(0.0f)(1.0f))))); validation.push_back(Validator(SETTING_NORMAL_MAP, true, LLSD::TypeUUID)); validation.push_back(Validator(SETTING_NORMAL_SCALE, true, LLSD::TypeArray, - boost::bind(&Validator::verifyVectorMinMax, _1, + boost::bind(&Validator::verifyVectorMinMax, _1, _2, LLSD(LLSDArray(0.0f)(0.0f)(0.0f)), LLSD(LLSDArray(10.0f)(10.0f)(10.0f))))); validation.push_back(Validator(SETTING_SCALE_ABOVE, true, LLSD::TypeReal, - boost::bind(&Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.0f)(3.0f))))); + boost::bind(&Validator::verifyFloatRange, _1, _2, LLSD(LLSDArray(0.0f)(3.0f))))); validation.push_back(Validator(SETTING_SCALE_BELOW, true, LLSD::TypeReal, - boost::bind(&Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.0f)(3.0f))))); + boost::bind(&Validator::verifyFloatRange, _1, _2, LLSD(LLSDArray(0.0f)(3.0f))))); validation.push_back(Validator(SETTING_WAVE1_DIR, true, LLSD::TypeArray, - boost::bind(&Validator::verifyVectorMinMax, _1, + boost::bind(&Validator::verifyVectorMinMax, _1, _2, LLSD(LLSDArray(-20.0f)(-20.0f)), LLSD(LLSDArray(20.0f)(20.0f))))); validation.push_back(Validator(SETTING_WAVE2_DIR, true, LLSD::TypeArray, - boost::bind(&Validator::verifyVectorMinMax, _1, + boost::bind(&Validator::verifyVectorMinMax, _1, _2, LLSD(LLSDArray(-20.0f)(-20.0f)), LLSD(LLSDArray(20.0f)(20.0f))))); } diff --git a/indra/llmessage/llblowfishcipher.cpp b/indra/llmessage/llblowfishcipher.cpp index de099c347c..2f71e71df3 100644 --- a/indra/llmessage/llblowfishcipher.cpp +++ b/indra/llmessage/llblowfishcipher.cpp @@ -52,24 +52,28 @@ U32 LLBlowfishCipher::encrypt(const U8* src, U32 src_len, U8* dst, U32 dst_len) if (src_len > dst_len) return 0; // OpenSSL uses "cipher contexts" to hold encryption parameters. - EVP_CIPHER_CTX context; - EVP_CIPHER_CTX_init(&context); + EVP_CIPHER_CTX *context = EVP_CIPHER_CTX_new(); + if (!context) + { + LL_WARNS() << "LLBlowfishCipher::encrypt EVP_CIPHER_CTX initiation failure" << LL_ENDL; + return 0; + } // We want a blowfish cyclic block chain cipher, but need to set // the key length before we pass in a key, so call EncryptInit // first with NULLs. - EVP_EncryptInit_ex(&context, EVP_bf_cbc(), NULL, NULL, NULL); - EVP_CIPHER_CTX_set_key_length(&context, (int)mSecretSize); + EVP_EncryptInit_ex(context, EVP_bf_cbc(), NULL, NULL, NULL); + EVP_CIPHER_CTX_set_key_length(context, (int)mSecretSize); // Complete initialization. Per EVP_EncryptInit man page, the // cipher pointer must be NULL. Apparently initial_vector must // be 8 bytes for blowfish, as this is the block size. unsigned char initial_vector[] = { 0, 0, 0, 0, 0, 0, 0, 0 }; - EVP_EncryptInit_ex(&context, NULL, NULL, mSecret, initial_vector); + EVP_EncryptInit_ex(context, NULL, NULL, mSecret, initial_vector); - int blocksize = EVP_CIPHER_CTX_block_size(&context); - int keylen = EVP_CIPHER_CTX_key_length(&context); - int iv_length = EVP_CIPHER_CTX_iv_length(&context); + int blocksize = EVP_CIPHER_CTX_block_size(context); + int keylen = EVP_CIPHER_CTX_key_length(context); + int iv_length = EVP_CIPHER_CTX_iv_length(context); LL_DEBUGS() << "LLBlowfishCipher blocksize " << blocksize << " keylen " << keylen << " iv_len " << iv_length @@ -77,7 +81,7 @@ U32 LLBlowfishCipher::encrypt(const U8* src, U32 src_len, U8* dst, U32 dst_len) int output_len = 0; int temp_len = 0; - if (!EVP_EncryptUpdate(&context, + if (!EVP_EncryptUpdate(context, dst, &output_len, src, @@ -89,18 +93,18 @@ U32 LLBlowfishCipher::encrypt(const U8* src, U32 src_len, U8* dst, U32 dst_len) // There may be some final data left to encrypt if the input is // not an exact multiple of the block size. - if (!EVP_EncryptFinal_ex(&context, (unsigned char*)(dst + output_len), &temp_len)) + if (!EVP_EncryptFinal_ex(context, (unsigned char*)(dst + output_len), &temp_len)) { LL_WARNS() << "LLBlowfishCipher::encrypt EVP_EncryptFinal failure" << LL_ENDL; goto ERROR; } output_len += temp_len; - EVP_CIPHER_CTX_cleanup(&context); + EVP_CIPHER_CTX_free(context); return output_len; ERROR: - EVP_CIPHER_CTX_cleanup(&context); + EVP_CIPHER_CTX_free(context); return 0; } @@ -113,18 +117,22 @@ U32 LLBlowfishCipher::decrypt(const U8* src, U32 src_len, U8* dst, U32 dst_len) if (!src || !src_len || !dst || !dst_len) return 0; if (src_len > dst_len) return 0; - EVP_CIPHER_CTX context; - EVP_CIPHER_CTX_init(&context); - - EVP_DecryptInit_ex(&context, EVP_bf_cbc(), NULL, NULL, NULL); - EVP_CIPHER_CTX_set_key_length(&context, (int)mSecretSize); + EVP_CIPHER_CTX *context = EVP_CIPHER_CTX_new(); + if (!context) + { + LL_WARNS() << "LLBlowfishCipher::encrypt EVP_CIPHER_CTX initiation failure" << LL_ENDL; + return 0; + } + + EVP_DecryptInit_ex(context, EVP_bf_cbc(), NULL, NULL, NULL); + EVP_CIPHER_CTX_set_key_length(context, (int)mSecretSize); unsigned char initial_vector[] = { 0, 0, 0, 0, 0, 0, 0, 0 }; - EVP_DecryptInit_ex(&context, NULL, NULL, mSecret, initial_vector); + EVP_DecryptInit_ex(context, NULL, NULL, mSecret, initial_vector); - int blocksize = EVP_CIPHER_CTX_block_size(&context); - int keylen = EVP_CIPHER_CTX_key_length(&context); - int iv_length = EVP_CIPHER_CTX_iv_length(&context); + int blocksize = EVP_CIPHER_CTX_block_size(context); + int keylen = EVP_CIPHER_CTX_key_length(context); + int iv_length = EVP_CIPHER_CTX_iv_length(context); LL_DEBUGS() << "LLBlowfishCipher blocksize " << blocksize << " keylen " << keylen << " iv_len " << iv_length @@ -132,12 +140,12 @@ U32 LLBlowfishCipher::decrypt(const U8* src, U32 src_len, U8* dst, U32 dst_len) int out_len = 0; int tmp_len = 0; - if (!EVP_DecryptUpdate(&context, dst, &out_len, src, src_len)) + if (!EVP_DecryptUpdate(context, dst, &out_len, src, src_len)) { LL_WARNS() << "LLBlowfishCipher::decrypt EVP_DecryptUpdate failure" << LL_ENDL; goto ERROR; } - if (!EVP_DecryptFinal_ex(&context, dst + out_len, &tmp_len)) + if (!EVP_DecryptFinal_ex(context, dst + out_len, &tmp_len)) { LL_WARNS() << "LLBlowfishCipher::decrypt EVP_DecryptFinal failure" << LL_ENDL; goto ERROR; @@ -145,11 +153,11 @@ U32 LLBlowfishCipher::decrypt(const U8* src, U32 src_len, U8* dst, U32 dst_len) out_len += tmp_len; - EVP_CIPHER_CTX_cleanup(&context); + EVP_CIPHER_CTX_free(context); return out_len; ERROR: - EVP_CIPHER_CTX_cleanup(&context); + EVP_CIPHER_CTX_free(context); return 0; // } diff --git a/indra/llmessage/lldatapacker.cpp b/indra/llmessage/lldatapacker.cpp index 5104373926..bf05b8b33b 100644 --- a/indra/llmessage/lldatapacker.cpp +++ b/indra/llmessage/lldatapacker.cpp @@ -172,6 +172,71 @@ BOOL LLDataPacker::unpackFixed(F32 &value, const char *name, return success; } +BOOL LLDataPacker::unpackU16s(U16 *values, S32 count, const char *name) +{ + for (S32 idx = 0; idx < count; ++idx) + { + if (!unpackU16(values[idx], name)) + { + LL_WARNS("DATAPACKER") << "Buffer overflow reading Unsigned 16s \"" << name << "\" at index " << idx << "!" << LL_ENDL; + return FALSE; + } + } + return TRUE; +} + +BOOL LLDataPacker::unpackS16s(S16 *values, S32 count, const char *name) +{ + for (S32 idx = 0; idx < count; ++idx) + { + if (!unpackS16(values[idx], name)) + { + LL_WARNS("DATAPACKER") << "Buffer overflow reading Signed 16s \"" << name << "\" at index " << idx << "!" << LL_ENDL; + return FALSE; + } + } + return TRUE; +} + +BOOL LLDataPacker::unpackF32s(F32 *values, S32 count, const char *name) +{ + for (S32 idx = 0; idx < count; ++idx) + { + if (!unpackF32(values[idx], name)) + { + LL_WARNS("DATAPACKER") << "Buffer overflow reading Float 32s \"" << name << "\" at index " << idx << "!" << LL_ENDL; + return FALSE; + } + } + return TRUE; +} + +BOOL LLDataPacker::unpackColor4Us(LLColor4U *values, S32 count, const char *name) +{ + for (S32 idx = 0; idx < count; ++idx) + { + if (!unpackColor4U(values[idx], name)) + { + LL_WARNS("DATAPACKER") << "Buffer overflow reading Float 32s \"" << name << "\" at index " << idx << "!" << LL_ENDL; + return FALSE; + } + } + return TRUE; +} + +BOOL LLDataPacker::unpackUUIDs(LLUUID *values, S32 count, const char *name) +{ + for (S32 idx = 0; idx < count; ++idx) + { + if (!unpackUUID(values[idx], name)) + { + LL_WARNS("DATAPACKER") << "Buffer overflow reading UUIDs \"" << name << "\" at index " << idx << "!" << LL_ENDL; + return FALSE; + } + } + return TRUE; +} + //--------------------------------------------------------------------------- // LLDataPackerBinaryBuffer implementation //--------------------------------------------------------------------------- @@ -339,6 +404,29 @@ BOOL LLDataPackerBinaryBuffer::unpackU16(U16 &value, const char *name) return TRUE; } +BOOL LLDataPackerBinaryBuffer::packS16(const S16 value, const char *name) +{ + BOOL success = verifyLength(sizeof(S16), name); + + if (mWriteEnabled && success) + { + htolememcpy(mCurBufferp, &value, MVT_S16, 2); + } + mCurBufferp += 2; + return success; +} + +BOOL LLDataPackerBinaryBuffer::unpackS16(S16 &value, const char *name) +{ + BOOL success = verifyLength(sizeof(S16), name); + + if (success) + { + htolememcpy(&value, mCurBufferp, MVT_S16, 2); + } + mCurBufferp += 2; + return success; +} BOOL LLDataPackerBinaryBuffer::packU32(const U32 value, const char *name) { @@ -939,6 +1027,52 @@ BOOL LLDataPackerAsciiBuffer::unpackU16(U16 &value, const char *name) return success; } +BOOL LLDataPackerAsciiBuffer::packS16(const S16 value, const char *name) +{ + BOOL success = TRUE; + writeIndentedName(name); + int numCopied = 0; + if (mWriteEnabled) + { + numCopied = snprintf(mCurBufferp, getBufferSize() - getCurrentSize(), "%d\n", value); /* Flawfinder: ignore */ + } + else + { + numCopied = snprintf(DUMMY_BUFFER, sizeof(DUMMY_BUFFER), "%d\n", value); /* Flawfinder: ignore */ + } + + // snprintf returns number of bytes that would have been written + // had the output not being truncated. In that case, it will + // return either -1 or value >= passed in size value . So a check needs to be added + // to detect truncation, and if there is any, only account for the + // actual number of bytes written..and not what could have been + // written. + if(numCopied < 0 || numCopied > getBufferSize() - getCurrentSize()) + { + numCopied = getBufferSize() - getCurrentSize(); + LL_WARNS() << "LLDataPackerAsciiBuffer::packS16: val truncated: " << LL_ENDL; + } + + mCurBufferp += numCopied; + + return success; +} + + +BOOL LLDataPackerAsciiBuffer::unpackS16(S16 &value, const char *name) +{ + BOOL success = TRUE; + char valuestr[DP_BUFSIZE]; /* Flawfinder: ignore */ + if (!getValueStr(name, valuestr, DP_BUFSIZE)) + { + return FALSE; + } + + S32 in_val; + sscanf(valuestr, "%d", &in_val); + value = in_val; + return success; +} BOOL LLDataPackerAsciiBuffer::packU32(const U32 value, const char *name) { @@ -1642,6 +1776,36 @@ BOOL LLDataPackerAsciiFile::unpackU16(U16 &value, const char *name) return success; } +BOOL LLDataPackerAsciiFile::packS16(const S16 value, const char *name) +{ + BOOL success = TRUE; + writeIndentedName(name); + if (mFP) + { + fprintf(mFP, "%d\n", value); + } + else if (mOutputStream) + { + *mOutputStream << "" << value << "\n"; + } + return success; +} + + +BOOL LLDataPackerAsciiFile::unpackS16(S16 &value, const char *name) +{ + BOOL success = TRUE; + char valuestr[DP_BUFSIZE]; /*Flawfinder: ignore */ + if (!getValueStr(name, valuestr, DP_BUFSIZE)) + { + return FALSE; + } + + S32 in_val; + sscanf(valuestr, "%d", &in_val); + value = in_val; + return success; +} BOOL LLDataPackerAsciiFile::packU32(const U32 value, const char *name) { diff --git a/indra/llmessage/lldatapacker.h b/indra/llmessage/lldatapacker.h index d06f4ccda4..721aa5eb55 100644 --- a/indra/llmessage/lldatapacker.h +++ b/indra/llmessage/lldatapacker.h @@ -62,6 +62,11 @@ public: virtual BOOL packU16(const U16 value, const char *name) = 0; virtual BOOL unpackU16(U16 &value, const char *name) = 0; + BOOL unpackU16s(U16 *value, S32 count, const char *name); + + virtual BOOL packS16(const S16 value, const char *name) = 0; + virtual BOOL unpackS16(S16 &value, const char *name) = 0; + BOOL unpackS16s(S16 *value, S32 count, const char *name); virtual BOOL packU32(const U32 value, const char *name) = 0; virtual BOOL unpackU32(U32 &value, const char *name) = 0; @@ -71,6 +76,7 @@ public: virtual BOOL packF32(const F32 value, const char *name) = 0; virtual BOOL unpackF32(F32 &value, const char *name) = 0; + BOOL unpackF32s(F32 *values, S32 count, const char *name); // Packs a float into an integer, using the given size // and picks the right U* data type to pack into. @@ -84,6 +90,7 @@ public: virtual BOOL packColor4U(const LLColor4U &value, const char *name) = 0; virtual BOOL unpackColor4U(LLColor4U &value, const char *name) = 0; + BOOL unpackColor4Us(LLColor4U *values, S32 count, const char *name); virtual BOOL packVector2(const LLVector2 &value, const char *name) = 0; virtual BOOL unpackVector2(LLVector2 &value, const char *name) = 0; @@ -96,6 +103,7 @@ public: virtual BOOL packUUID(const LLUUID &value, const char *name) = 0; virtual BOOL unpackUUID(LLUUID &value, const char *name) = 0; + BOOL unpackUUIDs(LLUUID *values, S32 count, const char *name); U32 getPassFlags() const { return mPassFlags; } void setPassFlags(U32 flags) { mPassFlags = flags; } protected: @@ -141,6 +149,9 @@ public: /*virtual*/ BOOL packU16(const U16 value, const char *name); /*virtual*/ BOOL unpackU16(U16 &value, const char *name); + /*virtual*/ BOOL packS16(const S16 value, const char *name); + /*virtual*/ BOOL unpackS16(S16 &value, const char *name); + /*virtual*/ BOOL packU32(const U32 value, const char *name); /*virtual*/ BOOL unpackU32(U32 &value, const char *name); @@ -258,6 +269,9 @@ public: /*virtual*/ BOOL packU16(const U16 value, const char *name); /*virtual*/ BOOL unpackU16(U16 &value, const char *name); + /*virtual*/ BOOL packS16(const S16 value, const char *name); + /*virtual*/ BOOL unpackS16(S16 &value, const char *name); + /*virtual*/ BOOL packU32(const U32 value, const char *name); /*virtual*/ BOOL unpackU32(U32 &value, const char *name); @@ -386,6 +400,9 @@ public: /*virtual*/ BOOL packU16(const U16 value, const char *name); /*virtual*/ BOOL unpackU16(U16 &value, const char *name); + /*virtual*/ BOOL packS16(const S16 value, const char *name); + /*virtual*/ BOOL unpackS16(S16 &value, const char *name); + /*virtual*/ BOOL packU32(const U32 value, const char *name); /*virtual*/ BOOL unpackU32(U32 &value, const char *name); diff --git a/indra/llmessage/message.cpp b/indra/llmessage/message.cpp index 9b5050af41..a9d03c425c 100644 --- a/indra/llmessage/message.cpp +++ b/indra/llmessage/message.cpp @@ -46,6 +46,7 @@ #include "apr_poll.h" // linden library headers +#include "llapp.h" #include "indra_constants.h" #include "lldir.h" #include "llerror.h" diff --git a/indra/llmessage/message_prehash.cpp b/indra/llmessage/message_prehash.cpp index 18a86cf8cf..aef7327b28 100644 --- a/indra/llmessage/message_prehash.cpp +++ b/indra/llmessage/message_prehash.cpp @@ -281,6 +281,13 @@ char const* const _PREHASH_PricePerMeter = LLMessageStringTable::getInstance()-> char const* const _PREHASH_RegionFlags = LLMessageStringTable::getInstance()->getString("RegionFlags"); char const* const _PREHASH_RegionFlagsExtended = LLMessageStringTable::getInstance()->getString("RegionFlagsExtended"); char const* const _PREHASH_RegionProtocols = LLMessageStringTable::getInstance()->getString("RegionProtocols"); +char const* const _PREHASH_ChatWhisperRange = LLMessageStringTable::getInstance()->getString("ChatWhisperRange"); +char const* const _PREHASH_ChatNormalRange = LLMessageStringTable::getInstance()->getString("ChatNormalRange"); +char const* const _PREHASH_ChatShoutRange = LLMessageStringTable::getInstance()->getString("ChatShoutRange"); +char const* const _PREHASH_ChatWhisperOffset = LLMessageStringTable::getInstance()->getString("ChatWhisperOffset"); +char const* const _PREHASH_ChatNormalOffset = LLMessageStringTable::getInstance()->getString("ChatNormalOffset"); +char const* const _PREHASH_ChatShoutOffset = LLMessageStringTable::getInstance()->getString("ChatShoutOffset"); +char const* const _PREHASH_ChatFlags = LLMessageStringTable::getInstance()->getString("ChatFlags"); char const* const _PREHASH_VoteResult = LLMessageStringTable::getInstance()->getString("VoteResult"); char const* const _PREHASH_ParcelDirFeeEstimate = LLMessageStringTable::getInstance()->getString("ParcelDirFeeEstimate"); char const* const _PREHASH_ModifyBlock = LLMessageStringTable::getInstance()->getString("ModifyBlock"); @@ -309,6 +316,7 @@ char const* const _PREHASH_DuplicateFlags = LLMessageStringTable::getInstance()- char const* const _PREHASH_RegionInfo2 = LLMessageStringTable::getInstance()->getString("RegionInfo2"); char const* const _PREHASH_RegionInfo3 = LLMessageStringTable::getInstance()->getString("RegionInfo3"); char const* const _PREHASH_RegionInfo4 = LLMessageStringTable::getInstance()->getString("RegionInfo4"); +char const* const _PREHASH_RegionInfo5 = LLMessageStringTable::getInstance()->getString("RegionInfo5"); char const* const _PREHASH_TextColor = LLMessageStringTable::getInstance()->getString("TextColor"); char const* const _PREHASH_SlaveID = LLMessageStringTable::getInstance()->getString("SlaveID"); char const* const _PREHASH_Charter = LLMessageStringTable::getInstance()->getString("Charter"); diff --git a/indra/llmessage/message_prehash.h b/indra/llmessage/message_prehash.h index 911b1a8ba0..6be4a25aa8 100644 --- a/indra/llmessage/message_prehash.h +++ b/indra/llmessage/message_prehash.h @@ -281,6 +281,13 @@ extern char const* const _PREHASH_PricePerMeter; extern char const* const _PREHASH_RegionFlags; extern char const* const _PREHASH_RegionFlagsExtended; extern char const* const _PREHASH_RegionProtocols; +extern char const* const _PREHASH_ChatWhisperRange; +extern char const* const _PREHASH_ChatNormalRange; +extern char const* const _PREHASH_ChatShoutRange; +extern char const* const _PREHASH_ChatWhisperOffset; +extern char const* const _PREHASH_ChatNormalOffset; +extern char const* const _PREHASH_ChatShoutOffset; +extern char const* const _PREHASH_ChatFlags; extern char const* const _PREHASH_VoteResult; extern char const* const _PREHASH_ParcelDirFeeEstimate; extern char const* const _PREHASH_ModifyBlock; @@ -309,6 +316,7 @@ extern char const* const _PREHASH_DuplicateFlags; extern char const* const _PREHASH_RegionInfo2; extern char const* const _PREHASH_RegionInfo3; extern char const* const _PREHASH_RegionInfo4; +extern char const* const _PREHASH_RegionInfo5; extern char const* const _PREHASH_TextColor; extern char const* const _PREHASH_SlaveID; extern char const* const _PREHASH_Charter; diff --git a/indra/llmessage/sound_ids.cpp b/indra/llmessage/sound_ids.cpp index 654efed127..2b8a0807c6 100644 --- a/indra/llmessage/sound_ids.cpp +++ b/indra/llmessage/sound_ids.cpp @@ -285,11 +285,6 @@ const LLUUID SND_STONE_DIRT_04 ("c8091652-e04b-4a11-84ba-15dba06e7a1b"); const LLUUID SND_STONE_STONE_02 ("ba4ef5ac-7435-4240-b826-c24ba8fa5a78"); const LLUUID SND_STONE_STONE_04 ("ea296329-0f09-4993-af1b-e6784bab1dc9"); -// NaCl - Antispam Registry. The following sounds will be ignored for purposes of spam protection. They have been gathered from wiki documentation of frequent official sounds. -const std::string COLLISION_SOUNDS[] ={"dce5fdd4-afe4-4ea1-822f-dd52cac46b08","51011582-fbca-4580-ae9e-1a5593f094ec","68d62208-e257-4d0c-bbe2-20c9ea9760bb","75872e8c-bc39-451b-9b0b-042d7ba36cba","6a45ba0b-5775-4ea8-8513-26008a17f873","992a6d1b-8c77-40e0-9495-4098ce539694","2de4da5a-faf8-46be-bac6-c4d74f1e5767","6e3fb0f7-6d9c-42ca-b86b-1122ff562d7d","14209133-4961-4acc-9649-53fc38ee1667","bc4a4348-cfcc-4e5e-908e-8a52a8915fe6","9e5c1297-6eed-40c0-825a-d9bcd86e3193","e534761c-1894-4b61-b20c-658a6fb68157","8761f73f-6cf9-4186-8aaa-0948ed002db1","874a26fd-142f-4173-8c5b-890cd846c74d","0e24a717-b97e-4b77-9c94-b59a5a88b2da","75cf3ade-9a5b-4c4d-bb35-f9799bda7fb2","153c8bf7-fb89-4d89-b263-47e58b1b4774","55c3e0ce-275a-46fa-82ff-e0465f5e8703","24babf58-7156-4841-9a3f-761bdbb8e237","aca261d8-e145-4610-9e20-9eff990f2c12","0642fba6-5dcf-4d62-8e7b-94dbb529d117","25a863e8-dc42-4e8a-a357-e76422ace9b5","9538f37c-456e-4047-81be-6435045608d4","8c0f84c3-9afd-4396-b5f5-9bca2c911c20","be582e5d-b123-41a2-a150-454c39e961c8","c70141d4-ba06-41ea-bcbc-35ea81cb8335","7d1826f4-24c4-4aac-8c2e-eff45df37783","063c97d3-033a-4e9b-98d8-05c8074922cb","00000000-0000-0000-0000-000000000120"}; -const int COLLISION_SOUNDS_SIZE=29; -// NaCl End - // extra guids diff --git a/indra/llmessage/sound_ids.h b/indra/llmessage/sound_ids.h index 74bdc898cd..6a2e343ad3 100644 --- a/indra/llmessage/sound_ids.h +++ b/indra/llmessage/sound_ids.h @@ -286,9 +286,4 @@ extern const LLUUID SND_STONE_DIRT_04; extern const LLUUID SND_STONE_STONE_02; extern const LLUUID SND_STONE_STONE_04; -// NaCl - Antispam Registry -extern const std::string COLLISION_SOUNDS[]; -extern const int COLLISION_SOUNDS_SIZE; -// NaCl End - #endif diff --git a/indra/llplugin/llpluginclassmedia.cpp b/indra/llplugin/llpluginclassmedia.cpp index 1a839ed7e7..d1310122ad 100644 --- a/indra/llplugin/llpluginclassmedia.cpp +++ b/indra/llplugin/llpluginclassmedia.cpp @@ -696,6 +696,66 @@ bool LLPluginClassMedia::textInput(const std::string &text, MASK modifiers, LLSD return true; } +// This function injects a previously stored OpenID cookie into +// each new media instance - see SL-15867 for details. It appears +// that the way we use the cache, shared between multiple CEF +// instances means that sometimes the OpenID cookie cannot be read +// even though it appears to be there. The long term solution to +// this is to create a separate cache directory for each instance +// but that has its own set of problems. This short term approach +// "forces" each new media instance to have a copy of the cookie +// so that a page that needs it - e.g. Profiles - finds it and +// can log in successfully. +void LLPluginClassMedia::injectOpenIDCookie() +{ + // can be called before we know who the user is at login + // and there is no OpenID cookie at that point so no + // need to try to set it (these values will all be empty) + if (sOIDcookieName.length() && sOIDcookieValue.length()) + { + setCookie(sOIDcookieUrl, sOIDcookieName, + sOIDcookieValue, sOIDcookieHost, sOIDcookiePath, sOIDcookieHttpOnly, sOIDcookieSecure); + } +} + +// We store each component of the OpenI cookie individuality here +// because previously, there was some significant parsing to +// break up the raw string into these components and we do not +// want to have to do that again here. Stored as statics because +// we want to share their value between all instances of this +// class - the ones that receive it at login and any others +// that open afterwards (e.g. the Profiles floater) +std::string LLPluginClassMedia::sOIDcookieUrl = std::string(); +std::string LLPluginClassMedia::sOIDcookieName = std::string(); +std::string LLPluginClassMedia::sOIDcookieValue = std::string(); +std::string LLPluginClassMedia::sOIDcookieHost = std::string(); +std::string LLPluginClassMedia::sOIDcookiePath = std::string(); +bool LLPluginClassMedia::sOIDcookieHttpOnly = false; +bool LLPluginClassMedia::sOIDcookieSecure = false; + +// Once we receive the OpenID cookie, it is parsed/processed +// in llViewerMedia::parseRawCookie() and then the component +// values are stored here so that next time a new media +// instance is created, we can use injectOpenIDCookie() +// to "insist" that the cookie store remember its value. +// One might ask why we need to go via LLViewerMedia (which +// makes this call) - this is because the raw cookie arrives +// here in this file but undergoes non-trivial processing +// in LLViewerMedia. +void LLPluginClassMedia::storeOpenIDCookie(const std::string url, + const std::string name, const std::string value, + const std::string host, const std::string path, + bool httponly, bool secure) +{ + sOIDcookieUrl = url; + sOIDcookieName = name; + sOIDcookieValue = value; + sOIDcookieHost = host; + sOIDcookiePath = path; + sOIDcookieHttpOnly = httponly; + sOIDcookieSecure = secure; +} + void LLPluginClassMedia::setCookie(std::string uri, std::string name, std::string value, std::string domain, std::string path, bool httponly, bool secure) { LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "set_cookie"); @@ -720,6 +780,15 @@ void LLPluginClassMedia::loadURI(const std::string &uri) sendMessage(message); } +void LLPluginClassMedia::executeJavaScript(const std::string &code) +{ + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "execute_javascript"); + + message.setValue("code", code); + + sendMessage(message); +} + const char* LLPluginClassMedia::priorityToString(EPriority priority) { const char* result = "UNKNOWN"; @@ -897,6 +966,19 @@ void LLPluginClassMedia::setJavascriptEnabled(const bool enabled) sendMessage(message); } +void LLPluginClassMedia::setWebSecurityDisabled(const bool disabled) +{ + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "web_security_disabled"); + message.setValueBoolean("disabled", disabled); + sendMessage(message); +} + +void LLPluginClassMedia::setFileAccessFromFileUrlsEnabled(const bool enabled) +{ + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "file_access_from_file_urls"); + message.setValueBoolean("enabled", enabled); + sendMessage(message); +} void LLPluginClassMedia::enableMediaPluginDebugging( bool enable ) { diff --git a/indra/llplugin/llpluginclassmedia.h b/indra/llplugin/llpluginclassmedia.h index ed9de254fe..f9fdb31579 100644 --- a/indra/llplugin/llpluginclassmedia.h +++ b/indra/llplugin/llpluginclassmedia.h @@ -135,10 +135,26 @@ public: // Text may be unicode (utf8 encoded) bool textInput(const std::string &text, MASK modifiers, LLSD native_key_data); + static std::string sOIDcookieUrl; + static std::string sOIDcookieName; + static std::string sOIDcookieValue; + static std::string sOIDcookieHost; + static std::string sOIDcookiePath; + static bool sOIDcookieHttpOnly; + static bool sOIDcookieSecure; + void storeOpenIDCookie(const std::string url, + const std::string name, const std::string value, + const std::string host, const std::string path, + bool httponly, bool secure); + + void injectOpenIDCookie(); + void setCookie(std::string uri, std::string name, std::string value, std::string domain, std::string path, bool httponly, bool secure); void loadURI(const std::string &uri); + void executeJavaScript(const std::string &code); + // "Loading" means uninitialized or any state prior to fully running (processing commands) bool isPluginLoading(void) { return mPlugin?mPlugin->isLoading():false; }; @@ -199,6 +215,8 @@ public: void setLanguageCode(const std::string &language_code); void setPluginsEnabled(const bool enabled); void setJavascriptEnabled(const bool enabled); + void setWebSecurityDisabled(const bool disabled); + void setFileAccessFromFileUrlsEnabled(const bool enabled); void setTarget(const std::string &target); /////////////////////////////////// diff --git a/indra/llplugin/llpluginprocessparent.cpp b/indra/llplugin/llpluginprocessparent.cpp index 6c6f819415..7088cf4d4b 100644 --- a/indra/llplugin/llpluginprocessparent.cpp +++ b/indra/llplugin/llpluginprocessparent.cpp @@ -28,6 +28,7 @@ #include "linden_common.h" +#include "llapp.h" #include "llpluginprocessparent.h" #include "llpluginmessagepipe.h" #include "llpluginmessageclasses.h" diff --git a/indra/llprimitive/llmaterialtable.cpp b/indra/llprimitive/llmaterialtable.cpp index 37c718b4c6..58b2d00d44 100644 --- a/indra/llprimitive/llmaterialtable.cpp +++ b/indra/llprimitive/llmaterialtable.cpp @@ -559,6 +559,23 @@ LLUUID LLMaterialTable::getCollisionSoundUUID(U8 mcode, U8 mcode2) } } +bool LLMaterialTable::isCollisionSound(const LLUUID &uuid) +{ + for (U8 i = 0; i < LL_MCODE_END; i++) + { + for (U8 j = 0; j < LL_MCODE_END; j++) + { + i &= LL_MCODE_MASK; + j &= LL_MCODE_MASK; + if (mCollisionSoundMatrix[i * LL_MCODE_END + j] == uuid) + { + return true; + } + } + } + return false; +} + LLUUID LLMaterialTable::getSlidingSoundUUID(U8 mcode, U8 mcode2) { mcode &= LL_MCODE_MASK; diff --git a/indra/llprimitive/llmaterialtable.h b/indra/llprimitive/llmaterialtable.h index a17e0103ff..0cf5e626ef 100644 --- a/indra/llprimitive/llmaterialtable.h +++ b/indra/llprimitive/llmaterialtable.h @@ -128,6 +128,8 @@ public: F32 getDamageMod(U8 mcode); F32 getEPMod(U8 mcode); + bool isCollisionSound(const LLUUID &uuid); + LLUUID getCollisionSoundUUID(U8 mcode, U8 mcode2); LLUUID getSlidingSoundUUID(U8 mcode, U8 mcode2); LLUUID getRollingSoundUUID(U8 mcode, U8 mcode2); diff --git a/indra/llprimitive/llmediaentry.cpp b/indra/llprimitive/llmediaentry.cpp index 02aba2bd83..53e9555c6a 100644 --- a/indra/llprimitive/llmediaentry.cpp +++ b/indra/llprimitive/llmediaentry.cpp @@ -27,8 +27,7 @@ #include "linden_common.h" #include "llmediaentry.h" #include "lllslconstants.h" - -#include +#include "llregex.h" // LLSD key defines // DO NOT REORDER OR REMOVE THESE! @@ -456,7 +455,7 @@ static bool pattern_match(const std::string &candidate_str, const std::string &p // case-insensitive matching: boost::regex regexp(expression, boost::regex::perl|boost::regex::icase); - return boost::regex_match(candidate_str, regexp); + return ll_regex_match(candidate_str, regexp); } bool LLMediaEntry::checkCandidateUrl(const std::string& url) const diff --git a/indra/llprimitive/llprimitive.cpp b/indra/llprimitive/llprimitive.cpp index 86612e0e6d..cf47fdfdd4 100644 --- a/indra/llprimitive/llprimitive.cpp +++ b/indra/llprimitive/llprimitive.cpp @@ -122,6 +122,35 @@ const char *SCULPT_DEFAULT_TEXTURE = "be293869-d0d9-0a69-5989-ad27f1946fd4"; // // can't be divided by 2. See DEV-19108 const F32 TEXTURE_ROTATION_PACK_FACTOR = ((F32) 0x08000); +struct material_id_type // originally from llrendermaterialtable +{ + material_id_type() + { + memset((void*)m_value, 0, sizeof(m_value)); + } + + bool operator==(const material_id_type& other) const + { + return (memcmp(m_value, other.m_value, sizeof(m_value)) == 0); + } + + bool operator!=(const material_id_type& other) const + { + return !operator==(other); + } + + bool isNull() const + { + return (memcmp(m_value, s_null_id, sizeof(m_value)) == 0); + } + + U8 m_value[MATERIAL_ID_SIZE]; // server side this is MD5RAW_BYTES + + static const U8 s_null_id[MATERIAL_ID_SIZE]; +}; + +const U8 material_id_type::s_null_id[] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }; + //static // LEGACY: by default we use the LLVolumeMgr::gVolumeMgr global // TODO -- eliminate this global from the codebase! @@ -1092,50 +1121,85 @@ S32 LLPrimitive::packTEField(U8 *cur_ptr, U8 *data_ptr, U8 data_size, U8 last_fa return (S32)(cur_ptr - start_loc); } -S32 LLPrimitive::unpackTEField(U8 *cur_ptr, U8 *buffer_end, U8 *data_ptr, U8 data_size, U8 face_count, EMsgVariableType type) +namespace { - U8 *start_loc = cur_ptr; - U64 i; - htolememcpy(data_ptr,cur_ptr, type,data_size); - cur_ptr += data_size; + template< typename T > + bool unpack_TEField(T dest[], U8 dest_count, U8 * &source, U8 *source_end, EMsgVariableType type) + { + const size_t size(sizeof(T)); - for (i = 1; i < face_count; i++) - { - // Already unswizzled, don't need to unswizzle it again! - memcpy(data_ptr+(i*data_size),data_ptr,data_size); /* Flawfinder: ignore */ - } - - while ((cur_ptr < buffer_end) && (*cur_ptr != 0)) - { - LL_DEBUGS("TEFieldDecode") << "TE exception" << LL_ENDL; - i = 0; - while (*cur_ptr & 0x80) - { - i |= ((*cur_ptr++) & 0x7F); - i = i << 7; - } + LL_DEBUGS("TEXTUREENTRY") << "Request to read items of size " << size << " with swizzle " << type << " froum buffer sized " << (source_end - source) << LL_ENDL; - i |= *cur_ptr++; + if ((source + size + 1) > source_end) + { + // we add 1 above to take into account the byte that we know must follow the value. + LL_WARNS("TEXTUREENTRY") << "Buffer exhausted! Requires " << size << " + 1 bytes for default, " << (source_end - source) << " bytes remaning." << LL_ENDL; + source = source_end; + return false; + } - for (S32 j = 0; j < face_count; j++) - { - if (i & 0x01) - { - htolememcpy(data_ptr+(j*data_size),cur_ptr,type,data_size); - LL_DEBUGS("TEFieldDecode") << "Assigning " ; - char foo[64]; - sprintf(foo,"%x %x",*(data_ptr+(j*data_size)), *(data_ptr+(j*data_size)+1)); - LL_CONT << foo << " to face " << j << LL_ENDL; - } - i = i >> 1; - } - cur_ptr += data_size; - } - llassert(cur_ptr <= buffer_end); // buffer underrun - return (S32)(cur_ptr - start_loc); + // Extract the default value and fill the array. + htolememcpy(dest, source, type, size); + source += size; + for (S32 idx = 1; idx < dest_count; ++idx) + { + dest[idx] = dest[0]; + } + + while (source < source_end) + { + U64 index_flags(0); + U8 sbit(0); + + // Unpack the variable length bitfield. Each bit represents whether the following + // value will be placed at the corresponding array index. + do + { + if (source >= source_end) + { + LL_WARNS("TEXTUREENTRY") << "Buffer exhausted! Reading index flags." << LL_ENDL; + source = source_end; + return false; + } + + sbit = *source++; + index_flags <<= 7; // original code had this after? + index_flags |= (sbit & 0x7F); + } while (sbit & 0x80); + + if (!index_flags) + { // We've hit the terminating 0 byte. + break; + } + + if ((source + size + 1) > source_end) + { + // we add 1 above to take into account the byte that we know must follow the value. + LL_WARNS("TEXTUREENTRY") << "Buffer exhausted! Requires " << size << " + 1 bytes for default, " << (source_end - source) << " bytes remaning." << LL_ENDL; + source = source_end; + return false; + } + + // get the value for the indexs. + T value; + htolememcpy(&value, source, type, size); + source += size; + + for (S32 idx = 0; idx < dest_count; idx++) + { + if (index_flags & 1ULL << idx) + { + dest[idx] = value; + } + } + + } + return true; + } } + // Pack information about all texture entries into container: // { TextureEntry Variable 2 } // Includes information about image ID, color, scale S,T, offset S,T and rotation @@ -1312,9 +1376,9 @@ BOOL LLPrimitive::packTEMessage(LLDataPacker &dp) const S32 LLPrimitive::parseTEMessage(LLMessageSystem* mesgsys, char const* block_name, const S32 block_num, LLTEContents& tec) { S32 retval = 0; - // temp buffer for material ID processing - // data will end up in tec.material_id[] - U8 material_data[LLTEContents::MAX_TES*16]; + // temp buffer for material ID processing + // data will end up in tec.material_id[] + material_id_type material_data[LLTEContents::MAX_TES]; if (block_num < 0) { @@ -1330,54 +1394,49 @@ S32 LLPrimitive::parseTEMessage(LLMessageSystem* mesgsys, char const* block_name tec.face_count = 0; return retval; } + else if (tec.size >= LLTEContents::MAX_TE_BUFFER) + { + LL_WARNS("TEXTUREENTRY") << "Excessive buffer size detected in Texture Entry! Truncating." << LL_ENDL; + tec.size = LLTEContents::MAX_TE_BUFFER - 1; + } - if (block_num < 0) - { - mesgsys->getBinaryDataFast(block_name, _PREHASH_TextureEntry, tec.packed_buffer, 0, 0, LLTEContents::MAX_TE_BUFFER); - } - else - { - mesgsys->getBinaryDataFast(block_name, _PREHASH_TextureEntry, tec.packed_buffer, 0, block_num, LLTEContents::MAX_TE_BUFFER); - } + // if block_num < 0 ask for block 0 + mesgsys->getBinaryDataFast(block_name, _PREHASH_TextureEntry, tec.packed_buffer, 0, std::max(block_num, 0), LLTEContents::MAX_TE_BUFFER - 1); - + // The last field is not zero terminated. + // Rather than special case the upack functions. Just make it 0x00 terminated. + tec.packed_buffer[tec.size] = 0x00; + ++tec.size; tec.face_count = llmin((U32)getNumTEs(),(U32)LLTEContents::MAX_TES); U8 *cur_ptr = tec.packed_buffer; - cur_ptr += unpackTEField(cur_ptr, tec.packed_buffer+tec.size, (U8 *)tec.image_data, 16, tec.face_count, MVT_LLUUID); - cur_ptr++; - cur_ptr += unpackTEField(cur_ptr, tec.packed_buffer+tec.size, (U8 *)tec.colors, 4, tec.face_count, MVT_U8); - cur_ptr++; - cur_ptr += unpackTEField(cur_ptr, tec.packed_buffer+tec.size, (U8 *)tec.scale_s, 4, tec.face_count, MVT_F32); - cur_ptr++; - cur_ptr += unpackTEField(cur_ptr, tec.packed_buffer+tec.size, (U8 *)tec.scale_t, 4, tec.face_count, MVT_F32); - cur_ptr++; - cur_ptr += unpackTEField(cur_ptr, tec.packed_buffer+tec.size, (U8 *)tec.offset_s, 2, tec.face_count, MVT_S16Array); - cur_ptr++; - cur_ptr += unpackTEField(cur_ptr, tec.packed_buffer+tec.size, (U8 *)tec.offset_t, 2, tec.face_count, MVT_S16Array); - cur_ptr++; - cur_ptr += unpackTEField(cur_ptr, tec.packed_buffer+tec.size, (U8 *)tec.image_rot, 2, tec.face_count, MVT_S16Array); - cur_ptr++; - cur_ptr += unpackTEField(cur_ptr, tec.packed_buffer+tec.size, (U8 *)tec.bump, 1, tec.face_count, MVT_U8); - cur_ptr++; - cur_ptr += unpackTEField(cur_ptr, tec.packed_buffer+tec.size, (U8 *)tec.media_flags, 1, tec.face_count, MVT_U8); - cur_ptr++; - cur_ptr += unpackTEField(cur_ptr, tec.packed_buffer+tec.size, (U8 *)tec.glow, 1, tec.face_count, MVT_U8); + LL_DEBUGS("TEXTUREENTRY") << "Texture Entry with buffere sized: " << tec.size << LL_ENDL; + U8 *buffer_end = tec.packed_buffer + tec.size; - if (cur_ptr < tec.packed_buffer + tec.size) + if (!( unpack_TEField(tec.image_data, tec.face_count, cur_ptr, buffer_end, MVT_LLUUID) && + unpack_TEField(tec.colors, tec.face_count, cur_ptr, buffer_end, MVT_U8) && + unpack_TEField(tec.scale_s, tec.face_count, cur_ptr, buffer_end, MVT_F32) && + unpack_TEField(tec.scale_t, tec.face_count, cur_ptr, buffer_end, MVT_F32) && + unpack_TEField(tec.offset_s, tec.face_count, cur_ptr, buffer_end, MVT_S16) && + unpack_TEField(tec.offset_t, tec.face_count, cur_ptr, buffer_end, MVT_S16) && + unpack_TEField(tec.image_rot, tec.face_count, cur_ptr, buffer_end, MVT_S16) && + unpack_TEField(tec.bump, tec.face_count, cur_ptr, buffer_end, MVT_U8) && + unpack_TEField(tec.media_flags, tec.face_count, cur_ptr, buffer_end, MVT_U8) && + unpack_TEField(tec.glow, tec.face_count, cur_ptr, buffer_end, MVT_U8))) + { + LL_WARNS("TEXTUREENTRY") << "Failure parsing Texture Entry Message due to malformed TE Field! Dropping changes on the floor. " << LL_ENDL; + return 0; + } + + if (cur_ptr >= buffer_end || !unpack_TEField(material_data, tec.face_count, cur_ptr, buffer_end, MVT_LLUUID)) { - cur_ptr++; - cur_ptr += unpackTEField(cur_ptr, tec.packed_buffer+tec.size, (U8 *)material_data, 16, tec.face_count, MVT_LLUUID); - } - else - { - memset(material_data, 0, sizeof(material_data)); + memset((void*)material_data, 0, sizeof(material_data)); } for (U32 i = 0; i < tec.face_count; i++) { - tec.material_ids[i].set(&material_data[i * 16]); + tec.material_ids[i].set(&(material_data[i])); } retval = 1; @@ -1389,7 +1448,6 @@ S32 LLPrimitive::applyParsedTEMessage(LLTEContents& tec) S32 retval = 0; LLColor4 color; - LLColor4U coloru; for (U32 i = 0; i < tec.face_count; i++) { LLUUID& req_id = ((LLUUID*)tec.image_data)[i]; @@ -1402,20 +1460,15 @@ S32 LLPrimitive::applyParsedTEMessage(LLTEContents& tec) retval |= setTEGlow(i, (F32)tec.glow[i] / (F32)0xFF); retval |= setTEMaterialID(i, tec.material_ids[i]); - coloru = LLColor4U(tec.colors + 4*i); - // Note: This is an optimization to send common colors (1.f, 1.f, 1.f, 1.f) // as all zeros. However, the subtraction and addition must be done in unsigned // byte space, not in float space, otherwise off-by-one errors occur. JC - color.mV[VRED] = F32(255 - coloru.mV[VRED]) / 255.f; - color.mV[VGREEN] = F32(255 - coloru.mV[VGREEN]) / 255.f; - color.mV[VBLUE] = F32(255 - coloru.mV[VBLUE]) / 255.f; - color.mV[VALPHA] = F32(255 - coloru.mV[VALPHA]) / 255.f; + color.mV[VRED] = F32(255 - tec.colors[i].mV[VRED]) / 255.f; + color.mV[VGREEN] = F32(255 - tec.colors[i].mV[VGREEN]) / 255.f; + color.mV[VBLUE] = F32(255 - tec.colors[i].mV[VBLUE]) / 255.f; + color.mV[VALPHA] = F32(255 - tec.colors[i].mV[VALPHA]) / 255.f; retval |= setTEColor(i, color); - - - } return retval; @@ -1437,24 +1490,32 @@ S32 LLPrimitive::unpackTEMessage(LLDataPacker &dp) const U32 MAX_TES = 45; // Avoid construction of 32 UUIDs per call - static LLUUID image_ids[MAX_TES]; static LLMaterialID material_ids[MAX_TES]; - U8 image_data[MAX_TES*16]; - U8 colors[MAX_TES*4]; - F32 scale_s[MAX_TES]; - F32 scale_t[MAX_TES]; - S16 offset_s[MAX_TES]; - S16 offset_t[MAX_TES]; - S16 image_rot[MAX_TES]; - U8 bump[MAX_TES]; - U8 media_flags[MAX_TES]; - U8 glow[MAX_TES]; - U8 material_data[MAX_TES*16]; + const U32 MAX_TE_BUFFER = 4096; + U8 packed_buffer[MAX_TE_BUFFER]; + memset((void*)packed_buffer, 0, MAX_TE_BUFFER); - const U32 MAX_TE_BUFFER = 4096; - U8 packed_buffer[MAX_TE_BUFFER]; - U8 *cur_ptr = packed_buffer; + LLUUID image_data[MAX_TES]; + LLColor4U colors[MAX_TES]; + F32 scale_s[MAX_TES]; + F32 scale_t[MAX_TES]; + S16 offset_s[MAX_TES]; + S16 offset_t[MAX_TES]; + S16 image_rot[MAX_TES]; + U8 bump[MAX_TES]; + U8 media_flags[MAX_TES]; + U8 glow[MAX_TES]; + material_id_type material_data[MAX_TES]; + + memset((void*)scale_s, 0, sizeof(scale_s)); + memset((void*)scale_t, 0, sizeof(scale_t)); + memset((void*)offset_s, 0, sizeof(offset_s)); + memset((void*)offset_t, 0, sizeof(offset_t)); + memset((void*)image_rot, 0, sizeof(image_rot)); + memset((void*)bump, 0, sizeof(bump)); + memset((void*)media_flags, 0, sizeof(media_flags)); + memset((void*)glow, 0, sizeof(glow)); S32 size; U32 face_count = 0; @@ -1470,50 +1531,52 @@ S32 LLPrimitive::unpackTEMessage(LLDataPacker &dp) { return retval; } + else if (size >= MAX_TE_BUFFER) + { + LL_WARNS("TEXTUREENTRY") << "Excessive buffer size detected in Texture Entry! Truncating." << LL_ENDL; + size = MAX_TE_BUFFER - 1; + } + // The last field is not zero terminated. + // Rather than special case the upack functions. Just make it 0x00 terminated. + packed_buffer[size] = 0x00; + ++size; face_count = llmin((U32) getNumTEs(), MAX_TES); U32 i; - cur_ptr += unpackTEField(cur_ptr, packed_buffer+size, (U8 *)image_data, 16, face_count, MVT_LLUUID); - cur_ptr++; - cur_ptr += unpackTEField(cur_ptr, packed_buffer+size, (U8 *)colors, 4, face_count, MVT_U8); - cur_ptr++; - cur_ptr += unpackTEField(cur_ptr, packed_buffer+size, (U8 *)scale_s, 4, face_count, MVT_F32); - cur_ptr++; - cur_ptr += unpackTEField(cur_ptr, packed_buffer+size, (U8 *)scale_t, 4, face_count, MVT_F32); - cur_ptr++; - cur_ptr += unpackTEField(cur_ptr, packed_buffer+size, (U8 *)offset_s, 2, face_count, MVT_S16Array); - cur_ptr++; - cur_ptr += unpackTEField(cur_ptr, packed_buffer+size, (U8 *)offset_t, 2, face_count, MVT_S16Array); - cur_ptr++; - cur_ptr += unpackTEField(cur_ptr, packed_buffer+size, (U8 *)image_rot, 2, face_count, MVT_S16Array); - cur_ptr++; - cur_ptr += unpackTEField(cur_ptr, packed_buffer+size, (U8 *)bump, 1, face_count, MVT_U8); - cur_ptr++; - cur_ptr += unpackTEField(cur_ptr, packed_buffer+size, (U8 *)media_flags, 1, face_count, MVT_U8); - cur_ptr++; - cur_ptr += unpackTEField(cur_ptr, packed_buffer+size, (U8 *)glow, 1, face_count, MVT_U8); - if (cur_ptr < packed_buffer + size) + U8 *cur_ptr = packed_buffer; + LL_DEBUGS("TEXTUREENTRY") << "Texture Entry with buffer sized: " << size << LL_ENDL; + U8 *buffer_end = packed_buffer + size; + + if (!( unpack_TEField(image_data, face_count, cur_ptr, buffer_end, MVT_LLUUID) && + unpack_TEField(colors, face_count, cur_ptr, buffer_end, MVT_U8) && + unpack_TEField(scale_s, face_count, cur_ptr, buffer_end, MVT_F32) && + unpack_TEField(scale_t, face_count, cur_ptr, buffer_end, MVT_F32) && + unpack_TEField(offset_s, face_count, cur_ptr, buffer_end, MVT_S16) && + unpack_TEField(offset_t, face_count, cur_ptr, buffer_end, MVT_S16) && + unpack_TEField(image_rot, face_count, cur_ptr, buffer_end, MVT_S16) && + unpack_TEField(bump, face_count, cur_ptr, buffer_end, MVT_U8) && + unpack_TEField(media_flags, face_count, cur_ptr, buffer_end, MVT_U8) && + unpack_TEField(glow, face_count, cur_ptr, buffer_end, MVT_U8))) + { + LL_WARNS("TEXTUREENTRY") << "Failure parsing Texture Entry Message due to malformed TE Field! Dropping changes on the floor. " << LL_ENDL; + return 0; + } + + if (cur_ptr >= buffer_end || !unpack_TEField(material_data, face_count, cur_ptr, buffer_end, MVT_LLUUID)) { - cur_ptr++; - cur_ptr += unpackTEField(cur_ptr, packed_buffer+size, (U8 *)material_data, 16, face_count, MVT_LLUUID); - } - else - { - memset(material_data, 0, sizeof(material_data)); + memset((void*)material_data, 0, sizeof(material_data)); } for (i = 0; i < face_count; i++) { - memcpy( image_ids[ i ].mData, &image_data[ i*UUID_BYTES ], UUID_BYTES ); /* Flawfinder: ignore */ - material_ids[ i ].set( &material_data[ i * UUID_BYTES ] ); + material_ids[i].set(&(material_data[i])); } LLColor4 color; - LLColor4U coloru; for (i = 0; i < face_count; i++) { - retval |= setTETexture(i, image_ids[i]); + retval |= setTETexture(i, ((LLUUID*)image_data)[i]); retval |= setTEScale(i, scale_s[i], scale_t[i]); retval |= setTEOffset(i, (F32)offset_s[i] / (F32)0x7FFF, (F32) offset_t[i] / (F32) 0x7FFF); retval |= setTERotation(i, ((F32)image_rot[i] / TEXTURE_ROTATION_PACK_FACTOR) * F_TWO_PI); @@ -1521,15 +1584,14 @@ S32 LLPrimitive::unpackTEMessage(LLDataPacker &dp) retval |= setTEMediaTexGen(i, media_flags[i]); retval |= setTEGlow(i, (F32)glow[i] / (F32)0xFF); retval |= setTEMaterialID(i, material_ids[i]); - coloru = LLColor4U(colors + 4*i); // Note: This is an optimization to send common colors (1.f, 1.f, 1.f, 1.f) // as all zeros. However, the subtraction and addition must be done in unsigned // byte space, not in float space, otherwise off-by-one errors occur. JC - color.mV[VRED] = F32(255 - coloru.mV[VRED]) / 255.f; - color.mV[VGREEN] = F32(255 - coloru.mV[VGREEN]) / 255.f; - color.mV[VBLUE] = F32(255 - coloru.mV[VBLUE]) / 255.f; - color.mV[VALPHA] = F32(255 - coloru.mV[VALPHA]) / 255.f; + color.mV[VRED] = F32(255 - colors[i].mV[VRED]) / 255.f; + color.mV[VGREEN] = F32(255 - colors[i].mV[VGREEN]) / 255.f; + color.mV[VBLUE] = F32(255 - colors[i].mV[VBLUE]) / 255.f; + color.mV[VALPHA] = F32(255 - colors[i].mV[VALPHA]) / 255.f; retval |= setTEColor(i, color); } diff --git a/indra/llprimitive/llprimitive.h b/indra/llprimitive/llprimitive.h index 744a946dba..826d113ed7 100644 --- a/indra/llprimitive/llprimitive.h +++ b/indra/llprimitive/llprimitive.h @@ -338,8 +338,8 @@ struct LLTEContents { static const U32 MAX_TES = 45; - U8 image_data[MAX_TES*16]; - U8 colors[MAX_TES*4]; + LLUUID image_data[MAX_TES]; + LLColor4U colors[MAX_TES]; F32 scale_s[MAX_TES]; F32 scale_t[MAX_TES]; S16 offset_s[MAX_TES]; @@ -432,7 +432,6 @@ public: void copyTEs(const LLPrimitive *primitive); S32 packTEField(U8 *cur_ptr, U8 *data_ptr, U8 data_size, U8 last_face_index, EMsgVariableType type) const; - S32 unpackTEField(U8 *cur_ptr, U8 *buffer_end, U8 *data_ptr, U8 data_size, U8 face_count, EMsgVariableType type); BOOL packTEMessage(LLMessageSystem *mesgsys) const; BOOL packTEMessage(LLDataPacker &dp) const; S32 unpackTEMessage(LLMessageSystem* mesgsys, char const* block_name, const S32 block_num); // Variable num of blocks diff --git a/indra/llui/llcombobox.cpp b/indra/llui/llcombobox.cpp index c2c7d0d50c..4a62cadb08 100644 --- a/indra/llui/llcombobox.cpp +++ b/indra/llui/llcombobox.cpp @@ -1065,6 +1065,43 @@ void LLComboBox::prearrangeList(std::string filter) } } + +//============================================================================ +// ll::ui::SearchableControl functions + +//virtual +std::string LLComboBox::_getSearchText() const +{ + std::string res; + if (mList) + { + // getAllData returns a full copy of content, might be a + // better option to implement an mList->getSearchText(column) + std::vector data = mList->getAllData(); + std::vector::iterator iter = data.begin(); + while (iter != data.end()) + { + LLScrollListCell* cell = (*iter)->getColumn(0); + if (cell) + { + std::string whitelist_url = cell->getValue().asString(); + res += cell->getValue().asString(); + } + iter++; + } + } + return res + getToolTip(); +} + +//virtual +void LLComboBox::onSetHighlight() const +{ + if (mButton) + { + mButton->ll::ui::SearchableControl::setHighlighted(ll::ui::SearchableControl::getHighlighted()); + } +} + //============================================================================ // LLCtrlListInterface functions diff --git a/indra/llui/llcombobox.h b/indra/llui/llcombobox.h index 4525ef9029..5f5bd2eb32 100644 --- a/indra/llui/llcombobox.h +++ b/indra/llui/llcombobox.h @@ -44,7 +44,9 @@ class LLFontGL; class LLViewBorder; class LLComboBox -: public LLUICtrl, public LLCtrlListInterface +: public LLUICtrl +, public LLCtrlListInterface +, public ll::ui::SearchableControl { public: typedef enum e_preferred_position @@ -101,6 +103,9 @@ protected: void initFromParams(const Params&); void prearrangeList(std::string filter = ""); + virtual std::string _getSearchText() const; + virtual void onSetHighlight() const; + public: // LLView interface virtual void onFocusLost(); diff --git a/indra/llui/llfloater.cpp b/indra/llui/llfloater.cpp index 018926c8ad..ef2ebd57f0 100644 --- a/indra/llui/llfloater.cpp +++ b/indra/llui/llfloater.cpp @@ -290,7 +290,8 @@ LLFloater::LLFloater(const LLSD& key, const LLFloater::Params& p) mDefaultRelativeX(p.rel_x), mDefaultRelativeY(p.rel_y), mMinimizeSignal(NULL), - mHostedFloaterShowtitlebar(p.hosted_floater_show_titlebar) // MultiFloater without titlebar for hosted floater + mHostedFloaterShowtitlebar(p.hosted_floater_show_titlebar), // MultiFloater without titlebar for hosted floater + mShiftPressed(false) // FIRE-24125: Add option to close all floaters of a group // mNotificationContext(NULL) { mPosition.setFloater(*this); @@ -1717,6 +1718,30 @@ BOOL LLFloater::handleDoubleClick(S32 x, S32 y, MASK mask) return was_minimized || LLPanel::handleDoubleClick(x, y, mask); } +// FIRE-24125: Add option to close all floaters of a group +//virtual +BOOL LLFloater::handleKeyHere(KEY key, MASK mask) +{ + if (mask == MASK_SHIFT) + { + mShiftPressed = true; + } + + return LLPanel::handleKeyHere(key, mask); +} + +//virtual +BOOL LLFloater::handleKeyUpHere(KEY key, MASK mask) +{ + if (mask == MASK_SHIFT) + { + mShiftPressed = false; + } + + return LLPanel::handleKeyUpHere(key, mask); +} +// + void LLFloater::bringToFront( S32 x, S32 y ) { if (getVisible() && pointInView(x, y)) @@ -1965,6 +1990,20 @@ void LLFloater::onClickClose( LLFloater* self ) void LLFloater::onClickCloseBtn(bool app_quitting) { + // FIRE-24125: Add option to close all floaters of a group + if (mShiftPressed) + { + auto floaterlist = LLFloaterReg::getAllFloatersInGroup(this); + for (auto floater : floaterlist) + { + if (floater != this) + { + floater->closeFloater(); + } + } + } + // + closeFloater(false); } diff --git a/indra/llui/llfloater.h b/indra/llui/llfloater.h index e72f79e4ea..f6ef386c74 100644 --- a/indra/llui/llfloater.h +++ b/indra/llui/llfloater.h @@ -310,7 +310,12 @@ public: virtual BOOL handleMiddleMouseDown(S32 x, S32 y, MASK mask); virtual BOOL handleScrollWheel(S32 x, S32 y, S32 mask); - + + // FIRE-24125: Add option to close all floaters of a group + virtual BOOL handleKeyHere(KEY key, MASK mask); + virtual BOOL handleKeyUpHere(KEY key, MASK mask); + // + virtual void draw(); virtual void drawShadow(LLPanel* panel); @@ -555,6 +560,9 @@ private: // MultiFloater without titlebar for hosted floater bool mHostedFloaterShowtitlebar; + + // FIRE-24125: Add option to close all floaters of a group + bool mShiftPressed; }; diff --git a/indra/llui/llfloaterreg.cpp b/indra/llui/llfloaterreg.cpp index cea1e11f07..5193b16a1e 100644 --- a/indra/llui/llfloaterreg.cpp +++ b/indra/llui/llfloaterreg.cpp @@ -103,6 +103,37 @@ LLFloater* LLFloaterReg::getLastFloaterInGroup(const std::string& name) return NULL; } +// FIRE-24125: Add option to close all floaters of a group +//static +LLFloaterReg::instance_list_t LLFloaterReg::getAllFloatersInGroup(LLFloater* floater) +{ + if (floater) + { + for (const auto& group : sGroupMap) + { + const std::string& group_name = group.second; + + if (group_name.empty()) + { + continue; + } + + instance_list_t& instances = sInstanceMap[group_name]; + + for (auto instance : instances) + { + if (instance == floater) + { + return sInstanceMap[group_name]; + } + } + } + } + + return {}; +} +// + LLFloater* LLFloaterReg::getLastFloaterCascading() { LLRect candidate_rect; diff --git a/indra/llui/llfloaterreg.h b/indra/llui/llfloaterreg.h index 0ab610906b..a76eb5c79b 100644 --- a/indra/llui/llfloaterreg.h +++ b/indra/llui/llfloaterreg.h @@ -114,6 +114,7 @@ public: // Helpers static LLFloater* getLastFloaterInGroup(const std::string& name); static LLFloater* getLastFloaterCascading(); + static instance_list_t getAllFloatersInGroup(LLFloater* floater); // FIRE-24125: Add option to close all floaters of a group // Find / get (create) / remove / destroy static LLFloater* findInstance(const std::string& name, const LLSD& key = LLSD()); diff --git a/indra/llui/llnotifications.h b/indra/llui/llnotifications.h index 8ec04d2bd5..624c267f28 100644 --- a/indra/llui/llnotifications.h +++ b/indra/llui/llnotifications.h @@ -84,7 +84,6 @@ #include #include -#include #include #include #include @@ -132,7 +131,7 @@ public: typedef boost::function LLNotificationResponder; -typedef boost::shared_ptr LLNotificationResponderPtr; +typedef std::shared_ptr LLNotificationResponderPtr; typedef LLFunctorRegistry LLNotificationFunctorRegistry; typedef LLFunctorRegistration LLNotificationFunctorRegistration; @@ -278,19 +277,19 @@ private: bool mInvertSetting; }; -typedef boost::shared_ptr LLNotificationFormPtr; +typedef std::shared_ptr LLNotificationFormPtr; struct LLNotificationTemplate; // we want to keep a map of these by name, and it's best to manage them // with smart pointers -typedef boost::shared_ptr LLNotificationTemplatePtr; +typedef std::shared_ptr LLNotificationTemplatePtr; struct LLNotificationVisibilityRule; -typedef boost::shared_ptr LLNotificationVisibilityRulePtr; +typedef std::shared_ptr LLNotificationVisibilityRulePtr; /** * @class LLNotification @@ -764,6 +763,10 @@ public: {} virtual ~LLNotificationChannelBase() { + // explicit cleanup for easier issue detection + mChanged.disconnect_all_slots(); + mPassedFilter.disconnect_all_slots(); + mFailedFilter.disconnect_all_slots(); mItems.clear(); } // you can also connect to a Channel, so you can be notified of diff --git a/indra/llui/llnotificationslistener.h b/indra/llui/llnotificationslistener.h index f9f7641de6..4bab377626 100644 --- a/indra/llui/llnotificationslistener.h +++ b/indra/llui/llnotificationslistener.h @@ -31,7 +31,6 @@ #include "lleventapi.h" #include "llnotificationptr.h" -#include #include #include @@ -61,7 +60,7 @@ private: static LLSD asLLSD(LLNotificationPtr); class Forwarder; - typedef std::map > ForwarderMap; + typedef std::map > ForwarderMap; ForwarderMap mForwarders; LLNotifications & mNotifications; }; diff --git a/indra/llui/llnotificationtemplate.h b/indra/llui/llnotificationtemplate.h index 20cbc89ede..a8902486e4 100644 --- a/indra/llui/llnotificationtemplate.h +++ b/indra/llui/llnotificationtemplate.h @@ -31,7 +31,7 @@ #include "llinitparam.h" #include "llnotifications.h" -typedef boost::shared_ptr LLNotificationFormPtr; +typedef std::shared_ptr LLNotificationFormPtr; // This is the class of object read from the XML file (notifications.xml, // from the appropriate local language directory). diff --git a/indra/llui/llscrolllistcell.cpp b/indra/llui/llscrolllistcell.cpp index 13839da400..61470d1440 100644 --- a/indra/llui/llscrolllistcell.cpp +++ b/indra/llui/llscrolllistcell.cpp @@ -54,6 +54,10 @@ LLScrollListCell* LLScrollListCell::create(const LLScrollListCell::Params& cell_ { cell = new LLScrollListIconText(cell_p); } + else if (cell_p.type() == "bar") + { + cell = new LLScrollListBar(cell_p); + } else // default is "text" { cell = new LLScrollListText(cell_p); @@ -165,6 +169,74 @@ void LLScrollListIcon::draw(const LLColor4& color, const LLColor4& highlight_col } } +// +// LLScrollListBar +// +LLScrollListBar::LLScrollListBar(const LLScrollListCell::Params& p) + : LLScrollListCell(p), + mRatio(0), + mColor(p.color), + mBottom(1), + mLeftPad(1), + mRightPad(1) +{} + +LLScrollListBar::~LLScrollListBar() +{ +} + +/*virtual*/ +S32 LLScrollListBar::getHeight() const +{ + return LLScrollListCell::getHeight(); +} + +/*virtual*/ +const LLSD LLScrollListBar::getValue() const +{ + return LLStringUtil::null; +} + +void LLScrollListBar::setValue(const LLSD& value) +{ + if (value.has("ratio")) + { + mRatio = value["ratio"].asReal(); + } + if (value.has("bottom")) + { + mBottom = value["bottom"].asInteger(); + } + if (value.has("left_pad")) + { + mLeftPad = value["left_pad"].asInteger(); + } + if (value.has("right_pad")) + { + mRightPad = value["right_pad"].asInteger(); + } +} + +void LLScrollListBar::setColor(const LLColor4& color) +{ + mColor = color; +} + +S32 LLScrollListBar::getWidth() const +{ + return LLScrollListCell::getWidth(); +} + + +void LLScrollListBar::draw(const LLColor4& color, const LLColor4& highlight_color) const +{ + S32 bar_width = getWidth() - mLeftPad - mRightPad; + S32 left = bar_width - bar_width * mRatio; + left = llclamp(left, mLeftPad, getWidth() - mRightPad - 1); + + gl_rect_2d(left, mBottom, getWidth() - mRightPad, mBottom - 1, mColor); +} + // // LLScrollListText // diff --git a/indra/llui/llscrolllistcell.h b/indra/llui/llscrolllistcell.h index 19576fb247..9a659dfd0d 100644 --- a/indra/llui/llscrolllistcell.h +++ b/indra/llui/llscrolllistcell.h @@ -33,6 +33,7 @@ #include "lluistring.h" #include "v4color.h" #include "llui.h" +#include "llgltexture.h" class LLCheckBoxCtrl; class LLSD; @@ -153,6 +154,7 @@ public: void setText(const LLStringExplicit& text); void setFontStyle(const U8 font_style); + void setAlignment(LLFontGL::HAlign align) { mFontAlignment = align; } protected: LLUIString mText; @@ -192,6 +194,26 @@ private: LLFontGL::HAlign mAlignment; }; + +class LLScrollListBar : public LLScrollListCell +{ +public: + LLScrollListBar(const LLScrollListCell::Params& p); + /*virtual*/ ~LLScrollListBar(); + /*virtual*/ void draw(const LLColor4& color, const LLColor4& highlight_color) const; + /*virtual*/ S32 getWidth() const; + /*virtual*/ S32 getHeight() const; + /*virtual*/ const LLSD getValue() const; + /*virtual*/ void setColor(const LLColor4&); + /*virtual*/ void setValue(const LLSD& value); + +private: + LLColor4 mColor; + F32 mRatio; + S32 mBottom; + S32 mRightPad; + S32 mLeftPad; +}; /* * An interactive cell containing a check box. */ diff --git a/indra/llui/llscrolllistctrl.cpp b/indra/llui/llscrolllistctrl.cpp index f1501cbd73..8407b30e4c 100644 --- a/indra/llui/llscrolllistctrl.cpp +++ b/indra/llui/llscrolllistctrl.cpp @@ -3709,7 +3709,8 @@ BOOL LLScrollListCtrl::operateOnAll(EOperation op) void LLScrollListCtrl::setFocus(BOOL b) { // for tabbing into pristine scroll lists (Finder) - if (!getFirstSelected()) + //if (!getFirstSelected()) + if (!getFirstSelected() && !getEnabled()) // make disabled lists not jump to the top on clicking an element in them. { selectFirstItem(); //onCommit(); // SJB: selectFirstItem() will call onCommit() if appropriate diff --git a/indra/llui/lltextbase.cpp b/indra/llui/lltextbase.cpp index 3b46cdf95a..2c192df2a9 100644 --- a/indra/llui/lltextbase.cpp +++ b/indra/llui/lltextbase.cpp @@ -206,6 +206,7 @@ LLTextBase::LLTextBase(const LLTextBase::Params &p) mFontShadow(p.font_shadow), mPopupMenuHandle(), mReadOnly(p.read_only), + mSkipTripleClick(false), mSkipLinkUnderline(p.skip_link_underline), mSpellCheck(p.spellcheck), mSpellCheckStart(-1), @@ -1092,6 +1093,11 @@ BOOL LLTextBase::handleMouseDown(S32 x, S32 y, MASK mask) // handle triple click if (!mTripleClickTimer.hasExpired()) { + if (mSkipTripleClick) + { + return TRUE; + } + S32 real_line = getLineNumFromDocIndex(mCursorPos, false); S32 line_start = -1; S32 line_end = -1; diff --git a/indra/llui/lltextbase.h b/indra/llui/lltextbase.h index 9421b69c65..0bebfd86ac 100644 --- a/indra/llui/lltextbase.h +++ b/indra/llui/lltextbase.h @@ -761,7 +761,7 @@ protected: bool mPlainText; // didn't use Image or Icon segments bool mAutoIndent; S32 mMaxTextByteLength; // Maximum length mText is allowed to be in bytes - + bool mSkipTripleClick; bool mSkipLinkUnderline; // support widgets diff --git a/indra/llui/lltextbox.cpp b/indra/llui/lltextbox.cpp index 1568693c90..d0c82faf94 100644 --- a/indra/llui/lltextbox.cpp +++ b/indra/llui/lltextbox.cpp @@ -45,7 +45,9 @@ LLTextBox::LLTextBox(const LLTextBox::Params& p) : LLTextBase(p), mClickedCallback(NULL), mShowCursorHand(true) -{} +{ + mSkipTripleClick = true; +} LLTextBox::~LLTextBox() {} diff --git a/indra/llui/lltexteditor.cpp b/indra/llui/lltexteditor.cpp index f6ef8a2731..c45941a198 100644 --- a/indra/llui/lltexteditor.cpp +++ b/indra/llui/lltexteditor.cpp @@ -1834,11 +1834,53 @@ BOOL LLTextEditor::handleSpecialKey(const KEY key, const MASK mask) S32 offset = getLineOffsetFromDocIndex(mCursorPos); - S32 spaces_needed = SPACES_PER_TAB - (offset % SPACES_PER_TAB); - for( S32 i=0; i < spaces_needed; i++ ) + // Allow Shift-Tab to tab-remove in text editors + // Modified version from removeCharOrTab() + if (mask & MASK_SHIFT) { - addChar( ' ' ); + S32 chars_to_remove = 0; + + LLWString text = getWText(); + if (mEnableTabRemove && text[mCursorPos - 1] == ' ') + { + // Try to remove a "tab" + S32 offset = getLineOffsetFromDocIndex(mCursorPos); + if (offset > 0) + { + chars_to_remove = offset % SPACES_PER_TAB; + if (chars_to_remove == 0) + { + chars_to_remove = SPACES_PER_TAB; + } + + for (S32 i = 0; i < chars_to_remove; i++) + { + if (text[mCursorPos - i - 1] != ' ') + { + // Fewer than a full tab's worth of spaces, so + // just delete a single character. + chars_to_remove = 1; + break; + } + } + } + } + + for (S32 i = 0; i < chars_to_remove; i++) + { + setCursorPos(mCursorPos - 1); + remove(mCursorPos, 1, FALSE); + } } + else + { + // + S32 spaces_needed = SPACES_PER_TAB - (offset % SPACES_PER_TAB); + for (S32 i = 0; i < spaces_needed; i++) + { + addChar(' '); + } + } // Allow Shift-Tab to tab-remove in text editors } break; diff --git a/indra/llui/llurlentry.cpp b/indra/llui/llurlentry.cpp index 03e37ff69f..27fe2cea59 100644 --- a/indra/llui/llurlentry.cpp +++ b/indra/llui/llurlentry.cpp @@ -35,6 +35,7 @@ #include "llavatarnamecache.h" #include "llcachename.h" +#include "llregex.h" #include "lltrans.h" #include "lluicolortable.h" #include "message.h" @@ -184,11 +185,51 @@ bool LLUrlEntryBase::isLinkDisabled() const return globally_disabled; } -bool LLUrlEntryBase::isWikiLinkCorrect(std::string url) +bool LLUrlEntryBase::isWikiLinkCorrect(const std::string &labeled_url) const { - LLWString label = utf8str_to_wstring(getLabelFromWikiLink(url)); - label.erase(std::remove(label.begin(), label.end(), L'\u200B'), label.end()); - return (LLUrlRegistry::instance().hasUrl(wstring_to_utf8str(label))) ? false : true; + LLWString wlabel = utf8str_to_wstring(getLabelFromWikiLink(labeled_url)); + wlabel.erase(std::remove(wlabel.begin(), wlabel.end(), L'\u200B'), wlabel.end()); + + // Unicode URL validation, see SL-15243 + std::replace_if(wlabel.begin(), + wlabel.end(), + [](const llwchar &chr) + { + return (chr == L'\u2024') // "One Dot Leader" + || (chr == L'\uFE52') // "Small Full Stop" + || (chr == L'\uFF0E') // "Fullwidth Full Stop" + // Not a decomposition, but suficiently similar + || (chr == L'\u05C5'); // "Hebrew Mark Lower Dot" + }, + L'\u002E'); // Dot "Full Stop" + + std::replace_if(wlabel.begin(), + wlabel.end(), + [](const llwchar &chr) + { + return (chr == L'\u02D0') // "Modifier Letter Colon" + || (chr == L'\uFF1A') // "Fullwidth Colon" + || (chr == L'\uFE55'); // "Small Colon" + }, + L'\u003A'); // Colon + + std::replace_if(wlabel.begin(), + wlabel.end(), + [](const llwchar &chr) + { + return (chr == L'\uFF0F'); // "Fullwidth Solidus" + }, + L'\u002F'); // Solidus + + std::string label = wstring_to_utf8str(wlabel); + if ((label.find(".com") != std::string::npos + || label.find("www.") != std::string::npos) + && label.find("://") == std::string::npos) + { + label = "http://" + label; + } + + return (LLUrlRegistry::instance().hasUrl(label)) ? false : true; } std::string LLUrlEntryBase::urlToLabelWithGreyQuery(const std::string &url) const @@ -1603,7 +1644,7 @@ std::string LLUrlEntryIcon::getIcon(const std::string &url) // Grep icon info between ... tags // matches[1] contains the icon name/path boost::match_results matches; - mIcon = (boost::regex_match(url, matches, mPattern) && matches[1].matched) + mIcon = (ll_regex_match(url, matches, mPattern) && matches[1].matched) ? matches[1] : LLStringUtil::null; LLStringUtil::trim(mIcon); diff --git a/indra/llui/llurlentry.h b/indra/llui/llurlentry.h index 6825d83f44..9b41618413 100644 --- a/indra/llui/llurlentry.h +++ b/indra/llui/llurlentry.h @@ -105,7 +105,7 @@ public: bool isLinkDisabled() const; - bool isWikiLinkCorrect(std::string url); + bool isWikiLinkCorrect(const std::string &url) const; virtual bool isSLURLvalid(const std::string &url) const { return TRUE; }; diff --git a/indra/llui/llurlregistry.cpp b/indra/llui/llurlregistry.cpp index a66c099a81..d8c1541a6c 100644 --- a/indra/llui/llurlregistry.cpp +++ b/indra/llui/llurlregistry.cpp @@ -26,10 +26,10 @@ */ #include "linden_common.h" +#include "llregex.h" #include "llurlregistry.h" #include "lluriparser.h" -#include #include //for boost::ifind_first -KC // default dummy callback that ignores any label updates from the server @@ -127,15 +127,7 @@ static bool matchRegex(const char *text, boost::regex regex, U32 &start, U32 &en boost::cmatch result; bool found; - // regex_search can potentially throw an exception, so check for it - try - { - found = boost::regex_search(text, result, regex); - } - catch (std::runtime_error &) - { - return false; - } + found = ll_regex_search(text, result, regex); if (! found) { diff --git a/indra/llwindow/llappdelegate-objc.h b/indra/llwindow/llappdelegate-objc.h index 0b38647b4a..ceda7ff74c 100644 --- a/indra/llwindow/llappdelegate-objc.h +++ b/indra/llwindow/llappdelegate-objc.h @@ -33,6 +33,7 @@ LLNonInlineTextView *inputView; NSTimer *frameTimer; NSString *currentInputLanguage; + std::string secondLogPath; } @property (assign) IBOutlet LLNSWindow *window; diff --git a/indra/llwindow/llopenglview-objc.mm b/indra/llwindow/llopenglview-objc.mm index d609eca77b..6680d6d0ba 100644 --- a/indra/llwindow/llopenglview-objc.mm +++ b/indra/llwindow/llopenglview-objc.mm @@ -504,7 +504,8 @@ attributedStringInfo getSegments(NSAttributedString *str) // e.g. OS Window for upload something or Input Window... // mModifiers instance variable is for insertText: or insertText:replacementRange: (by Pell Smit) mModifiers = [theEvent modifierFlags]; - bool acceptsText = mHasMarkedText ? false : callKeyDown(&eventData, keycode, mModifiers); + + bool acceptsText = mHasMarkedText ? false : callKeyDown(&eventData, keycode, mModifiers, [[theEvent characters] characterAtIndex:0]); unichar ch; if (acceptsText && !mMarkedTextAllowed && @@ -547,7 +548,7 @@ attributedStringInfo getSegments(NSAttributedString *str) if (mModifiers & mask) { eventData.mKeyEvent = NativeKeyEventData::KEYDOWN; - callKeyDown(&eventData, [theEvent keyCode], 0); + callKeyDown(&eventData, [theEvent keyCode], 0, [[theEvent characters] characterAtIndex:0]); } else { diff --git a/indra/llwindow/llwindowmacosx-objc.h b/indra/llwindow/llwindowmacosx-objc.h index 814de634b9..a9ebffc09a 100644 --- a/indra/llwindow/llwindowmacosx-objc.h +++ b/indra/llwindow/llwindowmacosx-objc.h @@ -132,7 +132,7 @@ void setupInputWindow(NSWindowRef window, GLViewRef view); // These are all implemented in llwindowmacosx.cpp. // This is largely for easier interop between Obj-C and C++ (at least in the viewer's case due to the BOOL vs. BOOL conflict) bool callKeyUp(NSKeyEventRef event, unsigned short key, unsigned int mask); -bool callKeyDown(NSKeyEventRef event, unsigned short key, unsigned int mask); +bool callKeyDown(NSKeyEventRef event, unsigned short key, unsigned int mask, wchar_t character); void callResetKeys(); bool callUnicodeCallback(wchar_t character, unsigned int mask); void callRightMouseDown(float *pos, unsigned int mask); diff --git a/indra/llwindow/llwindowmacosx.cpp b/indra/llwindow/llwindowmacosx.cpp index b342cef457..e0ddb6b07b 100644 --- a/indra/llwindow/llwindowmacosx.cpp +++ b/indra/llwindow/llwindowmacosx.cpp @@ -217,8 +217,17 @@ bool callKeyUp(NSKeyEventRef event, unsigned short key, unsigned int mask) return retVal; } -bool callKeyDown(NSKeyEventRef event, unsigned short key, unsigned int mask) +bool callKeyDown(NSKeyEventRef event, unsigned short key, unsigned int mask, wchar_t character) { + if((key == gKeyboard->inverseTranslateKey('Z')) && (character == 'y')) + { + key = gKeyboard->inverseTranslateKey('Y'); + } + else if ((key == gKeyboard->inverseTranslateKey('Y')) && (character == 'z')) + { + key = gKeyboard->inverseTranslateKey('Z'); + } + mRawKeyEvent = event; bool retVal = gKeyboard->handleKeyDown(key, mask); mRawKeyEvent = NULL; diff --git a/indra/llwindow/llwindowsdl.cpp b/indra/llwindow/llwindowsdl.cpp index a5eab80af4..6945e8da67 100644 --- a/indra/llwindow/llwindowsdl.cpp +++ b/indra/llwindow/llwindowsdl.cpp @@ -1791,7 +1791,9 @@ void LLWindowSDL::gatherInput() if (SDLCheckGrabbyKeys(event.key.keysym.sym, TRUE) != 0) SDLReallyCaptureInput(TRUE); - if (event.key.keysym.unicode) + // FIRE-11512 - Fix accelerator keys sometimes typing things into text entry fields, like alt+h, ctrl+shift+1 ... + // if (event.key.keysym.unicode) + if ((gKeyboard->currentMask(false) & (MASK_ALT | MASK_CONTROL)) == 0 && event.key.keysym.unicode) { handleUnicodeUTF16(event.key.keysym.unicode, gKeyboard->currentMask(FALSE)); diff --git a/indra/mac_crash_logger/CMakeLists.txt b/indra/mac_crash_logger/CMakeLists.txt deleted file mode 100644 index 75621d7b75..0000000000 --- a/indra/mac_crash_logger/CMakeLists.txt +++ /dev/null @@ -1,94 +0,0 @@ -# -*- cmake -*- - -project(mac_crash_logger) - -include(00-Common) -include(LLCommon) -include(LLCoreHttp) -include(LLCrashLogger) -include(LLMath) -include(LLMessage) -include(LLFilesystem) -include(LLXML) -include(Linking) -include(LLSharedLibs) -include(Boost) - -include_directories( - ${LLCOREHTTP_INCLUDE_DIRS} - ${LLCOMMON_INCLUDE_DIRS} - ${LLCRASHLOGGER_INCLUDE_DIRS} - ${LLMATH_INCLUDE_DIRS} - ${LLFILESYSTEM_INCLUDE_DIRS} - ${LLXML_INCLUDE_DIRS} - ) -include_directories(SYSTEM - ${LLCOMMON_SYSTEM_INCLUDE_DIRS} - ${LLXML_SYSTEM_INCLUDE_DIRS} - ) - -set(mac_crash_logger_SOURCE_FILES - mac_crash_logger.cpp - llcrashloggermac.cpp - llcrashloggermacdelegate.mm - ) - -set(mac_crash_logger_HEADER_FILES - CMakeLists.txt - - llcrashloggermac.h - llcrashloggermacdelegate.h - ) - -set_source_files_properties(${mac_crash_logger_HEADER_FILES} - PROPERTIES HEADER_FILE_ONLY TRUE) -list(APPEND mac_crash_logger_SOURCE_FILES ${mac_crash_logger_HEADER_FILES}) - -set(mac_crash_logger_RESOURCE_FILES - CrashReporter.nib/ - ) -set_source_files_properties( - ${mac_crash_logger_RESOURCE_FILES} - PROPERTIES - HEADER_FILE_ONLY TRUE - ) -SOURCE_GROUP("Resources" FILES ${mac_crash_logger_RESOURCE_FILES}) -list(APPEND mac_crash_logger_SOURCE_FILES ${mac_crash_logger_RESOURCE_FILES}) - -add_executable(mac-crash-logger - MACOSX_BUNDLE - ${mac_crash_logger_SOURCE_FILES}) - -set_target_properties(mac-crash-logger - PROPERTIES - MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_SOURCE_DIR}/Info.plist - ) - -find_library(COCOA_LIBRARY Cocoa) - -target_link_libraries(mac-crash-logger - ${LLCRASHLOGGER_LIBRARIES} - ${LLFILESYSTEM_LIBRARIES} - ${COCOA_LIBRARIES} - ${LLXML_LIBRARIES} - ${LLMESSAGE_LIBRARIES} - ${LLMATH_LIBRARIES} - ${LLCOREHTTP_LIBRARIES} - ${LLCOMMON_LIBRARIES} - ${BOOST_CONTEXT_LIBRARY} - ${BOOST_FIBER_LIBRARY} - ) - -add_custom_command( - TARGET mac-crash-logger POST_BUILD - COMMAND ${CMAKE_COMMAND} - ARGS - -E - copy_if_different - ${CMAKE_CURRENT_SOURCE_DIR}/CrashReporter.nib - ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/mac-crash-logger.app/Contents/Resources/CrashReporter.nib - ) - -ll_deploy_sharedlibs_command(mac-crash-logger) - - diff --git a/indra/mac_crash_logger/CrashReporter.nib b/indra/mac_crash_logger/CrashReporter.nib deleted file mode 100755 index e9d9e05985..0000000000 Binary files a/indra/mac_crash_logger/CrashReporter.nib and /dev/null differ diff --git a/indra/mac_crash_logger/CrashReporter.xib b/indra/mac_crash_logger/CrashReporter.xib deleted file mode 100755 index f6d4776d51..0000000000 --- a/indra/mac_crash_logger/CrashReporter.xib +++ /dev/null @@ -1,3895 +0,0 @@ - - - - 1070 - 11G63 - 2182 - 1138.51 - 569.00 - - com.apple.InterfaceBuilder.CocoaPlugin - 2182 - - - NSTextField - NSView - NSWindowTemplate - NSMenu - NSMenuItem - NSTextFieldCell - NSButtonCell - IBNSLayoutConstraint - NSButton - NSCustomObject - - - com.apple.InterfaceBuilder.CocoaPlugin - - - PluginDependencyRecalculationVersion - - - - - NSApplication - - - FirstResponder - - - NSApplication - - - AMainMenu - - - - Second Life Crash Logger - - 1048576 - 2147483647 - - NSImage - NSMenuCheckmark - - - NSImage - NSMenuMixedState - - submenuAction: - - Second Life Crash Logger - - - - About Second Life Crash Logger - - 2147483647 - - - - - - YES - YES - - - 1048576 - 2147483647 - - - - - - Preferences… - , - 1048576 - 2147483647 - - - - - - YES - YES - - - 1048576 - 2147483647 - - - - - - Services - - 1048576 - 2147483647 - - - submenuAction: - - Services - - _NSServicesMenu - - - - - YES - YES - - - 1048576 - 2147483647 - - - - - - Hide Second Life Crash Logger - h - 1048576 - 2147483647 - - - - - - Hide Others - h - 1572864 - 2147483647 - - - - - - Show All - - 1048576 - 2147483647 - - - - - - YES - YES - - - 1048576 - 2147483647 - - - - - - Quit Second Life Crash Logger - q - 1048576 - 2147483647 - - - - - _NSAppleMenu - - - - - File - - 1048576 - 2147483647 - - - submenuAction: - - File - - - - New - n - 1048576 - 2147483647 - - - - - - Open… - o - 1048576 - 2147483647 - - - - - - Open Recent - - 1048576 - 2147483647 - - - submenuAction: - - Open Recent - - - - Clear Menu - - 1048576 - 2147483647 - - - - - _NSRecentDocumentsMenu - - - - - YES - YES - - - 1048576 - 2147483647 - - - - - - Close - w - 1048576 - 2147483647 - - - - - - Save… - s - 1048576 - 2147483647 - - - - - - Revert to Saved - - 2147483647 - - - - - - YES - YES - - - 1048576 - 2147483647 - - - - - - Page Setup... - P - 1179648 - 2147483647 - - - - - - - Print… - p - 1048576 - 2147483647 - - - - - - - - - Edit - - 1048576 - 2147483647 - - - submenuAction: - - Edit - - - - Undo - z - 1048576 - 2147483647 - - - - - - Redo - Z - 1179648 - 2147483647 - - - - - - YES - YES - - - 1048576 - 2147483647 - - - - - - Cut - x - 1048576 - 2147483647 - - - - - - Copy - c - 1048576 - 2147483647 - - - - - - Paste - v - 1048576 - 2147483647 - - - - - - Paste and Match Style - V - 1572864 - 2147483647 - - - - - - Delete - - 1048576 - 2147483647 - - - - - - Select All - a - 1048576 - 2147483647 - - - - - - YES - YES - - - 1048576 - 2147483647 - - - - - - Find - - 1048576 - 2147483647 - - - submenuAction: - - Find - - - - Find… - f - 1048576 - 2147483647 - - - 1 - - - - Find and Replace… - f - 1572864 - 2147483647 - - - 12 - - - - Find Next - g - 1048576 - 2147483647 - - - 2 - - - - Find Previous - G - 1179648 - 2147483647 - - - 3 - - - - Use Selection for Find - e - 1048576 - 2147483647 - - - 7 - - - - Jump to Selection - j - 1048576 - 2147483647 - - - - - - - - - Spelling and Grammar - - 1048576 - 2147483647 - - - submenuAction: - - Spelling and Grammar - - - - Show Spelling and Grammar - : - 1048576 - 2147483647 - - - - - - Check Document Now - ; - 1048576 - 2147483647 - - - - - - YES - YES - - - 2147483647 - - - - - - Check Spelling While Typing - - 1048576 - 2147483647 - - - - - - Check Grammar With Spelling - - 1048576 - 2147483647 - - - - - - Correct Spelling Automatically - - 2147483647 - - - - - - - - - Substitutions - - 1048576 - 2147483647 - - - submenuAction: - - Substitutions - - - - Show Substitutions - - 2147483647 - - - - - - YES - YES - - - 2147483647 - - - - - - Smart Copy/Paste - f - 1048576 - 2147483647 - - - 1 - - - - Smart Quotes - g - 1048576 - 2147483647 - - - 2 - - - - Smart Dashes - - 2147483647 - - - - - - Smart Links - G - 1179648 - 2147483647 - - - 3 - - - - Text Replacement - - 2147483647 - - - - - - - - - Transformations - - 2147483647 - - - submenuAction: - - Transformations - - - - Make Upper Case - - 2147483647 - - - - - - Make Lower Case - - 2147483647 - - - - - - Capitalize - - 2147483647 - - - - - - - - - Speech - - 1048576 - 2147483647 - - - submenuAction: - - Speech - - - - Start Speaking - - 1048576 - 2147483647 - - - - - - Stop Speaking - - 1048576 - 2147483647 - - - - - - - - - - - - Format - - 2147483647 - - - submenuAction: - - Format - - - - Font - - 2147483647 - - - submenuAction: - - Font - - - - Show Fonts - t - 1048576 - 2147483647 - - - - - - Bold - b - 1048576 - 2147483647 - - - 2 - - - - Italic - i - 1048576 - 2147483647 - - - 1 - - - - Underline - u - 1048576 - 2147483647 - - - - - - YES - YES - - - 2147483647 - - - - - - Bigger - + - 1048576 - 2147483647 - - - 3 - - - - Smaller - - - 1048576 - 2147483647 - - - 4 - - - - YES - YES - - - 2147483647 - - - - - - Kern - - 2147483647 - - - submenuAction: - - Kern - - - - Use Default - - 2147483647 - - - - - - Use None - - 2147483647 - - - - - - Tighten - - 2147483647 - - - - - - Loosen - - 2147483647 - - - - - - - - - Ligature - - 2147483647 - - - submenuAction: - - Ligature - - - - Use Default - - 2147483647 - - - - - - Use None - - 2147483647 - - - - - - Use All - - 2147483647 - - - - - - - - - Baseline - - 2147483647 - - - submenuAction: - - Baseline - - - - Use Default - - 2147483647 - - - - - - Superscript - - 2147483647 - - - - - - Subscript - - 2147483647 - - - - - - Raise - - 2147483647 - - - - - - Lower - - 2147483647 - - - - - - - - - YES - YES - - - 2147483647 - - - - - - Show Colors - C - 1048576 - 2147483647 - - - - - - YES - YES - - - 2147483647 - - - - - - Copy Style - c - 1572864 - 2147483647 - - - - - - Paste Style - v - 1572864 - 2147483647 - - - - - _NSFontMenu - - - - - Text - - 2147483647 - - - submenuAction: - - Text - - - - Align Left - { - 1048576 - 2147483647 - - - - - - Center - | - 1048576 - 2147483647 - - - - - - Justify - - 2147483647 - - - - - - Align Right - } - 1048576 - 2147483647 - - - - - - YES - YES - - - 2147483647 - - - - - - Writing Direction - - 2147483647 - - - submenuAction: - - Writing Direction - - - - YES - Paragraph - - 2147483647 - - - - - - CURlZmF1bHQ - - 2147483647 - - - - - - CUxlZnQgdG8gUmlnaHQ - - 2147483647 - - - - - - CVJpZ2h0IHRvIExlZnQ - - 2147483647 - - - - - - YES - YES - - - 2147483647 - - - - - - YES - Selection - - 2147483647 - - - - - - CURlZmF1bHQ - - 2147483647 - - - - - - CUxlZnQgdG8gUmlnaHQ - - 2147483647 - - - - - - CVJpZ2h0IHRvIExlZnQ - - 2147483647 - - - - - - - - - YES - YES - - - 2147483647 - - - - - - Show Ruler - - 2147483647 - - - - - - Copy Ruler - c - 1310720 - 2147483647 - - - - - - Paste Ruler - v - 1310720 - 2147483647 - - - - - - - - - - - - View - - 1048576 - 2147483647 - - - submenuAction: - - View - - - - Show Toolbar - t - 1572864 - 2147483647 - - - - - - Customize Toolbar… - - 1048576 - 2147483647 - - - - - - - - - Window - - 1048576 - 2147483647 - - - submenuAction: - - Window - - - - Minimize - m - 1048576 - 2147483647 - - - - - - Zoom - - 1048576 - 2147483647 - - - - - - YES - YES - - - 1048576 - 2147483647 - - - - - - Bring All to Front - - 1048576 - 2147483647 - - - - - _NSWindowsMenu - - - - - Help - - 2147483647 - - - submenuAction: - - Help - - - - Second Life Crash Logger Help - ? - 1048576 - 2147483647 - - - - - _NSHelpMenu - - - - _NSMainMenu - - - 15 - 2 - {{335, 390}, {508, 477}} - 1954021376 - Second Life Crash Logger - NSWindow - - - - - 256 - - - - 268 - {{17, 228}, {474, 229}} - - - - _NS:9 - {250, 750} - YES - - 67239424 - 272891904 - - U2Vjb25kIExpZmUgYXBwZWFycyB0byBoYXZlIGNyYXNoZWQgb3IgZnJvemVuIHRoZSBsYXN0IHRpbWUg -aXQgcmFuLgoKVGhpcyBjcmFzaCByZXBvcnRlciBjb2xsZWN0cyBpbmZvcm1hdGlvbiBhYm91dCB5b3Vy -IGNvbXB1dGVyJ3MgaGFyZHdhcmUgY29uZmlndXJhdGlvbiwgb3BlcmF0aW5nIHN5c3RlbSwgYW5kIHNv -bWUgU2Vjb25kIExpZmUgbG9ncywgYWxsIG9mIHdoaWNoIGFyZSB1c2VkIGZvciBkZWJ1Z2dpbmcgcHVy -cG9zZXMgb25seS4KCkluIHRoZSBzcGFjZSBiZWxvdywgcGxlYXNlIGJyaWVmbHkgZGVzY3JpYmUgd2hh -dCB5b3Ugd2VyZSBkb2luZyBvciB0cnlpbmcgdG8gZG8ganVzdCBwcmlvciB0byB0aGUgY3Jhc2guICBU -aGFuayB5b3UgZm9yIHlvdXIgaGVscCEKClRoaXMgcmVwb3J0IGlzIE5PVCByZWFkIGJ5IEN1c3RvbWVy -IFN1cHBvcnQuICBJZiB5b3UgaGF2ZSBiaWxsaW5nIG9yIG90aGVyIHF1ZXN0aW9ucywgcGxlYXNlIGdv -IHRvOiBodHRwOi8vd3d3LnNlY29uZGxpZmUuY29tL3N1cHBvcnQvCgpJZiB5b3UgZG9uJ3Qgd2lzaCB0 -byBzZW5kIExpbmRlbiBMYWIgYSBjcmFzaCByZXBvcnQsIHByZXNzIENhbmNlbC4 - - - LucidaGrande - 13 - 16 - - _NS:9 - - - 6 - System - controlColor - - 3 - MC42NjY2NjY2NjY3AA - - - - 6 - System - controlTextColor - - 3 - MAA - - - - - - - 268 - {{20, 64}, {468, 163}} - - - - _NS:9 - {250, 750} - YES - - -1805517311 - 272891904 - - - LucidaGrande - 9 - 3614 - - _NS:9 - - YES - - 6 - System - textBackgroundColor - - 3 - MQA - - - - 6 - System - textColor - - - - - - - 268 - {{16, 18}, {189, 30}} - - - - _NS:9 - YES - - -2080244224 - 262144 - Remember This Choice - - _NS:9 - - 1211912703 - 2 - - NSImage - NSSwitch - - - NSSwitch - - - - 200 - 25 - - - - - 268 - {{285, 23}, {91, 17}} - - - - _NS:9 - YES - - -2080244224 - 134479872 - Send Report - - _NS:9 - - -2038152961 - 164 - - - 400 - 75 - - - - - 268 - {{388, 23}, {100, 17}} - - - - _NS:9 - YES - - -2080244224 - 134479872 - Don't Send - - _NS:9 - - -2038152961 - 164 - - - 400 - 75 - - - - {508, 477} - - - - - {{0, 0}, {1680, 1028}} - {10000000000000, 10000000000000} - YES - - - LLCrashLoggerMacDelegate - - - - - - - terminate: - - - - 449 - - - - orderFrontStandardAboutPanel: - - - - 142 - - - - delegate - - - - 495 - - - - performMiniaturize: - - - - 37 - - - - arrangeInFront: - - - - 39 - - - - print: - - - - 86 - - - - runPageLayout: - - - - 87 - - - - clearRecentDocuments: - - - - 127 - - - - performClose: - - - - 193 - - - - toggleContinuousSpellChecking: - - - - 222 - - - - undo: - - - - 223 - - - - copy: - - - - 224 - - - - checkSpelling: - - - - 225 - - - - paste: - - - - 226 - - - - stopSpeaking: - - - - 227 - - - - cut: - - - - 228 - - - - showGuessPanel: - - - - 230 - - - - redo: - - - - 231 - - - - selectAll: - - - - 232 - - - - startSpeaking: - - - - 233 - - - - delete: - - - - 235 - - - - performZoom: - - - - 240 - - - - performFindPanelAction: - - - - 241 - - - - centerSelectionInVisibleArea: - - - - 245 - - - - toggleGrammarChecking: - - - - 347 - - - - toggleSmartInsertDelete: - - - - 355 - - - - toggleAutomaticQuoteSubstitution: - - - - 356 - - - - toggleAutomaticLinkDetection: - - - - 357 - - - - saveDocument: - - - - 362 - - - - revertDocumentToSaved: - - - - 364 - - - - runToolbarCustomizationPalette: - - - - 365 - - - - toggleToolbarShown: - - - - 366 - - - - hide: - - - - 367 - - - - hideOtherApplications: - - - - 368 - - - - unhideAllApplications: - - - - 370 - - - - newDocument: - - - - 373 - - - - openDocument: - - - - 374 - - - - raiseBaseline: - - - - 426 - - - - lowerBaseline: - - - - 427 - - - - copyFont: - - - - 428 - - - - subscript: - - - - 429 - - - - superscript: - - - - 430 - - - - tightenKerning: - - - - 431 - - - - underline: - - - - 432 - - - - orderFrontColorPanel: - - - - 433 - - - - useAllLigatures: - - - - 434 - - - - loosenKerning: - - - - 435 - - - - pasteFont: - - - - 436 - - - - unscript: - - - - 437 - - - - useStandardKerning: - - - - 438 - - - - useStandardLigatures: - - - - 439 - - - - turnOffLigatures: - - - - 440 - - - - turnOffKerning: - - - - 441 - - - - toggleAutomaticSpellingCorrection: - - - - 456 - - - - orderFrontSubstitutionsPanel: - - - - 458 - - - - toggleAutomaticDashSubstitution: - - - - 461 - - - - toggleAutomaticTextReplacement: - - - - 463 - - - - uppercaseWord: - - - - 464 - - - - capitalizeWord: - - - - 467 - - - - lowercaseWord: - - - - 468 - - - - pasteAsPlainText: - - - - 486 - - - - performFindPanelAction: - - - - 487 - - - - performFindPanelAction: - - - - 488 - - - - performFindPanelAction: - - - - 489 - - - - showHelp: - - - - 493 - - - - alignCenter: - - - - 518 - - - - pasteRuler: - - - - 519 - - - - toggleRuler: - - - - 520 - - - - alignRight: - - - - 521 - - - - copyRuler: - - - - 522 - - - - alignJustified: - - - - 523 - - - - alignLeft: - - - - 524 - - - - makeBaseWritingDirectionNatural: - - - - 525 - - - - makeBaseWritingDirectionLeftToRight: - - - - 526 - - - - makeBaseWritingDirectionRightToLeft: - - - - 527 - - - - makeTextWritingDirectionNatural: - - - - 528 - - - - makeTextWritingDirectionLeftToRight: - - - - 529 - - - - makeTextWritingDirectionRightToLeft: - - - - 530 - - - - performFindPanelAction: - - - - 535 - - - - window - - - - 532 - - - - remember: - - - - 1176 - - - - send: - - - - 1177 - - - - cancel: - - - - 1178 - - - - crashText - - - - 1179 - - - - rememberCheck - - - - 1187 - - - - - - 0 - - - - - - -2 - - - File's Owner - - - -1 - - - First Responder - - - -3 - - - Application - - - 29 - - - - - - - - - - - - - - 19 - - - - - - - - 56 - - - - - - - - 217 - - - - - - - - 83 - - - - - - - - 81 - - - - - - - - - - - - - - - - - 75 - - - - - 78 - - - - - 72 - - - - - 82 - - - - - 124 - - - - - - - - 77 - - - - - 73 - - - - - 79 - - - - - 112 - - - - - 74 - - - - - 125 - - - - - - - - 126 - - - - - 205 - - - - - - - - - - - - - - - - - - - - - - 202 - - - - - 198 - - - - - 207 - - - - - 214 - - - - - 199 - - - - - 203 - - - - - 197 - - - - - 206 - - - - - 215 - - - - - 218 - - - - - - - - 216 - - - - - - - - 200 - - - - - - - - - - - - - 219 - - - - - 201 - - - - - 204 - - - - - 220 - - - - - - - - - - - - - 213 - - - - - 210 - - - - - 221 - - - - - 208 - - - - - 209 - - - - - 57 - - - - - - - - - - - - - - - - - - 58 - - - - - 134 - - - - - 150 - - - - - 136 - - - - - 144 - - - - - 129 - - - - - 143 - - - - - 236 - - - - - 131 - - - - - - - - 149 - - - - - 145 - - - - - 130 - - - - - 24 - - - - - - - - - - - 92 - - - - - 5 - - - - - 239 - - - - - 23 - - - - - 295 - - - - - - - - 296 - - - - - - - - - 297 - - - - - 298 - - - - - 211 - - - - - - - - 212 - - - - - - - - - 195 - - - - - 196 - - - - - 346 - - - - - 348 - - - - - - - - 349 - - - - - - - - - - - - - - 350 - - - - - 351 - - - - - 354 - - - - - 371 - - - - - - - - 372 - - - - - - - - 3 - 0 - - 3 - 1 - - 20 - - 1000 - 8 - 29 - 3 - - - - - - - 6 - 0 - - 6 - 1 - - 20 - - 1000 - 8 - 29 - 3 - - - - - 5 - 0 - - 5 - 1 - - 20 - - 1000 - 8 - 29 - 3 - - - - - 6 - 0 - - 6 - 1 - - 20 - - 1000 - 8 - 29 - 3 - - - - - 5 - 0 - - 5 - 1 - - 20 - - 1000 - 8 - 29 - 3 - - - - - 4 - 0 - - 4 - 1 - - 64 - - 1000 - 3 - 9 - 3 - - - - - 6 - 0 - - 6 - 1 - - 20 - - 1000 - 8 - 29 - 3 - - - - - 5 - 0 - - 5 - 1 - - 20 - - 1000 - 8 - 29 - 3 - - - - - 4 - 0 - - 4 - 1 - - 21 - - 1000 - 3 - 9 - 3 - - - - - 6 - 0 - - 6 - 1 - - 132 - - 1000 - 3 - 9 - 3 - - - - - 11 - 0 - - 11 - 1 - - 0.0 - - 1000 - 6 - 24 - 2 - - - - - 10 - 0 - - 10 - 1 - - 0.0 - - 1000 - 6 - 24 - 2 - - - - - - - 375 - - - - - - - - 376 - - - - - - - - - 377 - - - - - - - - 388 - - - - - - - - - - - - - - - - - - - - - - - 389 - - - - - 390 - - - - - 391 - - - - - 392 - - - - - 393 - - - - - 394 - - - - - 395 - - - - - 396 - - - - - 397 - - - - - - - - 398 - - - - - - - - 399 - - - - - - - - 400 - - - - - 401 - - - - - 402 - - - - - 403 - - - - - 404 - - - - - 405 - - - - - - - - - - - - 406 - - - - - 407 - - - - - 408 - - - - - 409 - - - - - 410 - - - - - 411 - - - - - - - - - - 412 - - - - - 413 - - - - - 414 - - - - - 415 - - - - - - - - - - - 416 - - - - - 417 - - - - - 418 - - - - - 419 - - - - - 450 - - - - - - - - 451 - - - - - - - - - - 452 - - - - - 453 - - - - - 454 - - - - - 457 - - - - - 459 - - - - - 460 - - - - - 462 - - - - - 465 - - - - - 466 - - - - - 485 - - - - - 490 - - - - - - - - 491 - - - - - - - - 492 - - - - - 494 - - - - - 496 - - - - - - - - 497 - - - - - - - - - - - - - - - - - 498 - - - - - 499 - - - - - 500 - - - - - 501 - - - - - 502 - - - - - 503 - - - - - - - - 504 - - - - - 505 - - - - - 506 - - - - - 507 - - - - - 508 - - - - - - - - - - - - - - - - 509 - - - - - 510 - - - - - 511 - - - - - 512 - - - - - 513 - - - - - 514 - - - - - 515 - - - - - 516 - - - - - 517 - - - - - 534 - - - - - 536 - - - - - - 8 - 0 - - 0 - 1 - - 229 - - 1000 - 3 - 9 - 1 - - - - - - - 537 - - - - - 593 - - - - - - 8 - 0 - - 0 - 1 - - 163 - - 1000 - 3 - 9 - 1 - - - - - - - 594 - - - - - 727 - - - - - - 7 - 0 - - 0 - 1 - - 183 - - 1000 - 3 - 9 - 1 - - - - - 8 - 0 - - 0 - 1 - - 22 - - 1000 - 3 - 9 - 1 - - - - - - - 728 - - - - - 775 - - - - - - - - 776 - - - - - 780 - - - - - - 7 - 0 - - 0 - 1 - - 100 - - 1000 - 3 - 9 - 1 - - - - - - - 781 - - - - - 884 - - - - - 981 - - - - - 982 - - - - - 1022 - - - - - 1026 - - - - - 979 - - - - - 985 - - - - - 977 - - - - - 1099 - - - - - 1093 - - - - - 1100 - - - - - 1098 - - - - - 1168 - - - - - 1167 - - - - - 1095 - - - - - 1166 - - - - - 1076 - - - - - - - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - {{380, 496}, {480, 360}} - - - - - - - - - - - - - - - - com.apple.InterfaceBuilder.CocoaPlugin - - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - - - - - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - - - - - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - - - - - - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - - - - - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - - - - - - 1187 - - - - - LLCrashLoggerMacDelegate - NSObject - - id - id - id - - - - cancel: - id - - - remember: - id - - - send: - id - - - - NSTextField - NSButton - NSWindow - - - - crashText - NSTextField - - - rememberCheck - NSButton - - - window - NSWindow - - - - IBProjectSource - ./Classes/LLCrashLoggerMacDelegate.h - - - - NSLayoutConstraint - NSObject - - IBProjectSource - ./Classes/NSLayoutConstraint.h - - - - - 0 - IBCocoaFramework - - com.apple.InterfaceBuilder.CocoaPlugin.macosx - - - YES - 3 - - {11, 11} - {10, 3} - {15, 15} - - YES - - diff --git a/indra/mac_crash_logger/Info.plist b/indra/mac_crash_logger/Info.plist deleted file mode 100644 index 2ebed11c3f..0000000000 --- a/indra/mac_crash_logger/Info.plist +++ /dev/null @@ -1,28 +0,0 @@ - - - - - CFBundleDevelopmentRegion - English - CFBundleExecutable - mac-crash-logger - CFBundleGetInfoString - - CFBundleIconFile - - CFBundleInfoDictionaryVersion - 6.0 - CFBundlePackageType - APPL - CFBundleShortVersionString - - CFBundleSignature - ???? - CFBundleVersion - 1.0.0 - NSMainNibFile - CrashReporter - NSPrincipalClass - NSApplication - - diff --git a/indra/mac_crash_logger/llcrashloggermac.cpp b/indra/mac_crash_logger/llcrashloggermac.cpp deleted file mode 100644 index d35f5fe015..0000000000 --- a/indra/mac_crash_logger/llcrashloggermac.cpp +++ /dev/null @@ -1,99 +0,0 @@ -/** - * @file llcrashloggermac.cpp - * @brief Mac OSX crash logger implementation - * - * $LicenseInfo:firstyear=2003&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - - -#include "llcrashloggermac.h" - -#include - -#include "indra_constants.h" // CRASH_BEHAVIOR_ASK, CRASH_SETTING_NAME -#include "llerror.h" -#include "llfile.h" -#include "lltimer.h" -#include "llstring.h" -#include "lldir.h" -#include "llsdserialize.h" - -// Windows Message Handlers - -BOOL gFirstDialog = TRUE; -LLFILE *gDebugFile = NULL; - -std::string gUserNotes = ""; -bool gSendReport = false; -bool gRememberChoice = false; - -LLCrashLoggerMac::LLCrashLoggerMac(void) -{ -} - -LLCrashLoggerMac::~LLCrashLoggerMac(void) -{ -} - -bool LLCrashLoggerMac::init(void) -{ - bool ok = LLCrashLogger::init(); - return ok; -} - -void LLCrashLoggerMac::gatherPlatformSpecificFiles() -{ -} - -bool LLCrashLoggerMac::frame() -{ - - if (mCrashBehavior == CRASH_BEHAVIOR_ALWAYS_SEND) - { - gSendReport = true; - } - - // Restore crash report user settings - if(gRememberChoice) - { - if(gSendReport) saveCrashBehaviorSetting(CRASH_BEHAVIOR_ALWAYS_SEND); - else saveCrashBehaviorSetting(CRASH_BEHAVIOR_NEVER_SEND); - } - // - - if(gSendReport) - { - setUserText(gUserNotes); - sendCrashLogs(); - } - - LL_INFOS() << "Sending of logs complete" << LL_ENDL; - - return true; -} - -bool LLCrashLoggerMac::cleanup() -{ - commonCleanup(); - mKeyMaster.releaseMaster(); - return true; -} diff --git a/indra/mac_crash_logger/llcrashloggermac.h b/indra/mac_crash_logger/llcrashloggermac.h deleted file mode 100644 index 05ef8c9f53..0000000000 --- a/indra/mac_crash_logger/llcrashloggermac.h +++ /dev/null @@ -1,45 +0,0 @@ -/** - * @file llcrashloggermac.h - * @brief Mac OSX crash logger definition - * - * $LicenseInfo:firstyear=2003&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#ifndef LLCRASHLOGGERMAC_H -#define LLCRASHLOGGERMAC_H - -#include "linden_common.h" -#include "llcrashlogger.h" -#include "llstring.h" - -class LLCrashLoggerMac : public LLCrashLogger -{ -public: - LLCrashLoggerMac(void); - ~LLCrashLoggerMac(void); - virtual bool init(); - virtual bool frame(); - virtual bool cleanup(); - virtual void gatherPlatformSpecificFiles(); -}; - -#endif diff --git a/indra/mac_crash_logger/llcrashloggermacdelegate.h b/indra/mac_crash_logger/llcrashloggermacdelegate.h deleted file mode 100644 index c998a8efe2..0000000000 --- a/indra/mac_crash_logger/llcrashloggermacdelegate.h +++ /dev/null @@ -1,52 +0,0 @@ -/** - * @file llcrashloggermacdelegate.h - * @brief Mac OSX crash logger implementation - * - * $LicenseInfo:firstyear=2003&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -/* -#import - -@interface LLCrashLoggerMacDelegate : NSObject -{ - IBOutlet NSTextField *crashText; - IBOutlet NSButton *rememberCheck; - - NSWindow *_window; - bool mRemember; - -} - -- (void)setWindow:(NSWindow *)newWindow; -- (NSWindow *)window; - -- (IBAction)remember:(id)sender; -- (IBAction)send:(id)sender; -- (IBAction)cancel:(id)sender; - -@property (assign) IBOutlet NSWindow *window; - -@end -*/ - - diff --git a/indra/mac_crash_logger/llcrashloggermacdelegate.mm b/indra/mac_crash_logger/llcrashloggermacdelegate.mm deleted file mode 100644 index 1b1893cf01..0000000000 --- a/indra/mac_crash_logger/llcrashloggermacdelegate.mm +++ /dev/null @@ -1,75 +0,0 @@ -/** - * @file llcrashloggermacdelegate.mm - * @brief Mac OSX crash logger implementation - * - * $LicenseInfo:firstyear=2003&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - - -/* -#import "llcrashloggermacdelegate.h" -#include - -extern std::string gUserNotes; -extern bool gSendReport; -extern bool gRememberChoice; - -@implementation LLCrashLoggerMacDelegate - -- (void)setWindow:(NSWindow *)window -{ - _window = window; -} - -- (NSWindow *)window -{ - return _window; -} - -- (void)dealloc -{ - [super dealloc]; -} - -std::string* NSToString( NSString *ns_str ) -{ - return ( new std::string([ns_str UTF8String]) ); -} - -- (IBAction)remember:(id)sender -{ - gRememberChoice = [rememberCheck state]; -} - -- (IBAction)send:(id)sender -{ - std::string* user_input = NSToString([crashText stringValue]); - gUserNotes = *user_input; - gSendReport = true; -} - -- (IBAction)cancel:(id)sender -{ - [ _window close]; -} -@end -*/ diff --git a/indra/mac_crash_logger/mac_crash_logger.cpp b/indra/mac_crash_logger/mac_crash_logger.cpp deleted file mode 100644 index 66d8cfa590..0000000000 --- a/indra/mac_crash_logger/mac_crash_logger.cpp +++ /dev/null @@ -1,57 +0,0 @@ -/** - * @file mac_crash_logger.cpp - * @brief Mac OSX crash logger implementation - * - * $LicenseInfo:firstyear=2003&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#include "linden_common.h" -#include "llcrashloggermac.h" -#include "indra_constants.h" - -#include - -int main(int argc, char **argv) -{ - LLCrashLoggerMac app; - app.parseCommandOptions(argc, argv); - - LLSD options = LLApp::instance()->getOptionData( - LLApp::PRIORITY_COMMAND_LINE); - - if (! app.init()) - { - LL_WARNS() << "Unable to initialize application." << LL_ENDL; - return 1; - } - - if (app.getCrashBehavior() != CRASH_BEHAVIOR_ALWAYS_SEND) - { -// return NSApplicationMain(argc, (const char **)argv); - } - app.frame(); - app.cleanup(); - - LL_INFOS() << "Crash reporter finished normally." << LL_ENDL; - - return 0; -} diff --git a/indra/media_plugins/cef/CMakeLists.txt b/indra/media_plugins/cef/CMakeLists.txt index d53252f198..a846c04626 100644 --- a/indra/media_plugins/cef/CMakeLists.txt +++ b/indra/media_plugins/cef/CMakeLists.txt @@ -5,7 +5,6 @@ project(media_plugin_cef) include(Boost) include(00-Common) include(LLCommon) -include(LLImage) include(LLPlugin) include(LLMath) include(LLRender) @@ -13,7 +12,6 @@ include(LLWindow) include(Linking) include(PluginAPI) include(MediaPluginBase) -include(OpenGL) include(CEFPlugin) @@ -22,7 +20,6 @@ include_directories( ${MEDIA_PLUGIN_BASE_INCLUDE_DIRS} ${LLCOMMON_INCLUDE_DIRS} ${LLMATH_INCLUDE_DIRS} - ${LLIMAGE_INCLUDE_DIRS} ${LLRENDER_INCLUDE_DIRS} ${LLWINDOW_INCLUDE_DIRS} ${CEF_INCLUDE_DIR} diff --git a/indra/media_plugins/cef/media_plugin_cef.cpp b/indra/media_plugins/cef/media_plugin_cef.cpp index 00c707af39..7dbceba2d8 100644 --- a/indra/media_plugins/cef/media_plugin_cef.cpp +++ b/indra/media_plugins/cef/media_plugin_cef.cpp @@ -29,7 +29,7 @@ #include "linden_common.h" #include "indra_constants.h" // for indra keyboard codes -#include "llgl.h" +#include "llglheaders.h" // for GL_* constants #include "llsdutil.h" #include "llplugininstance.h" #include "llpluginmessage.h" @@ -37,9 +37,6 @@ #include "volume_catcher.h" #include "media_plugin_base.h" -#include -#include - #include "dullahan.h" #include "dullahan_version.h" @@ -66,7 +63,7 @@ private: void onTooltipCallback(std::string text); void onLoadStartCallback(); void onRequestExitCallback(); - void onLoadEndCallback(int httpStatusCode); + void onLoadEndCallback(int httpStatusCode, std::string url); void onLoadError(int status, const std::string error_text); void onAddressChangeCallback(std::string url); void onOpenPopupCallback(std::string url, std::string target); @@ -93,6 +90,8 @@ private: bool mDisableGPU; bool mDisableNetworkService; bool mUseMockKeyChain; + bool mDisableWebSecurity; + bool mFileAccessFromFileUrls; std::string mUserAgentSubtring; std::string mAuthUsername; std::string mAuthPassword; @@ -128,6 +127,8 @@ MediaPluginBase(host_send_func, host_user_data) mDisableGPU = false; mDisableNetworkService = true; mUseMockKeyChain = true; + mDisableWebSecurity = false; + mFileAccessFromFileUrls = false; mUserAgentSubtring = ""; mAuthUsername = ""; mAuthPassword = ""; @@ -141,10 +142,6 @@ MediaPluginBase(host_send_func, host_user_data) mPickedFiles.clear(); mCurVolume = 0.0; -#ifdef LL_LINUX - mDisableGPU = true; -#endif - mCEFLib = new dullahan(); setVolume(); @@ -265,13 +262,14 @@ void MediaPluginCEF::onRequestExitCallback() //////////////////////////////////////////////////////////////////////////////// // -void MediaPluginCEF::onLoadEndCallback(int httpStatusCode) +void MediaPluginCEF::onLoadEndCallback(int httpStatusCode, std::string url) { LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "navigate_complete"); //message.setValue("uri", event.getEventUri()); // not easily available here in CEF - needed? message.setValueS32("result_code", httpStatusCode); message.setValueBoolean("history_back_available", mCEFLib->canGoBack()); message.setValueBoolean("history_forward_available", mCEFLib->canGoForward()); + message.setValue("uri", url); sendMessage(message); } @@ -360,14 +358,16 @@ const std::vector MediaPluginCEF::onFileDialog(dullahan::EFileDialo } else if (dialog_type == dullahan::FD_SAVE_FILE) { + mPickedFiles.clear(); mAuthOK = false; LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "file_download"); + message.setValueBoolean("blocking_request", true); message.setValue("filename", default_file); sendMessage(message); - return std::vector(); + return mPickedFiles; } return std::vector(); @@ -528,7 +528,7 @@ void MediaPluginCEF::receiveMessage(const char* message_string) mCEFLib->setOnTitleChangeCallback(std::bind(&MediaPluginCEF::onTitleChangeCallback, this, std::placeholders::_1)); mCEFLib->setOnTooltipCallback(std::bind(&MediaPluginCEF::onTooltipCallback, this, std::placeholders::_1)); mCEFLib->setOnLoadStartCallback(std::bind(&MediaPluginCEF::onLoadStartCallback, this)); - mCEFLib->setOnLoadEndCallback(std::bind(&MediaPluginCEF::onLoadEndCallback, this, std::placeholders::_1)); + mCEFLib->setOnLoadEndCallback(std::bind(&MediaPluginCEF::onLoadEndCallback, this, std::placeholders::_1, std::placeholders::_2)); mCEFLib->setOnLoadErrorCallback(std::bind(&MediaPluginCEF::onLoadError, this, std::placeholders::_1, std::placeholders::_2)); mCEFLib->setOnAddressChangeCallback(std::bind(&MediaPluginCEF::onAddressChangeCallback, this, std::placeholders::_1)); mCEFLib->setOnOpenPopupCallback(std::bind(&MediaPluginCEF::onOpenPopupCallback, this, std::placeholders::_1, std::placeholders::_2)); @@ -567,6 +567,19 @@ void MediaPluginCEF::receiveMessage(const char* message_string) settings.disable_network_service = mDisableNetworkService; settings.use_mock_keychain = mUseMockKeyChain; #endif + // these were added to facilitate loading images directly into a local + // web page for the prototype 360 project in 2017 - something that is + // disallowed normally by the browser security model. Now the the source + // (cubemap) images are stores as JavaScript, we can avoid opening up + // this security hole (it was only set for the 360 floater but still + // a concern). Leaving them here, explicitly turn off vs removing + // entirely from this source file so that others are aware of them + // in the future. + settings.disable_web_security = false; + settings.file_access_from_file_urls = false; + + settings.flash_enabled = mPluginsEnabled; + // This setting applies to all plugins, not just Flash // Regarding, SL-15559 PDF files do not load in CEF v91, // it turns out that on Windows, PDF support is treated @@ -695,6 +708,11 @@ void MediaPluginCEF::receiveMessage(const char* message_string) std::string uri = message_in.getValue("uri"); mCEFLib->navigate(uri); } + else if (message_name == "execute_javascript") + { + std::string code = message_in.getValue("code"); + mCEFLib->executeJavaScript(code); + } else if (message_name == "set_cookie") { std::string uri = message_in.getValue("uri"); @@ -891,6 +909,14 @@ void MediaPluginCEF::receiveMessage(const char* message_string) { mDisableGPU = message_in.getValueBoolean("disable"); } + else if (message_name == "web_security_disabled") + { + mDisableWebSecurity = message_in.getValueBoolean("disabled"); + } + else if (message_name == "file_access_from_file_urls") + { + mFileAccessFromFileUrls = message_in.getValueBoolean("enabled"); + } } else if (message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME) { diff --git a/indra/media_plugins/libvlc/media_plugin_libvlc.cpp b/indra/media_plugins/libvlc/media_plugin_libvlc.cpp index f7d35b33c2..1afe25e9a1 100644 --- a/indra/media_plugins/libvlc/media_plugin_libvlc.cpp +++ b/indra/media_plugins/libvlc/media_plugin_libvlc.cpp @@ -34,6 +34,11 @@ #include "llpluginmessageclasses.h" #include "media_plugin_base.h" +#if defined(_MSC_VER) +#include +typedef SSIZE_T ssize_t; +#endif + #include "vlc/vlc.h" #include "vlc/libvlc_version.h" @@ -278,35 +283,16 @@ void MediaPluginLibVLC::playMedia() return; } + // A new call to play the media is received after the initial one. Typically + // this is due to a size change request either as the media naturally resizes + // to the size of the prim container, or else, as a 2D window is resized by the + // user. Stopping the media, helps avoid a race condition where the media pixel + // buffer size is out of sync with the declared size (width/height) for a frame + // or two and the plugin crashes as VLC tries to decode a frame into unallocated + // memory. if (mLibVLCMediaPlayer) { - // stop listening to events while we reset things - libvlc_event_manager_t* em = libvlc_media_player_event_manager(mLibVLCMediaPlayer); - if (em) - { - libvlc_event_detach(em, libvlc_MediaPlayerOpening, eventCallbacks, NULL); - libvlc_event_detach(em, libvlc_MediaPlayerPlaying, eventCallbacks, NULL); - libvlc_event_detach(em, libvlc_MediaPlayerPaused, eventCallbacks, NULL); - libvlc_event_detach(em, libvlc_MediaPlayerStopped, eventCallbacks, NULL); - libvlc_event_detach(em, libvlc_MediaPlayerEndReached, eventCallbacks, NULL); - libvlc_event_detach(em, libvlc_MediaPlayerEncounteredError, eventCallbacks, NULL); - libvlc_event_detach(em, libvlc_MediaPlayerTimeChanged, eventCallbacks, NULL); - libvlc_event_detach(em, libvlc_MediaPlayerPositionChanged, eventCallbacks, NULL); - libvlc_event_detach(em, libvlc_MediaPlayerLengthChanged, eventCallbacks, NULL); - libvlc_event_detach(em, libvlc_MediaPlayerTitleChanged, eventCallbacks, NULL); - }; - libvlc_media_player_stop(mLibVLCMediaPlayer); - libvlc_media_player_release(mLibVLCMediaPlayer); - - mLibVLCMediaPlayer = 0; - } - - if (mLibVLCMedia) - { - libvlc_media_release(mLibVLCMedia); - - mLibVLCMedia = 0; } mLibVLCMedia = libvlc_media_new_location(mLibVLC, mURL.c_str()); @@ -340,6 +326,9 @@ void MediaPluginLibVLC::playMedia() libvlc_event_attach(em, libvlc_MediaPlayerTitleChanged, eventCallbacks, this); } + libvlc_video_set_callbacks(mLibVLCMediaPlayer, lock, unlock, display, &mLibVLCCallbackContext); + libvlc_video_set_format(mLibVLCMediaPlayer, "RV32", mWidth, mHeight, mWidth * mDepth); + mLibVLCCallbackContext.parent = this; mLibVLCCallbackContext.texture_pixels = mPixels; mLibVLCCallbackContext.mp = mLibVLCMediaPlayer; @@ -361,14 +350,11 @@ void MediaPluginLibVLC::playMedia() setStatus(STATUS_LOADED); - libvlc_video_set_callbacks(mLibVLCMediaPlayer, lock, unlock, display, &mLibVLCCallbackContext); - libvlc_video_set_format(mLibVLCMediaPlayer, "RV32", mWidth, mHeight, mWidth * mDepth); - // note this relies on the "set_loop" message arriving before the "start" (play) one // but that appears to always be the case if (mIsLooping) { - libvlc_media_add_option(mLibVLCMedia, "input-repeat=-1"); + libvlc_media_add_option(mLibVLCMedia, "input-repeat=65535"); } libvlc_media_player_play(mLibVLCMediaPlayer); diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index 9170669f64..ef91073f27 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -12,12 +12,14 @@ include(bugsplat) include(BuildPackagesInfo) include(BuildVersion) include(CMakeCopyIfDifferent) +include(CubemapToEquirectangularJS) include(DBusGlib) include(DragDrop) include(EXPAT) include(FMODSTUDIO) include(GLOD) include(Hunspell) +include(JPEGEncoderBasic) include(JsonCpp) include(LLAppearance) include(LLAudio) @@ -47,6 +49,7 @@ include(OpenGL) include(OpenSSL) include(PNG) include(TemplateCheck) +include(ThreeJS) include(UI) include(UnixInstall) include(ViewerMiscLibs) @@ -314,6 +317,7 @@ set(viewer_SOURCE_FILES llfilteredwearablelist.cpp llfirstuse.cpp llflexibleobject.cpp + llfloater360capture.cpp llfloaterabout.cpp llfloaterbvhpreview.cpp llfloateraddpaymentmethod.cpp @@ -388,7 +392,7 @@ set(viewer_SOURCE_FILES llfloaternamedesc.cpp llfloaternotificationsconsole.cpp llfloaternotificationstabbed.cpp - llfloateroutfitphotopreview.cpp + llfloateroutfitphotopreview.cpp llfloateroutfitsnapshot.cpp llfloaterobjectweights.cpp llfloateropenobject.cpp @@ -397,9 +401,12 @@ set(viewer_SOURCE_FILES llfloaterpathfindinglinksets.cpp llfloaterpathfindingobjects.cpp llfloaterpay.cpp + # llfloaterperformance.cpp replaced with fs version due to large changes and likelihood that LL version will not release. + fsfloaterperformance.cpp llfloaterperms.cpp llfloaterpostprocess.cpp llfloaterpreference.cpp + # llfloaterpreferencesgraphicsadvanced.cpp llfloaterpreferenceviewadvanced.cpp llfloaterpreviewtrash.cpp llfloaterproperties.cpp @@ -1090,6 +1097,7 @@ set(viewer_HEADER_FILES llfilteredwearablelist.h llfirstuse.h llflexibleobject.h + llfloater360capture.h llfloaterabout.h llfloaterbvhpreview.h llfloateraddpaymentmethod.h @@ -1176,9 +1184,12 @@ set(viewer_HEADER_FILES llfloaterpathfindinglinksets.h llfloaterpathfindingobjects.h llfloaterpay.h + # llfloaterperformance.h replaced with fs version due to large changes and likelihood that LL version will not release. + fsfloaterperformance.h llfloaterperms.h llfloaterpostprocess.h llfloaterpreference.h + # llfloaterpreferencesgraphicsadvanced.h llfloaterpreferenceviewadvanced.h llfloaterpreviewtrash.h llfloaterproperties.h @@ -1678,6 +1689,10 @@ configure_file( list(APPEND viewer_HEADER_FILES ${CMAKE_CURRENT_BINARY_DIR}/fsversionvalues.h) # + # Performance stast support + list(APPEND viewer_SOURCE_FILES fsperfstats.cpp) + list(APPEND viewer_HEADER_FILES fsperfstats.h) + # source_group("CMake Rules" FILES ViewerInstall.cmake) #build_data.json creation moved to viewer_manifest.py MAINT-6413 @@ -1686,7 +1701,7 @@ file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/viewer_version.txt" "${VIEWER_SHORT_VERSION}.${VIEWER_VERSION_REVISION}\n") set_source_files_properties( - llversioninfo.cpp tests/llversioninfo_test.cpp + llversioninfo.cpp tests/llversioninfo_test.cpp PROPERTIES # The next line causes a full rebuild of the entire newview # directory every time the Mercurial revision number changes. @@ -2273,10 +2288,6 @@ if (WINDOWS) ${GOOGLE_PERF_TOOLS_SOURCE} ${CMAKE_CURRENT_SOURCE_DIR}/licenses-win32.txt ${CMAKE_CURRENT_SOURCE_DIR}/featuretable.txt - ${ARCH_PREBUILT_DIRS_RELEASE}/libeay32.dll - ${ARCH_PREBUILT_DIRS_RELEASE}/ssleay32.dll - ${ARCH_PREBUILT_DIRS_DEBUG}/libeay32.dll - ${ARCH_PREBUILT_DIRS_DEBUG}/ssleay32.dll ${viewer_APPSETTINGS_FILES} ${ARCH_PREBUILT_DIRS_RELEASE}/growl.dll SLPlugin @@ -2303,11 +2314,15 @@ if (WINDOWS) list(APPEND COPY_INPUT_DEPENDENCIES ${SHARED_LIB_STAGING_DIR}/${CMAKE_CFG_INTDIR}/vivoxsdk_x64.dll ${SHARED_LIB_STAGING_DIR}/${CMAKE_CFG_INTDIR}/ortp_x64.dll + ${ARCH_PREBUILT_DIRS_RELEASE}/libcrypto-1_1-x64.dll + ${ARCH_PREBUILT_DIRS_RELEASE}/libssl-1_1-x64.dll ) else (ADDRESS_SIZE EQUAL 64) list(APPEND COPY_INPUT_DEPENDENCIES ${SHARED_LIB_STAGING_DIR}/${CMAKE_CFG_INTDIR}/vivoxsdk.dll ${SHARED_LIB_STAGING_DIR}/${CMAKE_CFG_INTDIR}/ortp.dll + ${ARCH_PREBUILT_DIRS_RELEASE}/libcrypto-1_1.dll + ${ARCH_PREBUILT_DIRS_RELEASE}/libssl-1_1.dll ) endif (ADDRESS_SIZE EQUAL 64) @@ -2361,12 +2376,10 @@ if (WINDOWS) if (EXISTS ${CMAKE_SOURCE_DIR}/copy_win_scripts) add_dependencies(${VIEWER_BINARY_NAME} copy_win_scripts) endif (EXISTS ${CMAKE_SOURCE_DIR}/copy_win_scripts) - - add_dependencies(${VIEWER_BINARY_NAME} SLPlugin) - if (NOT USE_BUGSPLAT) - add_dependencies(${VIEWER_BINARY_NAME} windows-crash-logger) - endif (NOT USE_BUGSPLAT) + add_dependencies(${VIEWER_BINARY_NAME} + SLPlugin + ) # sets the 'working directory' for debugging from visual studio. # Condition for version can be moved to requirements once build agents will be updated (see TOOL-3865) @@ -2458,7 +2471,7 @@ endif (WINDOWS) # one of these being libz where you can find four or more versions in play # at once. On Linux, libz can be found at link and run time via a number # of paths: -# +# # => -lfreetype # => libz.so.1 (on install machine, not build) # => -lSDL @@ -2564,7 +2577,7 @@ if (NOT ENABLE_MEDIA_PLUGINS) else (NOT ENABLE_MEDIA_PLUGINS) set(COPY_INPUT_DEPENDENCIES ${VIEWER_BINARY_NAME} - linux-crash-logger + #linux-crash-logger SLPlugin media_plugin_cef #media_plugin_gstreamer010 @@ -2572,10 +2585,6 @@ else (NOT ENABLE_MEDIA_PLUGINS) ) endif (NOT ENABLE_MEDIA_PLUGINS) - if (NOT USE_BUGSPLAT) - LIST(APPEND COPY_INPUT_DEPENDENCIES linux-crash-logger) - endif (NOT USE_BUGSPLAT) - add_custom_command( OUTPUT ${product}.tar.bz2 COMMAND ${PYTHON_EXECUTABLE} @@ -2670,7 +2679,7 @@ if (DARWIN) # https://blog.kitware.com/upcoming-in-cmake-2-8-12-osx-rpath-support/ set(CMAKE_MACOSX_RPATH 1) - + set_target_properties( ${VIEWER_BINARY_NAME} PROPERTIES @@ -2680,10 +2689,8 @@ if (DARWIN) # SIGH, as of 2018-05-24 (cmake 3.11.1) the INSTALL_RPATH property simply # does not work. Try this: LINK_FLAGS "-rpath @loader_path/../Frameworks" - MACOSX_BUNDLE_INFO_PLIST - # Use Firestorm plist - #"${CMAKE_CURRENT_SOURCE_DIR}/Info-SecondLife.plist" - "${CMAKE_CURRENT_SOURCE_DIR}/Info-Firestorm.plist" + MACOSX_BUNDLE_INFO_PLIST "${CMAKE_CURRENT_SOURCE_DIR}/Info-Firestorm.plist" + XCODE_ATTRIBUTE_PRODUCT_BUNDLE_IDENTIFIER "${MACOSX_BUNDLE_GUI_IDENTIFIER}" ) set(VIEWER_APP_BUNDLE "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/${product}.app") @@ -2726,10 +2733,6 @@ if (DARWIN) add_dependencies(${VIEWER_BINARY_NAME} SLPlugin media_plugin_libvlc media_plugin_cef) - if (NOT USE_BUGSPLAT) - add_dependencies(${VIEWER_BINARY_NAME} mac-crash-logger) - endif (NOT USE_BUGSPLAT) - if (ENABLE_SIGNING) set(SIGNING_SETTING "--signature=${SIGNING_IDENTITY}") else (ENABLE_SIGNING) @@ -2772,63 +2775,7 @@ endif (INSTALL) # Note that the conventional VIEWER_SYMBOL_FILE is set by ../../build.sh if (PACKAGE AND (RELEASE_CRASH_REPORTING OR NON_RELEASE_CRASH_REPORTING) AND VIEWER_SYMBOL_FILE) - if (NOT USE_BUGSPLAT) - # Breakpad symbol-file generation - set(SYMBOL_SEARCH_DIRS "") - if (WINDOWS) - list(APPEND SYMBOL_SEARCH_DIRS "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}") - # slplugin.exe failing symbols dump - need to debug, might have to do with updated version of google breakpad - # set(VIEWER_EXE_GLOBS "${VIEWER_BINARY_NAME}${CMAKE_EXECUTABLE_SUFFIX} slplugin.exe") - set(VIEWER_EXE_GLOBS "${VIEWER_BINARY_NAME}${CMAKE_EXECUTABLE_SUFFIX}") - set(VIEWER_LIB_GLOB "*${CMAKE_SHARED_MODULE_SUFFIX}") - set(VIEWER_COPY_MANIFEST copy_w_viewer_manifest) - endif (WINDOWS) - if (DARWIN) - list(APPEND SYMBOL_SEARCH_DIRS "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}") - # *TODO: Generate these search dirs in the cmake files related to each binary. - list(APPEND SYMBOL_SEARCH_DIRS "${CMAKE_BINARY_DIR}/llplugin/slplugin/${CMAKE_CFG_INTDIR}") - list(APPEND SYMBOL_SEARCH_DIRS "${CMAKE_BINARY_DIR}/mac_crash_logger/${CMAKE_CFG_INTDIR}") - list(APPEND SYMBOL_SEARCH_DIRS "${CMAKE_BINARY_DIR}/media_plugins/gstreamer010/${CMAKE_CFG_INTDIR}") -## set(VIEWER_EXE_GLOBS "'${product}' SLPlugin") - set(VIEWER_EXE_GLOBS "'${product}' mac-crash-logger") - set(VIEWER_LIB_GLOB "*.dylib") - endif (DARWIN) - if (LINUX) - list(APPEND SYMBOL_SEARCH_DIRS "${CMAKE_CURRENT_BINARY_DIR}/packaged") -## set(VIEWER_EXE_GLOBS "do-not-directly-run-secondlife-bin SLPlugin") - set(VIEWER_EXE_GLOBS "do-not-directly-run-firestorm-bin") - set(VIEWER_LIB_GLOB "*${CMAKE_SHARED_MODULE_SUFFIX}*") - set(VIEWER_COPY_MANIFEST copy_l_viewer_manifest) - endif (LINUX) - - if(CMAKE_CFG_INTDIR STREQUAL ".") - set(LLBUILD_CONFIG ${CMAKE_BUILD_TYPE}) - else(CMAKE_CFG_INTDIR STREQUAL ".") - # set LLBUILD_CONFIG to be a shell variable evaluated at build time - # reflecting the configuration we are currently building. - set(LLBUILD_CONFIG ${CMAKE_CFG_INTDIR}) - endif(CMAKE_CFG_INTDIR STREQUAL ".") - add_custom_command(OUTPUT "${VIEWER_SYMBOL_FILE}" - COMMAND "${PYTHON_EXECUTABLE}" - ARGS - "${CMAKE_CURRENT_SOURCE_DIR}/generate_breakpad_symbols.py" - "${LLBUILD_CONFIG}" - "${SYMBOL_SEARCH_DIRS}" - "${VIEWER_EXE_GLOBS}" - "${VIEWER_LIB_GLOB}" - "${AUTOBUILD_INSTALL_DIR}/bin/dump_syms" - "${VIEWER_SYMBOL_FILE}" - DEPENDS generate_breakpad_symbols.py - VERBATIM) - - add_custom_target(generate_breakpad_symbols DEPENDS "${VIEWER_SYMBOL_FILE}" "${VIEWER_BINARY_NAME}" "${VIEWER_COPY_MANIFEST}") - add_custom_target(generate_symbols DEPENDS "${VIEWER_SYMBOL_FILE}") - add_dependencies(generate_symbols ${VIEWER_BINARY_NAME}) - if (WINDOWS OR LINUX) - add_dependencies(generate_symbols "${VIEWER_COPY_MANIFEST}") - endif (WINDOWS OR LINUX) - - else (NOT USE_BUGSPLAT) + if (USE_BUGSPLAT) # BugSplat symbol-file generation if (WINDOWS) # Just pack up a tarball containing only the .pdb file for the @@ -2912,7 +2859,7 @@ if (PACKAGE AND (RELEASE_CRASH_REPORTING OR NON_RELEASE_CRASH_REPORTING) AND VIE if (LINUX) # TBD endif (LINUX) - endif (NOT USE_BUGSPLAT) + endif (USE_BUGSPLAT) # for both Bugsplat and Breakpad add_dependencies(llpackage generate_symbols) @@ -2938,7 +2885,7 @@ if (LL_TESTS) llworldmap.cpp llworldmipmap.cpp PROPERTIES - LL_TEST_ADDITIONAL_SOURCE_FILES + LL_TEST_ADDITIONAL_SOURCE_FILES tests/llviewertexture_stub.cpp #llviewertexturelist.cpp ) @@ -2981,7 +2928,7 @@ if (LL_TESTS) llworldmap.cpp llworldmipmap.cpp PROPERTIES - LL_TEST_ADDITIONAL_SOURCE_FILES + LL_TEST_ADDITIONAL_SOURCE_FILES tests/llviewertexture_stub.cpp #llviewertexturelist.cpp LL_TEST_ADDITIONAL_LIBRARIES "${BOOST_SYSTEM_LIBRARY}" diff --git a/indra/newview/Info-Firestorm.plist b/indra/newview/Info-Firestorm.plist index 18341c8860..2b0e24e92e 100644 --- a/indra/newview/Info-Firestorm.plist +++ b/indra/newview/Info-Firestorm.plist @@ -11,7 +11,7 @@ CFBundleIconFile ${MACOSX_BUNDLE_ICON_FILE} CFBundleIdentifier - ${MACOSX_BUNDLE_GUI_IDENTIFIER} + ${PRODUCT_BUNDLE_IDENTIFIER} CFBundleInfoDictionaryVersion 6.0 CFBundleLongVersionString diff --git a/indra/newview/Info-SecondLife.plist b/indra/newview/Info-SecondLife.plist index cfe9d991c5..09b0e1ec1b 100644 --- a/indra/newview/Info-SecondLife.plist +++ b/indra/newview/Info-SecondLife.plist @@ -11,7 +11,7 @@ CFBundleIconFile ${MACOSX_BUNDLE_ICON_FILE} CFBundleIdentifier - ${MACOSX_BUNDLE_GUI_IDENTIFIER} + $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleLongVersionString diff --git a/indra/newview/installers/darwin/firestorm-beta-dmg/LGPL-license.txt b/indra/newview/LGPL-license.txt similarity index 100% rename from indra/newview/installers/darwin/firestorm-beta-dmg/LGPL-license.txt rename to indra/newview/LGPL-license.txt diff --git a/indra/newview/NACLantispam.cpp b/indra/newview/NACLantispam.cpp index 5fee4d0621..a72bbbffc8 100644 --- a/indra/newview/NACLantispam.cpp +++ b/indra/newview/NACLantispam.cpp @@ -10,7 +10,6 @@ #include "llviewerobjectlist.h" #include "llviewerregion.h" #include "llworld.h" -#include "sound_ids.h" #include #include @@ -207,11 +206,6 @@ NACLAntiSpamRegistry::NACLAntiSpamRegistry() : { mQueues[queue] = new NACLAntiSpamQueue(mGlobalTime, mGlobalAmount); } - - for (S32 i = 0; i < COLLISION_SOUNDS_SIZE; ++i) - { - mCollisionSounds.insert(LLUUID(COLLISION_SOUNDS[i])); - } } NACLAntiSpamRegistry::~NACLAntiSpamRegistry() @@ -640,11 +634,6 @@ void NACLAntiSpamRegistry::purgeGlobalEntries() mGlobalEntries.clear(); } -bool NACLAntiSpamRegistry::isCollisionSound(const LLUUID& sound_id) -{ - return (mCollisionSounds.find(sound_id) != mCollisionSounds.end()); -} - void NACLAntiSpamRegistry::processObjectPropertiesFamily(LLMessageSystem* msg) { static LLCachedControl useAntiSpam(gSavedSettings, "UseAntiSpam"); diff --git a/indra/newview/NACLantispam.h b/indra/newview/NACLantispam.h index 870bcf7e8a..d5cf7889a6 100644 --- a/indra/newview/NACLantispam.h +++ b/indra/newview/NACLantispam.h @@ -113,8 +113,6 @@ public: void clearAllQueues(); void purgeAllQueues(); - bool isCollisionSound(const LLUUID& sound_id); - void processObjectPropertiesFamily(LLMessageSystem* msg); private: diff --git a/indra/newview/VIEWER_VERSION.txt b/indra/newview/VIEWER_VERSION.txt index 4c8366c864..5e3ec53ea6 100644 --- a/indra/newview/VIEWER_VERSION.txt +++ b/indra/newview/VIEWER_VERSION.txt @@ -1 +1 @@ -6.4.23 +6.5.2 diff --git a/indra/newview/ao.cpp b/indra/newview/ao.cpp index a0e3077d62..f7a8f3f7e3 100644 --- a/indra/newview/ao.cpp +++ b/indra/newview/ao.cpp @@ -178,6 +178,7 @@ void FloaterAO::updateList() } } + U32 selected_index = 0; for (U32 index = 0; index < mSetList.size(); ++index) { std::string setName = mSetList[index]->getName(); @@ -185,13 +186,16 @@ void FloaterAO::updateList() mSetSelectorSmall->add(setName, &mSetList[index], ADD_BOTTOM, TRUE); if (setName.compare(currentSetName) == 0) { + selected_index = index; mSelectedSet = AOEngine::instance().selectSetByName(currentSetName); - mSetSelector->selectNthItem(index); - mSetSelectorSmall->selectNthItem(index); updateSetParameters(); updateAnimationList(); } } + + mSetSelector->selectNthItem(selected_index); + mSetSelectorSmall->selectNthItem(selected_index); + enableSetControls(TRUE); if (mSetSelector->getSelectedItemLabel().empty()) { @@ -428,7 +432,7 @@ LLScrollListItem* FloaterAO::addAnimation(const std::string& name) LLSD row; row["columns"][0]["column"] = "icon"; row["columns"][0]["type"] = "icon"; - row["columns"][0]["value"] = "Inv_Animation"; + row["columns"][0]["value"] = "FSAO_Animation_Stopped"; row["columns"][1]["column"] = "animation_name"; row["columns"][1]["type"] = "text"; @@ -466,6 +470,15 @@ void FloaterAO::onSelectState() if (item) { item->setUserdata(&mSelectedState->mAnimations[index].mInventoryUUID); + + // update currently playing animation if we are looking at the currently running state in the UI + if (mSelectedSet->getMotion() == mSelectedState->mRemapID && + mSelectedState->mCurrentAnimationID == mSelectedState->mAnimations[index].mAssetUUID) + { + mCurrentBoldItem = item; + ((LLScrollListIcon*)item->getColumn(0))->setValue("FSAO_Animation_Playing"); + ((LLScrollListText*)item->getColumn(1))->setFontStyle(LLFontGL::BOLD); + } } } @@ -809,8 +822,8 @@ void FloaterAO::onAnimationChanged(const LLUUID& animation) if (mCurrentBoldItem) { - LLScrollListText* column = (LLScrollListText*)mCurrentBoldItem->getColumn(1); - column->setFontStyle(LLFontGL::NORMAL); + ((LLScrollListIcon*)mCurrentBoldItem->getColumn(0))->setValue("FSAO_Animation_Stopped"); + ((LLScrollListText*)mCurrentBoldItem->getColumn(1))->setFontStyle(LLFontGL::NORMAL); mCurrentBoldItem = nullptr; } @@ -832,8 +845,8 @@ void FloaterAO::onAnimationChanged(const LLUUID& animation) { mCurrentBoldItem = item; - LLScrollListText* column = (LLScrollListText*)mCurrentBoldItem->getColumn(1); - column->setFontStyle(LLFontGL::BOLD); + ((LLScrollListIcon*)mCurrentBoldItem->getColumn(0))->setValue("FSAO_Animation_Playing"); + ((LLScrollListText*)mCurrentBoldItem->getColumn(1))->setFontStyle(LLFontGL::BOLD); return; } diff --git a/indra/newview/aoengine.cpp b/indra/newview/aoengine.cpp index 0176d38959..d9f39434fc 100644 --- a/indra/newview/aoengine.cpp +++ b/indra/newview/aoengine.cpp @@ -373,7 +373,7 @@ void AOEngine::enableStands(bool enable_stands) void AOEngine::enable(bool enable) { - LL_DEBUGS("AOEngine") << "using " << mLastMotion << " enable " << enable << LL_ENDL; + LL_DEBUGS("AOEngine") << "using " << gAnimLibrary.animationName(mLastMotion) << " enable " << enable << LL_ENDL; mEnabled = enable; if (!mCurrentSet) @@ -390,7 +390,9 @@ void AOEngine::enable(bool enable) LL_DEBUGS("AOEngine") << "Enabling animation state " << state->mName << LL_ENDL; // do not stop underlying sit animations when re-enabling the AO - if (mLastOverriddenMotion != ANIM_AGENT_SIT_GROUND_CONSTRAINED && mLastOverriddenMotion != ANIM_AGENT_SIT) + if (mLastOverriddenMotion != ANIM_AGENT_SIT_GROUND && + mLastOverriddenMotion != ANIM_AGENT_SIT_GROUND_CONSTRAINED && + mLastOverriddenMotion != ANIM_AGENT_SIT) { gAgent.sendAnimationRequest(mLastOverriddenMotion, ANIM_REQUEST_STOP); } @@ -435,11 +437,15 @@ void AOEngine::enable(bool enable) } else { - LL_WARNS("AOEngine") << "Unhandled last motion id " << mLastMotion << LL_ENDL; + LL_WARNS("AOEngine") << "Unhandled last motion id " << gAnimLibrary.animationName(mLastMotion) << LL_ENDL; } gAgent.sendAnimationRequest(animation, ANIM_REQUEST_START); mAnimationChangedSignal(state->mAnimations[state->mCurrentAnimation].mInventoryUUID); + + // remember to ignore this motion once in the overrider so stopping the Linden motion + // will not trigger a stop of the override animation + mIgnoreMotionStopOnce = mLastMotion; } } else @@ -493,13 +499,9 @@ void AOEngine::setStateCycleTimer(const AOSet::AOState* state) } } -const LLUUID AOEngine::override(const LLUUID& pMotion, bool start) +const LLUUID AOEngine::override(const LLUUID& motion, bool start) { - LL_DEBUGS("AOEngine") << "override(" << pMotion << "," << start << ")" << LL_ENDL; - - LLUUID animation; - - LLUUID motion = pMotion; + LL_DEBUGS("AOEngine") << "override(" << gAnimLibrary.animationName(motion) << "," << start << ")" << LL_ENDL; if (!mEnabled) { @@ -517,25 +519,37 @@ const LLUUID AOEngine::override(const LLUUID& pMotion, bool start) } } } - return animation; + return LLUUID::null; } if (mSets.empty()) { LL_DEBUGS("AOEngine") << "No sets loaded. Skipping overrider." << LL_ENDL; - return animation; + return LLUUID::null; } if (!mCurrentSet) { LL_DEBUGS("AOEngine") << "No current AO set chosen. Skipping overrider." << LL_ENDL; - return animation; + return LLUUID::null; } - // we don't distinguish between these two - if (motion == ANIM_AGENT_SIT_GROUND) + // ignore stopping this motion once so we can stop the Linden animation + // without killing our overrider when logging in or re-enabling + if (!start && motion == mIgnoreMotionStopOnce) { - motion = ANIM_AGENT_SIT_GROUND_CONSTRAINED; + LL_DEBUGS("AOEngine") << "Not stop-overriding motion " << gAnimLibrary.animationName(motion) + << " within same state." << LL_ENDL; + + mIgnoreMotionStopOnce = LLUUID::null; + + // when stopping a sit motion make sure to stop the cycle point cover-up animation + if (motion == ANIM_AGENT_SIT) + { + gAgent.sendAnimationRequest(ANIM_AGENT_SIT_GENERIC, ANIM_REQUEST_STOP); + } + + return LLUUID::null; } // map the requested motion to an animation state, taking underwater @@ -543,7 +557,7 @@ const LLUUID AOEngine::override(const LLUUID& pMotion, bool start) AOSet::AOState* state = getStateForMotion(motion); if (!state) { - LL_DEBUGS("AOEngine") << "No current AO state for motion " << motion << " (" << gAnimLibrary.animationName(motion) << ")." << LL_ENDL; + LL_DEBUGS("AOEngine") << "No current AO state for motion " << gAnimLibrary.animationName(motion) << LL_ENDL; // This part of the code was added to capture an edge case where animations got stuck // However, it seems it isn't needed anymore and breaks other, more important cases. // So we disable this code for now, unless bad things happen and the stuck animations @@ -562,7 +576,7 @@ const LLUUID AOEngine::override(const LLUUID& pMotion, bool start) // gAgentAvatarp->LLCharacter::stopMotion(motion); // } // } - return animation; + return LLUUID::null; } mAnimationChangedSignal(LLUUID::null); @@ -624,6 +638,8 @@ const LLUUID AOEngine::override(const LLUUID& pMotion, bool start) } } + LLUUID animation; + mCurrentSet->stopTimer(); if (start) { @@ -636,7 +652,7 @@ const LLUUID AOEngine::override(const LLUUID& pMotion, bool start) mInMouselook) { LL_DEBUGS("AOEngine") << "(enabled AO, mouselook stand stopped) setting last motion id to " << gAnimLibrary.animationName(mLastMotion) << LL_ENDL; - return animation; + return LLUUID::null; } // Don't override start and turning stands if stand override is disabled @@ -644,24 +660,24 @@ const LLUUID AOEngine::override(const LLUUID& pMotion, bool start) (motion == ANIM_AGENT_STAND || motion == ANIM_AGENT_TURNRIGHT || motion == ANIM_AGENT_TURNLEFT)) { LL_DEBUGS("AOEngine") << "(enabled AO, stands disabled) setting last motion id to " << gAnimLibrary.animationName(mLastMotion) << LL_ENDL; - return animation; + return LLUUID::null; } // Do not start override sits if not selected if (!mCurrentSet->getSitOverride() && motion == ANIM_AGENT_SIT) { LL_DEBUGS("AOEngine") << "(enabled AO, sit override stopped) setting last motion id to " << gAnimLibrary.animationName(mLastMotion) << LL_ENDL; - return animation; + return LLUUID::null; } // scripted seats that use ground_sit as animation need special treatment - if (motion == ANIM_AGENT_SIT_GROUND_CONSTRAINED) + if (motion == ANIM_AGENT_SIT_GROUND || motion == ANIM_AGENT_SIT_GROUND_CONSTRAINED) { const LLViewerObject* agentRoot = dynamic_cast(gAgentAvatarp->getRoot()); if (agentRoot && agentRoot->getID() != gAgentID) { LL_DEBUGS("AOEngine") << "Ground sit animation playing but sitting on a prim - disabling overrider." << LL_ENDL; - return animation; + return LLUUID::null; } } @@ -677,10 +693,7 @@ const LLUUID AOEngine::override(const LLUUID& pMotion, bool start) mCurrentSet->setMotion(motion); } - if (animation.isNull()) - { - animation = mCurrentSet->getAnimationForState(state); - } + animation = mCurrentSet->getAnimationForState(state); if (state->mCurrentAnimationID.notNull()) { @@ -716,7 +729,8 @@ const LLUUID AOEngine::override(const LLUUID& pMotion, bool start) } } // special treatment for "transient animations" because the viewer needs the Linden animation to know the agent's state - else if (motion == ANIM_AGENT_SIT_GROUND_CONSTRAINED || + else if (motion == ANIM_AGENT_SIT_GROUND || + motion == ANIM_AGENT_SIT_GROUND_CONSTRAINED || motion == ANIM_AGENT_PRE_JUMP || motion == ANIM_AGENT_STANDUP || motion == ANIM_AGENT_LAND || @@ -756,6 +770,13 @@ const LLUUID AOEngine::override(const LLUUID& pMotion, bool start) return animation; } + // stop the underlying Linden Lab motion, in case it's still running. + // frequently happens with sits, so we keep it only for those currently. + if (motion == ANIM_AGENT_SIT) + { + stopAllSitVariants(); + } + if (motion != mCurrentSet->getMotion()) { LL_WARNS("AOEngine") << "trying to stop-override motion " << gAnimLibrary.animationName(motion) @@ -766,7 +787,8 @@ const LLUUID AOEngine::override(const LLUUID& pMotion, bool start) mCurrentSet->setMotion(LLUUID::null); // again, special treatment for "transient" animations to make sure our own animation gets stopped properly - if (motion == ANIM_AGENT_SIT_GROUND_CONSTRAINED || + if (motion == ANIM_AGENT_SIT_GROUND || + motion == ANIM_AGENT_SIT_GROUND_CONSTRAINED || motion == ANIM_AGENT_PRE_JUMP || motion == ANIM_AGENT_STANDUP || motion == ANIM_AGENT_LAND || @@ -777,13 +799,6 @@ const LLUUID AOEngine::override(const LLUUID& pMotion, bool start) setStateCycleTimer(state); return LLUUID::null; } - - // stop the underlying Linden Lab motion, in case it's still running. - // frequently happens with sits, so we keep it only for those currently. - if (mLastMotion == ANIM_AGENT_SIT) - { - stopAllSitVariants(); - } } return animation; diff --git a/indra/newview/aoengine.h b/indra/newview/aoengine.h index 8be4dc0001..a9b5c46686 100644 --- a/indra/newview/aoengine.h +++ b/indra/newview/aoengine.h @@ -205,6 +205,10 @@ class AOEngine LLUUID mLastOverriddenMotion; LLUUID mTransitionId; + // this motion will be ignored once in the overrider when stopping, fixes a case + // where the AO doesn't correctly start up on login or when getting enabled manually + LLUUID mIgnoreMotionStopOnce; + std::vector mSets; std::vector mOldSets; AOSet* mCurrentSet; diff --git a/indra/newview/app_settings/commands.xml b/indra/newview/app_settings/commands.xml index a13da0b23a..2f677d6a12 100644 --- a/indra/newview/app_settings/commands.xml +++ b/indra/newview/app_settings/commands.xml @@ -638,4 +638,25 @@ is_running_function="Floater.IsOpen" is_running_parameters="my_environments" /> + + diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index 658df3f703..78b7632095 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -203,7 +203,7 @@ FSAvatarTurnSpeed Comment - Modify the speed at which the avatar responds to turning movements. 0-100 percent of max rate + Modify the speed at which the avatar responds to turning movements. 0-100 percent of max rate. Default is 0. Persist 1 Type @@ -3187,10 +3187,11 @@ Value 1.0 - CameraPreset + CameraPreset + Comment - Preset camera position - view (0 - rear, 1 - front, 2 - group) + (Deprecated) Preset camera position - view (0 - rear, 1 - front, 2 - group) Persist 1 Type @@ -3719,6 +3720,28 @@ Backup 0 + BrowserFileAccessFromFileUrls + + Comment + Allow access to local files via file urls in the embedded browser + Persist + 1 + Type + Boolean + Value + 1 + + BrowserPluginsEnabled + + Comment + Enable Web plugins in the built-in Web browser? + Persist + 1 + Type + Boolean + Value + 1 + ChatBarCustomWidth Comment @@ -4216,10 +4239,11 @@ Backup 0 - DEPRECATED: DebugShowPrivateMem + DebugShowPrivateMem + Comment - Show Private Mem Info + (Deprecated) Show Private Mem Info Persist 1 Type @@ -5608,7 +5632,7 @@ Value 0 - DoubleClickTeleport + DoubleClickTeleport Comment Enable double-click to teleport where allowed (afects minimap and people panel) @@ -5854,6 +5878,17 @@ Value 1 + EnableCollisionSounds + + Comment + Play sounds on collision + Persist + 1 + Type + Boolean + Value + 1 + EnableMouselook Comment @@ -8171,7 +8206,7 @@ Comment Duration in seconds of the login SRV request timeout Persist - 0 + 1 Type F32 Value @@ -8180,7 +8215,7 @@ LoginSRVPump Comment - Name of the message pump that handles SRV request (deprecated) + (Deprecated) Name of the message pump that handles SRV request) Persist 0 Type @@ -9038,10 +9073,11 @@ Value 600.0 - MemoryPrivatePoolEnabled + MemoryPrivatePoolEnabled + Comment - DEPRECATED: Enable the private memory pool management + (Deprecated) Enable the private memory pool management Persist 1 Type @@ -9051,10 +9087,11 @@ Backup 0 - MemoryPrivatePoolSize + MemoryPrivatePoolSize + Comment - DEPRECATED: Size of the private memory pool in MB (min. value is 256) + (Deprecated) Size of the private memory pool in MB (min. value is 256) Persist 1 Type @@ -11103,7 +11140,7 @@ Change of this parameter will affect the layout of buttons in notification toast Type Boolean Value - 0 + 1 QAMode @@ -11119,7 +11156,7 @@ Change of this parameter will affect the layout of buttons in notification toast QAModeEventHostPort Comment - DEPRECATED: Port on which lleventhost should listen + (Deprecated) Port on which lleventhost should listen Persist 0 Type @@ -11698,7 +11735,7 @@ Change of this parameter will affect the layout of buttons in notification toast Value 0 - RenderHiDPI + RenderHiDPI Comment Enable support for HiDPI displays, like Retina (MacOS X ONLY, requires restart) @@ -15853,6 +15890,17 @@ Change of this parameter will affect the layout of buttons in notification toast Backup 0 + TextureSaveLocation + + Comment + Current location for bulk saving textures to disk + Persist + 0 + Type + String + Value + + ThrottleBandwidthKBPS Comment @@ -17577,10 +17625,11 @@ Change of this parameter will affect the layout of buttons in notification toast Value Default - UseExternalBrowser + UseExternalBrowser + Comment - Use default browser when opening web pages instead of in-world browser. + (Deprecated) Use default browser when opening web pages instead of in-world browser. Persist 1 Type @@ -18087,6 +18136,7 @@ Change of this parameter will affect the layout of buttons in notification toast 0 VoiceCallsRejectGroup + Comment Silently reject all incoming group voice calls. @@ -21838,7 +21888,84 @@ Change of this parameter will affect the layout of buttons in notification toast Boolean Value 0 - + + 360CaptureUseInterestListCap + + Comment + Flag if set, uses the new InterestList cap to ask the simulator for full content + Persist + 1 + Type + Boolean + Value + 1 + + 360CaptureJPEGEncodeQuality + + Comment + Quality value to use in the JPEG encoder (0..100) + Persist + 1 + Type + U32 + Value + 95 + + 360CaptureDebugSaveImage + + Comment + Flag if set, saves off each cube map as an image, as well as the JavaScript data URL, for debugging purposes + Persist + 1 + Type + Boolean + Value + 0 + + 360CaptureOutputImageWidth + + Comment + Width of the output 360 equirectangular image + Persist + 1 + Type + U32 + Value + 4096 + + 360CaptureHideAvatars + + Comment + Flag if set, removes all the avatars from the 360 snapshot + Persist + 1 + Type + Boolean + Value + 0 + + 360CaptureCameraFOV + + Comment + Field of view of the WebGL camera that converts the cubemap to an equirectangular image + Persist + 1 + Type + U32 + Value + 75 + + 360CaptureNumRenderPasses + + Comment + Number of times to render the scene while taking a snapshot + Persist + 1 + Type + U32 + Value + 3 + CefVerboseLog Comment @@ -22504,17 +22631,6 @@ Change of this parameter will affect the layout of buttons in notification toast Value 0 - FSPlayCollisionSounds - - Comment - Play collision sounds. - Persist - 1 - Type - Boolean - Value - 1 - FSFadeAudioStream Comment @@ -25173,6 +25289,17 @@ Change of this parameter will affect the layout of buttons in notification toast Value 0 + FSLinuxEnableWin64VoiceProxy + + Comment + Use Win64 SLVoice.exe for voice. Needs wine (https://www.winehq.org/) installed, as SLVoice.exe is started inside wine. + Persist + 1 + Type + Boolean + Value + 0 + FSStatusBarMenuButtonPopupOnRollover Comment @@ -25701,6 +25828,39 @@ Change of this parameter will affect the layout of buttons in notification toast Value 0 + FSTargetFPS + + Comment + Desired minimum FPS + Persist + 1 + Type + U32 + Value + 25 + + FSAutoTuneFPS + + Comment + Allow the viewer to adjust your settings to achieve target FPS + Persist + 0 + Type + Boolean + Value + 0 + + FSPerfFloaterSmoothingPeriods + + Comment + Number of periods to smooth the stats over + Persist + 1 + Type + U32 + Value + 50 + FSAutoUnmuteSounds Comment @@ -25723,5 +25883,115 @@ Change of this parameter will affect the layout of buttons in notification toast Value 0 + RenderJellyDollsAsImpostors + + Comment + Use an impostor instead of a JellyDoll for better visuals (true) + Persist + 1 + Type + Boolean + Value + 1 + + FSPerfStatsCaptureEnabled + + Comment + Enable/disable render time data to support autotune. + Persist + 1 + Type + Boolean + Value + 1 + + FSAutoTuneImpostorByDistEnabled + + Comment + Enable/disable using MaxNonImpostor to limit avatar rendering by distance. + Persist + 1 + Type + Boolean + Value + 1 + + FSAllowSelfImpostor + + Comment + Allow own render time to impostor your avatar. + Persist + 1 + Type + Boolean + Value + 0 + + FSShowTunedART + + Comment + Show the tuned render time in the avatar display. + Persist + 1 + Type + Boolean + Value + 0 + + FSRenderAvatarMaxART + + Comment + Render Time Limit in microseconds (0.0 = no limit) + Persist + 0 + Type + F32 + Value + 4.699 + + FSAutoTuneRenderFarClipMin + + Comment + The lowest draw distance that auto tune is allowed to use + Persist + 0 + Type + F32 + Value + 32.0 + + FSAutoTuneRenderFarClipTarget + + Comment + The draw distance that auto tune will try to achieve + Persist + 0 + Type + F32 + Value + 256.0 + + FSAutoTuneImpostorFarAwayDistance + + Comment + Avatars beyond this range will automatically be optimized + Persist + 0 + Type + F32 + Value + 64.0 + + FSTuningFPSStrategy + + Comment + Strategy to use when tuning FPS. 0=Tune avatar rendering only, 1=Tune both avatar and global scene settings. + Persist + 1 + Type + U32 + Value + 0 + diff --git a/indra/newview/fsfloaterperformance.cpp b/indra/newview/fsfloaterperformance.cpp new file mode 100644 index 0000000000..c8f5d64d76 --- /dev/null +++ b/indra/newview/fsfloaterperformance.cpp @@ -0,0 +1,1030 @@ +/** + * @file llfloaterperformance.cpp + * + * $LicenseInfo:firstyear=2021&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2021, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" +#include "fsfloaterperformance.h" + +#include "llagent.h" +#include "llagentcamera.h" +#include "llappearancemgr.h" +#include "llavataractions.h" +#include "llavatarrendernotifier.h" +#include "llcheckboxctrl.h" +#include "llfeaturemanager.h" +#include "llfloaterpreference.h" // LLAvatarComplexityControls +#include "llfloaterreg.h" +#include "llmoveview.h" // for LLPanelStandStopFlying +#include "llnamelistctrl.h" +#include "llradiogroup.h" +#include "llselectmgr.h" +#include "llsliderctrl.h" +#include "lltextbox.h" +#include "llcombobox.h" +#include "lltrans.h" +#include "llviewerobjectlist.h" +#include "llviewerjoystick.h" +#include "llviewermediafocus.h" +#include "llvoavatar.h" +#include "llvoavatarself.h" +#include "pipeline.h" +#include "llviewercontrol.h" +#include "fsavatarrenderpersistence.h" +#include "fsperfstats.h" // performance stats support +#include "fslslbridge.h" + +const F32 REFRESH_INTERVAL = 1.0f; +const S32 BAR_LEFT_PAD = 2; +const S32 BAR_RIGHT_PAD = 5; +const S32 BAR_BOTTOM_PAD = 9; + +constexpr auto AvType {FSPerfStats::ObjType_t::OT_AVATAR}; +constexpr auto AttType {FSPerfStats::ObjType_t::OT_ATTACHMENT}; +constexpr auto HudType {FSPerfStats::ObjType_t::OT_HUD}; +constexpr auto SceneType {FSPerfStats::ObjType_t::OT_GENERAL}; +class FSExceptionsContextMenu : public LLListContextMenu +{ +public: + FSExceptionsContextMenu(FSFloaterPerformance* floater_settings) + : mFloaterPerformance(floater_settings) + {} +protected: + LLContextMenu* createMenu() + { + LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar; + LLUICtrl::EnableCallbackRegistry::ScopedRegistrar enable_registrar; + registrar.add("Settings.SetRendering", boost::bind(&FSFloaterPerformance::onCustomAction, mFloaterPerformance, _2, mUUIDs.front())); + enable_registrar.add("Settings.IsSelected", boost::bind(&FSFloaterPerformance::isActionChecked, mFloaterPerformance, _2, mUUIDs.front())); + registrar.add("Avatar.Extended", boost::bind(&FSFloaterPerformance::onExtendedAction, mFloaterPerformance, _2, mUUIDs.front())); + LLContextMenu* menu = createFromFile("menu_perf_avatar_rendering_settings.xml"); + + return menu; + } + + FSFloaterPerformance* mFloaterPerformance; +}; + + + +FSFloaterPerformance::FSFloaterPerformance(const LLSD& key) +: LLFloater(key), + mUpdateTimer(new LLTimer()), + mNearbyMaxComplexity(0) +{ + mContextMenu = new FSExceptionsContextMenu(this); +} + +FSFloaterPerformance::~FSFloaterPerformance() +{ + mComplexityChangedSignal.disconnect(); + delete mContextMenu; + delete mUpdateTimer; +} + +BOOL FSFloaterPerformance::postBuild() +{ + mMainPanel = getChild("panel_performance_main"); + mNearbyPanel = getChild("panel_performance_nearby"); + mComplexityPanel = getChild("panel_performance_complexity"); + mSettingsPanel = getChild("panel_performance_preferences"); + mHUDsPanel = getChild("panel_performance_huds"); + mAutoTunePanel = getChild("panel_performance_autotune"); + + getChild("nearby_subpanel")->setMouseDownCallback(boost::bind(&FSFloaterPerformance::showSelectedPanel, this, mNearbyPanel)); + getChild("complexity_subpanel")->setMouseDownCallback(boost::bind(&FSFloaterPerformance::showSelectedPanel, this, mComplexityPanel)); + getChild("settings_subpanel")->setMouseDownCallback(boost::bind(&FSFloaterPerformance::showSelectedPanel, this, mSettingsPanel)); + getChild("huds_subpanel")->setMouseDownCallback(boost::bind(&FSFloaterPerformance::showSelectedPanel, this, mHUDsPanel)); + + auto tgt_panel = findChild("target_subpanel"); + if (tgt_panel) + { + tgt_panel->getChild("target_btn")->setCommitCallback(boost::bind(&FSFloaterPerformance::showSelectedPanel, this, mAutoTunePanel)); + tgt_panel->getChild("FSTuningFPSStrategy")->setCurrentByIndex(gSavedSettings.getU32("FSTuningFPSStrategy")); + } + + initBackBtn(mNearbyPanel); + initBackBtn(mComplexityPanel); + initBackBtn(mSettingsPanel); + initBackBtn(mHUDsPanel); + initBackBtn(mAutoTunePanel); + + mHUDList = mHUDsPanel->getChild("hud_list"); + mHUDList->setNameListType(LLNameListCtrl::SPECIAL); + mHUDList->setHoverIconName("StopReload_Off"); + mHUDList->setIconClickedCallback(boost::bind(&FSFloaterPerformance::detachItem, this, _1)); + + mObjectList = mComplexityPanel->getChild("obj_list"); + mObjectList->setNameListType(LLNameListCtrl::SPECIAL); + mObjectList->setHoverIconName("StopReload_Off"); + mObjectList->setIconClickedCallback(boost::bind(&FSFloaterPerformance::detachItem, this, _1)); + + mSettingsPanel->getChild("graphics_quality")->setCommitCallback(boost::bind(&FSFloaterPerformance::onChangeQuality, this, _2)); + + mNearbyPanel->getChild("exceptions_btn")->setCommitCallback(boost::bind(&FSFloaterPerformance::onClickExceptions, this)); + mNearbyPanel->getChild("hide_avatars")->setCommitCallback(boost::bind(&FSFloaterPerformance::onClickHideAvatars, this)); + mNearbyPanel->getChild("hide_avatars")->set(!LLPipeline::hasRenderTypeControl(LLPipeline::RENDER_TYPE_AVATAR)); + mNearbyList = mNearbyPanel->getChild("nearby_list"); + mNearbyList->setRightMouseDownCallback(boost::bind(&FSFloaterPerformance::onAvatarListRightClick, this, _1, _2, _3)); + + updateComplexityText(); + mComplexityChangedSignal = gSavedSettings.getControl("RenderAvatarMaxComplexity")->getCommitSignal()->connect(boost::bind(&FSFloaterPerformance::updateComplexityText, this)); + mNearbyPanel->getChild("IndirectMaxComplexity")->setCommitCallback(boost::bind(&FSFloaterPerformance::updateMaxComplexity, this)); + + mMaxARTChangedSignal = gSavedSettings.getControl("FSRenderAvatarMaxART")->getCommitSignal()->connect(boost::bind(&FSFloaterPerformance::updateMaxRenderTime, this)); + mNearbyPanel->getChild("FSRenderAvatarMaxART")->setCommitCallback(boost::bind(&FSFloaterPerformance::updateMaxRenderTime, this)); + + LLAvatarComplexityControls::setIndirectMaxArc(); + + return TRUE; +} + +void FSFloaterPerformance::showSelectedPanel(LLPanel* selected_panel) +{ + hidePanels(); + mMainPanel->setVisible(FALSE); + selected_panel->setVisible(TRUE); + + if (mHUDsPanel == selected_panel) + { + populateHUDList(); + } + else if (mNearbyPanel == selected_panel) + { + populateNearbyList(); + } + else if (mComplexityPanel == selected_panel) + { + populateObjectList(); + } +} + +void FSFloaterPerformance::draw() +{ + const S32 NUM_PERIODS = 50; + constexpr auto NANOS = 1000000000; + + static LLCachedControl fpsCap(gSavedSettings, "FramePerSecondLimit"); // user limited FPS + static LLCachedControl targetFPS(gSavedSettings, "FSTargetFPS"); // desired FPS + static LLCachedControl tuningStrategy(gSavedSettings, "FSTuningFPSStrategy"); + + if (mUpdateTimer->hasExpired()) + { + LLStringUtil::format_map_t args; + + auto fps = LLTrace::get_frame_recording().getPeriodMedianPerSec(LLStatViewer::FPS, NUM_PERIODS); + getChild("fps_value")->setValue((S32)llround(fps)); + + auto target_frame_time_ns = NANOS/(targetFPS==0?1:targetFPS); + + FSPerfStats::bufferToggleLock.lock(); // prevent toggle for a moment + + auto tot_frame_time_ns = FSPerfStats::raw_to_ns(FSPerfStats::StatsRecorder::getSceneStat(FSPerfStats::StatType_t::RENDER_FRAME)); + // cumulative avatar time (includes idle processing, attachments and base av) + auto tot_avatar_time_raw = FSPerfStats::StatsRecorder::getSum(AvType, FSPerfStats::StatType_t::RENDER_COMBINED); + // cumulative avatar render specific time (a bit arbitrary as the processing is too.) + auto tot_avatar_render_time_raw = tot_avatar_time_raw - FSPerfStats::StatsRecorder::getSum(AvType, FSPerfStats::StatType_t::RENDER_IDLE); + // the time spent this frame on the "display()" call. Treated as "tot time rendering" + auto tot_render_time_raw = FSPerfStats::StatsRecorder::getSceneStat(FSPerfStats::StatType_t::RENDER_DISPLAY); + // sleep time is basically forced sleep when window out of focus + auto tot_sleep_time_raw = FSPerfStats::StatsRecorder::getSceneStat(FSPerfStats::StatType_t::RENDER_SLEEP); + // time spent on UI + auto tot_ui_time_raw = FSPerfStats::StatsRecorder::getSceneStat(FSPerfStats::StatType_t::RENDER_UI); + // cumulative time spent rendering HUDS + auto tot_huds_time_raw = FSPerfStats::StatsRecorder::getSceneStat(FSPerfStats::StatType_t::RENDER_HUDS); + // "idle" time. This is the time spent in the idle poll section of the main loop, we DO remove the avatar idle time as the avatar number we display is the total avatar time inclusive of idle processing. + auto tot_idle_time_raw = FSPerfStats::StatsRecorder::getSceneStat(FSPerfStats::StatType_t::RENDER_IDLE) - FSPerfStats::StatsRecorder::getSum(AvType, FSPerfStats::StatType_t::RENDER_IDLE); + // similar to sleep time, induced by FPS limit + auto tot_limit_time_raw = FSPerfStats::StatsRecorder::getSceneStat(FSPerfStats::StatType_t::RENDER_FPSLIMIT); + // swap time is time spent in swap buffer + auto tot_swap_time_raw = FSPerfStats::StatsRecorder::getSceneStat(FSPerfStats::StatType_t::RENDER_SWAP); + + FSPerfStats::bufferToggleLock.unlock(); + + auto unreliable = false; // if there is something to skew the stats such as sleep of fps cap + auto tot_avatar_time_ns = FSPerfStats::raw_to_ns( tot_avatar_time_raw ); + auto tot_huds_time_ns = FSPerfStats::raw_to_ns( tot_huds_time_raw ); + // UI time includes HUD time so dedut that before we calc percentages + auto tot_ui_time_ns = FSPerfStats::raw_to_ns( tot_ui_time_raw - tot_huds_time_raw); + + // auto tot_sleep_time_ns = FSPerfStats::raw_to_ns( tot_sleep_time_raw ); + // auto tot_limit_time_ns = FSPerfStats::raw_to_ns( tot_limit_time_raw ); + + // auto tot_render_time_ns = FSPerfStats::raw_to_ns( tot_render_time_raw ); + auto tot_idle_time_ns = FSPerfStats::raw_to_ns( tot_idle_time_raw ); + auto tot_swap_time_ns = FSPerfStats::raw_to_ns( tot_swap_time_raw ); + auto tot_scene_time_ns = FSPerfStats::raw_to_ns( tot_render_time_raw - tot_avatar_render_time_raw - tot_swap_time_raw - tot_ui_time_raw); + + + // // remove time spent sleeping for fps limit or out of focus. + // tot_frame_time_ns -= tot_limit_time_ns; + // tot_frame_time_ns -= tot_sleep_time_ns; + + if(tot_frame_time_ns == 0) + { + LL_WARNS("performance") << "things went wrong, quit while we can." << LL_ENDL; + return; + } + auto pct_avatar_time = (tot_avatar_time_ns * 100)/tot_frame_time_ns; + auto pct_huds_time = (tot_huds_time_ns * 100)/tot_frame_time_ns; + auto pct_ui_time = (tot_ui_time_ns * 100)/tot_frame_time_ns; + auto pct_idle_time = (tot_idle_time_ns * 100)/tot_frame_time_ns; + auto pct_swap_time = (tot_swap_time_ns * 100)/tot_frame_time_ns; + auto pct_scene_render_time = (tot_scene_time_ns * 100)/tot_frame_time_ns; + pct_avatar_time = llclamp(pct_avatar_time,0.,100.); + pct_huds_time = llclamp(pct_huds_time,0.,100.); + pct_ui_time = llclamp(pct_ui_time,0.,100.); + pct_idle_time = llclamp(pct_idle_time,0.,100.); + pct_swap_time = llclamp(pct_swap_time,0.,100.); + pct_scene_render_time = llclamp(pct_scene_render_time,0.,100.); + + args["AV_FRAME_PCT"] = llformat("%02u", (U32)llround(pct_avatar_time)); + args["HUDS_FRAME_PCT"] = llformat("%02u", (U32)llround(pct_huds_time)); + args["UI_FRAME_PCT"] = llformat("%02u", (U32)llround(pct_ui_time)); + args["IDLE_FRAME_PCT"] = llformat("%02u", (U32)llround(pct_idle_time)); + args["SWAP_FRAME_PCT"] = llformat("%02u", (U32)llround(pct_swap_time)); + args["SCENERY_FRAME_PCT"] = llformat("%02u", (U32)llround(pct_scene_render_time)); + args["TOT_FRAME_TIME"] = llformat("%02u", (U32)llround(tot_frame_time_ns/1000000)); + args["FPSCAP"] = llformat("%02u", (U32)fpsCap); + args["FPSTARGET"] = llformat("%02u", (U32)targetFPS); + + getChild("av_frame_stats")->setText(getString("av_frame_pct", args)); + getChild("huds_frame_stats")->setText(getString("huds_frame_pct", args)); + getChild("frame_breakdown")->setText(getString("frame_stats", args)); + + auto textbox = getChild("fps_warning"); + if (tot_sleep_time_raw > 0) // We are sleeping because view is not focussed + { + textbox->setVisible(true); + textbox->setText(getString("focus_fps")); + textbox->setColor(LLUIColorTable::instance().getColor("DrYellow")); + unreliable = true; + } + else if (tot_limit_time_raw > 0) + { + textbox->setVisible(true); + textbox->setText(getString("limit_fps", args)); + textbox->setColor(LLUIColorTable::instance().getColor("DrYellow")); + unreliable = true; + } + else if (FSPerfStats::autoTune) + { + textbox->setVisible(true); + textbox->setText(getString("tuning_fps", args)); + textbox->setColor(LLUIColorTable::instance().getColor("green")); + } + else + { + textbox->setVisible(false); + } + + if (FSPerfStats::autoTune && !unreliable ) + { + // the tuning itself is managed from another thread but we can report progress here + + // Is our target frame time lower than current? If so we need to take action to reduce draw overheads. + if (target_frame_time_ns <= tot_frame_time_ns) + { + U32 non_avatar_time_ns = tot_frame_time_ns - tot_avatar_time_ns; + // If the target frame time < non avatar frame time then we can pototentially reach it. + if (non_avatar_time_ns < target_frame_time_ns) + { + textbox->setColor(LLUIColorTable::instance().getColor("orange")); + } + else + { + // TODO(Beq): Set advisory text for further actions + textbox->setColor(LLUIColorTable::instance().getColor("red")); + } + } + else if (target_frame_time_ns > (tot_frame_time_ns + FSPerfStats::renderAvatarMaxART_ns)) + { + // if we have more time to spare. Display this (the service will update things) + textbox->setColor(LLUIColorTable::instance().getColor("green")); + } + } + + if (mHUDsPanel->getVisible()) + { + populateHUDList(); + } + else if (mNearbyPanel->getVisible()) + { + populateNearbyList(); + mNearbyPanel->getChild("hide_avatars")->set(!LLPipeline::hasRenderTypeControl(LLPipeline::RENDER_TYPE_AVATAR)); + } + else if (mComplexityPanel->getVisible()) + { + populateObjectList(); + } + + mUpdateTimer->setTimerExpirySec(REFRESH_INTERVAL); + } + LLFloater::draw(); +} + +void FSFloaterPerformance::showMainPanel() +{ + hidePanels(); + mMainPanel->setVisible(TRUE); +} + +void FSFloaterPerformance::hidePanels() +{ + mNearbyPanel->setVisible(FALSE); + mComplexityPanel->setVisible(FALSE); + mHUDsPanel->setVisible(FALSE); + mSettingsPanel->setVisible(FALSE); + mAutoTunePanel->setVisible(FALSE); +} + +void FSFloaterPerformance::initBackBtn(LLPanel* panel) +{ + panel->getChild("back_btn")->setCommitCallback(boost::bind(&FSFloaterPerformance::showMainPanel, this)); + panel->getChild("back_lbl")->setShowCursorHand(false); + panel->getChild("back_lbl")->setSoundFlags(LLView::MOUSE_UP); + panel->getChild("back_lbl")->setClickedCallback(boost::bind(&FSFloaterPerformance::showMainPanel, this)); +} + +void FSFloaterPerformance::populateHUDList() +{ + S32 prev_pos = mHUDList->getScrollPos(); + LLUUID prev_selected_id = mHUDList->getSelectedSpecialId(); + mHUDList->clearRows(); + mHUDList->updateColumns(true); + + hud_complexity_list_t complexity_list = LLHUDRenderNotifier::getInstance()->getHUDComplexityList(); + + hud_complexity_list_t::iterator iter = complexity_list.begin(); + hud_complexity_list_t::iterator end = complexity_list.end(); + + U32 max_complexity = 0; + for (; iter != end; ++iter) + { + max_complexity = llmax(max_complexity, (*iter).objectsCost); + } + + auto huds_max_render_time_raw = FSPerfStats::StatsRecorder::getMax(HudType, FSPerfStats::StatType_t::RENDER_GEOMETRY); + for (iter = complexity_list.begin(); iter != end; ++iter) + { + LLHUDComplexity hud_object_complexity = *iter; + + if (hud_object_complexity.objectName == FSLSLBridge::instance().currentFullName()) + { + continue; + } + + auto hud_render_time_raw = FSPerfStats::StatsRecorder::get(HudType, hud_object_complexity.objectId, FSPerfStats::StatType_t::RENDER_GEOMETRY); + LLSD item; + + item["special_id"] = hud_object_complexity.objectId; + item["target"] = LLNameListCtrl::SPECIAL; + LLSD& row = item["columns"]; + row[0]["column"] = "art_visual"; + row[0]["type"] = "bar"; + LLSD& value = row[0]["value"]; + value["ratio"] = (F32)hud_render_time_raw / huds_max_render_time_raw; + value["bottom"] = BAR_BOTTOM_PAD; + value["left_pad"] = BAR_LEFT_PAD; + value["right_pad"] = BAR_RIGHT_PAD; + + row[1]["column"] = "art_value"; + row[1]["type"] = "text"; + row[1]["value"] = llformat( "%.2f",FSPerfStats::raw_to_us(hud_render_time_raw) ); + row[1]["font"]["name"] = "SANSSERIF"; + + row[2]["column"] = "name"; + row[2]["type"] = "text"; + row[2]["value"] = hud_object_complexity.objectName; + row[2]["font"]["name"] = "SANSSERIF"; + + LLScrollListItem* obj = mHUDList->addElement(item); + if (obj) + { + // ART value + LLScrollListText* value_text = dynamic_cast(obj->getColumn(1)); + if (value_text) + { + value_text->setAlignment(LLFontGL::RIGHT); + } + + // name + value_text = dynamic_cast(obj->getColumn(3)); + if (value_text) + { + value_text->setAlignment(LLFontGL::LEFT); + } + } + } + + mHUDList->sortByColumnIndex(1, FALSE); + mHUDList->setScrollPos(prev_pos); + mHUDList->selectItemBySpecialId(prev_selected_id); +} + +void FSFloaterPerformance::populateObjectList() +{ + S32 prev_pos = mObjectList->getScrollPos(); + auto prev_selected_id = mObjectList->getSelectedSpecialId(); + + std::string current_sort_col = mObjectList->getSortColumnName(); + BOOL current_sort_asc = mObjectList->getSortAscending(); + + mObjectList->clearRows(); + mObjectList->updateColumns(true); + + object_complexity_list_t attachment_list = LLAvatarRenderNotifier::getInstance()->getObjectComplexityList(); + + object_complexity_list_t::iterator iter = attachment_list.begin(); + object_complexity_list_t::iterator end = attachment_list.end(); + + U32 max_complexity = 0; + for (; iter != end; ++iter) + { + max_complexity = llmax(max_complexity, (*iter).objectCost); + } + + // for consistency we lock the buffer while we build the list. In theory this is uncontended as th ebuffer should only toggle on end of frame + { + std::lock_guard guard{FSPerfStats::bufferToggleLock}; + auto att_max_render_time_raw = FSPerfStats::StatsRecorder::getMax(AttType, FSPerfStats::StatType_t::RENDER_COMBINED); + auto att_sum_render_time_raw = FSPerfStats::StatsRecorder::getSum(AttType, FSPerfStats::StatType_t::RENDER_COMBINED); + LL_DEBUGS("PerfFloater") << "Attachments for frame : " << gFrameCount << " Max:" << att_max_render_time_raw << LL_ENDL; + for (iter = attachment_list.begin(); iter != end; ++iter) + { + LLObjectComplexity attachment_complexity = *iter; + S32 obj_cost_short = llmax((S32)attachment_complexity.objectCost / 1000, 1); + + auto& attID{attachment_complexity.objectId}; + auto& attName{attachment_complexity.objectName}; + auto attach_render_time_raw = FSPerfStats::StatsRecorder::get(AttType, attID, FSPerfStats::StatType_t::RENDER_COMBINED); + LL_DEBUGS("PerfFloater") << "Att: " << attName << " (" << attID.asString() << ") Cost: " << FSPerfStats::raw_to_us(attach_render_time_raw) << LL_ENDL; + LLSD item; + item["special_id"] = attID; + item["target"] = LLNameListCtrl::SPECIAL; + LLSD& row = item["columns"]; + row[0]["column"] = "art_visual"; + row[0]["type"] = "bar"; + LLSD& value = row[0]["value"]; + value["ratio"] = ((F32)attach_render_time_raw) / att_max_render_time_raw; + value["bottom"] = BAR_BOTTOM_PAD; + value["left_pad"] = BAR_LEFT_PAD; + value["right_pad"] = BAR_RIGHT_PAD; + + row[1]["column"] = "art_value"; + row[1]["type"] = "text"; + // row[1]["value"] = std::to_string(obj_cost_short); + row[1]["value"] = llformat( "%.2f", FSPerfStats::raw_to_us(attach_render_time_raw) ); + row[1]["font"]["name"] = "SANSSERIF"; + + row[2]["column"] = "complex_value"; + row[2]["type"] = "text"; + row[2]["value"] = std::to_string(obj_cost_short); + row[2]["font"]["name"] = "SANSSERIF"; + + row[3]["column"] = "name"; + row[3]["type"] = "text"; + row[3]["value"] = attName; + row[3]["font"]["name"] = "SANSSERIF"; + + LLScrollListItem* obj = mObjectList->addElement(item); + if (obj) + { + // ART value + LLScrollListText* value_text = dynamic_cast(obj->getColumn(1)); + if (value_text) + { + value_text->setAlignment(LLFontGL::RIGHT); + } + // ARC value + value_text = dynamic_cast(obj->getColumn(2)); + if (value_text) + { + value_text->setAlignment(LLFontGL::RIGHT); + } + } + } + + auto textbox = getChild("tot_att_count"); + LLStringUtil::format_map_t args; + args["TOT_ATT"] = llformat("%d", (int64_t)attachment_list.size()); + args["TOT_ATT_TIME"] = llformat("%.2f", FSPerfStats::raw_to_us(att_sum_render_time_raw)); + textbox->setText(getString("tot_att_template", args)); + } + + LL_DEBUGS("PerfFloater") << "Attachments for frame : " << gFrameCount << " COMPLETED" << LL_ENDL; + mNearbyList->sortByColumn(current_sort_col, current_sort_asc); + mObjectList->setScrollPos(prev_pos); + mObjectList->selectItemBySpecialId(prev_selected_id); +} + +void FSFloaterPerformance::populateNearbyList() +{ + static LLCachedControl showTunedART(gSavedSettings, "FSShowTunedART"); + S32 prev_pos = mNearbyList->getScrollPos(); + LLUUID prev_selected_id = mNearbyList->getStringUUIDSelectedItem(); + std::string current_sort_col = mNearbyList->getSortColumnName(); + BOOL current_sort_asc = mNearbyList->getSortAscending(); + + if (current_sort_col == "art_visual") + { + current_sort_col = "art_value"; + current_sort_asc = false; + } + + mNearbyList->clearRows(); + mNearbyList->updateColumns(true); + + std::vector valid_nearby_avs; + getNearbyAvatars(valid_nearby_avs); + + std::vector::iterator char_iter = valid_nearby_avs.begin(); + + FSPerfStats::bufferToggleLock.lock(); + auto av_render_max_raw = FSPerfStats::StatsRecorder::getMax(AvType, FSPerfStats::StatType_t::RENDER_COMBINED); + auto av_render_tot_raw = FSPerfStats::StatsRecorder::getSum(AvType, FSPerfStats::StatType_t::RENDER_COMBINED); + FSPerfStats::bufferToggleLock.unlock(); + + // FSPlot("max ART", (int64_t)av_render_max_raw); + // FSPlot("Num av", (int64_t)valid_nearby_avs.size()); + + while (char_iter != valid_nearby_avs.end()) + { + LLVOAvatar* avatar = dynamic_cast(*char_iter); + if (avatar) + { + auto overall_appearance = avatar->getOverallAppearance(); + if (overall_appearance == LLVOAvatar::AOA_INVISIBLE) + { + continue; + } + + S32 complexity_short = llmax((S32)avatar->getVisualComplexity() / 1000, 1); + + FSPerfStats::bufferToggleLock.lock(); + auto render_av_raw = FSPerfStats::StatsRecorder::get(AvType, avatar->getID(),FSPerfStats::StatType_t::RENDER_COMBINED); + FSPerfStats::bufferToggleLock.unlock(); + + auto is_slow = avatar->isTooSlowWithShadows(); + + LLSD item; + item["id"] = avatar->getID(); + LLSD& row = item["columns"]; + row[0]["column"] = "art_visual"; + row[0]["type"] = "bar"; + LLSD& value = row[0]["value"]; + // The ratio used in the bar is the current cost, as soon as we take action this changes so we keep the + // pre-tune value for the numerical column and sorting. + value["ratio"] = (double)render_av_raw / av_render_max_raw; + value["bottom"] = BAR_BOTTOM_PAD; + value["left_pad"] = BAR_LEFT_PAD; + value["right_pad"] = BAR_RIGHT_PAD; + + row[1]["column"] = "art_value"; + row[1]["type"] = "text"; + if (is_slow && !showTunedART) + { + row[1]["value"] = llformat( "%.2f", FSPerfStats::raw_to_us( avatar->getLastART() ) ); + } + else + { + row[1]["value"] = llformat( "%.2f", FSPerfStats::raw_to_us( render_av_raw ) ); + } + row[1]["font"]["name"] = "SANSSERIF"; + row[1]["width"] = "50"; + + row[2]["column"] = "complex_value"; + row[2]["type"] = "text"; + row[2]["value"] = std::to_string(complexity_short); + row[2]["font"]["name"] = "SANSSERIF"; + row[2]["width"] = "50"; + + row[3]["column"] = "state"; + row[3]["type"] = "text"; + if (is_slow) + { + if (avatar->isTooSlowWithoutShadows()) + { + row[3]["value"] = std::string{"I"}; + } + else + { + row[3]["value"] = std::string{"S"}; + } + } + else + { + row[3]["value"] = std::string{" "}; + } + + row[3]["font"]["name"] = "SANSSERIF"; + + row[4]["column"] = "name"; + + LLScrollListItem* av_item = mNearbyList->addElement(item); + if (av_item) + { + LLScrollListText* art_text = dynamic_cast(av_item->getColumn(1)); + if (art_text) + { + art_text->setAlignment(LLFontGL::RIGHT); + } + LLScrollListText* value_text = dynamic_cast(av_item->getColumn(2)); + if (value_text) + { + value_text->setAlignment(LLFontGL::RIGHT); + } + LLScrollListText* state_text = dynamic_cast(av_item->getColumn(3)); + if (state_text) + { + state_text->setAlignment(LLFontGL::HCENTER); + } + LLScrollListText* name_text = dynamic_cast(av_item->getColumn(4)); + if (name_text) + { + if (avatar->isSelf()) + { + name_text->setColor(LLUIColorTable::instance().getColor("DrYellow")); + } + else + { + std::string color = "white"; + if (is_slow || LLVOAvatar::AOA_JELLYDOLL == overall_appearance) + { + color = "LabelDisabledColor"; + LLScrollListBar* bar = dynamic_cast(av_item->getColumn(0)); + if (bar) + { + bar->setColor(LLUIColorTable::instance().getColor(color)); + } + } + else if (LLVOAvatar::AOA_NORMAL == overall_appearance) + { + color = LLAvatarActions::isFriend(avatar->getID()) ? "ConversationFriendColor" : "white"; + } + name_text->setColor(LLUIColorTable::instance().getColor(color)); + } + } + } + } + char_iter++; + } + mNearbyList->sortByColumn(current_sort_col, current_sort_asc); + mNearbyList->setScrollPos(prev_pos); + mNearbyList->selectByID(prev_selected_id); + + auto textbox = getChild("tot_av_count"); + LLStringUtil::format_map_t args; + args["TOT_AV"] = llformat("%d", (int64_t)valid_nearby_avs.size()); + args["TOT_AV_TIME"] = llformat("%.2f", FSPerfStats::raw_to_us(av_render_tot_raw)); + textbox->setText(getString("tot_av_template", args)); +} + +void FSFloaterPerformance::getNearbyAvatars(std::vector &valid_nearby_avs) +{ + static LLCachedControl render_far_clip(gSavedSettings, "RenderFarClip", 64); + mNearbyMaxComplexity = 0; + F32 radius = render_far_clip * render_far_clip; + std::vector::iterator char_iter = LLCharacter::sInstances.begin(); + while (char_iter != LLCharacter::sInstances.end()) + { + LLVOAvatar* avatar = dynamic_cast(*char_iter); + if (avatar && !avatar->isDead() && !avatar->isControlAvatar()) + { + if ((dist_vec_squared(avatar->getPositionGlobal(), gAgent.getPositionGlobal()) > radius) && + (dist_vec_squared(avatar->getPositionGlobal(), gAgentCamera.getCameraPositionGlobal()) > radius)) + { + char_iter++; + continue; + } + avatar->calculateUpdateRenderComplexity(); + mNearbyMaxComplexity = llmax(mNearbyMaxComplexity, (S32)avatar->getVisualComplexity()); + valid_nearby_avs.push_back(*char_iter); + } + char_iter++; + } +} + +void FSFloaterPerformance::detachItem(const LLUUID& item_id) +{ + LLAppearanceMgr::instance().removeItemFromAvatar(item_id); +} + +void FSFloaterPerformance::onChangeQuality(const LLSD& data) +{ + LLFloaterPreference* instance = LLFloaterReg::getTypedInstance("preferences"); + if (instance) + { + instance->onChangeQuality(data); + } +} + +void FSFloaterPerformance::onClickHideAvatars() +{ + LLPipeline::toggleRenderTypeControl(LLPipeline::RENDER_TYPE_AVATAR); +} + +void FSFloaterPerformance::onClickFocusAvatar() +{ + FSPerfStats::StatsRecorder::setFocusAv(mNearbyCombo->getSelectedValue().asUUID()); +} + +void FSFloaterPerformance::onClickExceptions() +{ + // [FS Persisted Avatar Render Settings] + //LLFloaterReg::showInstance("avatar_render_settings"); + LLFloaterReg::showInstance("fs_avatar_render_settings"); + // +} + +void FSFloaterPerformance::updateMaxComplexity() +{ + LLAvatarComplexityControls::updateMax( + mNearbyPanel->getChild("IndirectMaxComplexity"), + mNearbyPanel->getChild("IndirectMaxComplexityText"), + true); +} + +void FSFloaterPerformance::updateMaxRenderTime() +{ + LLAvatarComplexityControls::updateMaxRenderTime( + mNearbyPanel->getChild("FSRenderAvatarMaxART"), + mNearbyPanel->getChild("FSRenderAvatarMaxARTText"), + true); +} + +void FSFloaterPerformance::updateMaxRenderTimeText() +{ + LLAvatarComplexityControls::setRenderTimeText( + gSavedSettings.getF32("FSRenderAvatarMaxART"), + mNearbyPanel->getChild("FSRenderAvatarMaxARTText", true), + true); +} + +void FSFloaterPerformance::updateComplexityText() +{ + LLAvatarComplexityControls::setText(gSavedSettings.getU32("RenderAvatarMaxComplexity"), + mNearbyPanel->getChild("IndirectMaxComplexityText", true), + true); +} + +static LLVOAvatar* find_avatar(const LLUUID& id) +{ + LLViewerObject *obj = gObjectList.findObject(id); + while (obj && obj->isAttachment()) + { + obj = (LLViewerObject *)obj->getParent(); + } + + if (obj && obj->isAvatar()) + { + return (LLVOAvatar*)obj; + } + else + { + return NULL; + } +} + +void FSFloaterPerformance::onCustomAction(const LLSD& userdata, const LLUUID& av_id) +{ + const std::string command_name = userdata.asString(); + + LLVOAvatar::VisualMuteSettings new_setting = LLVOAvatar::AV_RENDER_NORMALLY; + if ("default" == command_name) + { + new_setting = LLVOAvatar::AV_RENDER_NORMALLY; + } + else if ("never" == command_name) + { + new_setting = LLVOAvatar::AV_DO_NOT_RENDER; + } + else if ("always" == command_name) + { + new_setting = LLVOAvatar::AV_ALWAYS_RENDER; + } + + LLVOAvatar *avatarp = find_avatar(av_id); + if (avatarp) + { + avatarp->setVisualMuteSettings(new_setting); + } + else + { + // [FS Persisted Avatar Render Settings] + //LLRenderMuteList::getInstance()->saveVisualMuteSetting(av_id, new_setting); + FSAvatarRenderPersistence::instance().setAvatarRenderSettings(av_id, LLVOAvatar::VisualMuteSettings(new_setting)); + // + } +} + +bool FSFloaterPerformance::isActionChecked(const LLSD& userdata, const LLUUID& av_id) +{ + const std::string command_name = userdata.asString(); + + // [FS Persisted Avatar Render Settings] + //S32 visual_setting = LLRenderMuteList::getInstance()->getSavedVisualMuteSetting(av_id); + S32 visual_setting = (S32)FSAvatarRenderPersistence::instance().getAvatarRenderSettings(av_id); + // + if ("default" == command_name) + { + return (visual_setting == LLVOAvatar::AV_RENDER_NORMALLY); + } + else if ("non_default" == command_name) + { + return (visual_setting != LLVOAvatar::AV_RENDER_NORMALLY); + } + else if ("never" == command_name) + { + return (visual_setting == LLVOAvatar::AV_DO_NOT_RENDER); + } + else if ("always" == command_name) + { + return (visual_setting == LLVOAvatar::AV_ALWAYS_RENDER); + } + return false; +} + +void FSFloaterPerformance::onAvatarListRightClick(LLUICtrl* ctrl, S32 x, S32 y) +{ + LLNameListCtrl* list = dynamic_cast(ctrl); + if (!list) return; + list->selectItemAt(x, y, MASK_NONE); + uuid_vec_t selected_uuids; + + if ((list->getCurrentID().notNull()) && (list->getCurrentID() != gAgentID)) + { + selected_uuids.push_back(list->getCurrentID()); + mContextMenu->show(ctrl, selected_uuids, x, y); + } +} + +void FSFloaterPerformance::onExtendedAction(const LLSD& userdata, const LLUUID& av_id) +{ + const std::string command_name = userdata.asString(); + + LLViewerObject* objectp = gObjectList.findObject(av_id); + if (!objectp) + { + return; + } + auto avp = objectp->asAvatar(); + if ("inspect" == command_name) + { + for (LLVOAvatar::attachment_map_t::iterator iter = avp->mAttachmentPoints.begin(); + iter != avp->mAttachmentPoints.end(); + ++iter) + { + LLViewerJointAttachment* attachment = iter->second; + + if (!attachment) + { + continue; + } + + for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin(); + attachment_iter != attachment->mAttachedObjects.end(); + ++attachment_iter) + { + LLViewerObject* attached_object = attachment_iter->get(); + + if ( attached_object && !attached_object->isDead() ) + { + LLSelectMgr::getInstance()->selectObjectAndFamily(attached_object); + } + } + } + LLFloaterReg::showInstance("inspect"); + } + else if ("zoom" == command_name) + { + // Disable flycam if active. Without this, the requested look-at doesn't happen because the flycam code overrides all other camera motion. + bool fly_cam_status(LLViewerJoystick::getInstance()->getOverrideCamera()); + if (fly_cam_status) + { + LLViewerJoystick::getInstance()->setOverrideCamera(false); + LLPanelStandStopFlying::clearStandStopFlyingMode(LLPanelStandStopFlying::SSFM_FLYCAM); + // *NOTE: Above may not be the proper way to disable flycam. What I really want to do is just be able to move the camera and then leave the flycam in the the same state it was in, just moved to the new location. ~Cron + } + + LLViewerJoystick::getInstance()->setCameraNeedsUpdate(true); // Fixes an edge case where if the user has JUST disabled flycam themselves, the camera gets stuck waiting for input. + + gAgentCamera.setFocusOnAvatar(FALSE, ANIMATE); + + gAgentCamera.setLookAt(LOOKAT_TARGET_SELECT, objectp); + + // Place the camera looking at the object, along the line from the camera to the object, + // and sufficiently far enough away for the object to fill 3/4 of the screen, + // but not so close that the bbox's nearest possible vertex goes inside the near clip. + // Logic C&P'd from LLViewerMediaFocus::setCameraZoom() and then edited as needed + + LLBBox bbox = objectp->getBoundingBoxAgent(); + LLVector3d center(gAgent.getPosGlobalFromAgent(bbox.getCenterAgent())); + F32 height; + F32 width; + F32 depth; + F32 angle_of_view; + F32 distance; + + LLVector3d target_pos(center); + LLVector3d camera_dir(gAgentCamera.getCameraPositionGlobal() - target_pos); + camera_dir.normalize(); + + // We need the aspect ratio, and the 3 components of the bbox as height, width, and depth. + F32 aspect_ratio(LLViewerMediaFocus::getBBoxAspectRatio(bbox, LLVector3(camera_dir), &height, &width, &depth)); + F32 camera_aspect(LLViewerCamera::getInstance()->getAspect()); + + // We will normally use the side of the volume aligned with the short side of the screen (i.e. the height for + // a screen in a landscape aspect ratio), however there is an edge case where the aspect ratio of the object is + // more extreme than the screen. In this case we invert the logic, using the longer component of both the object + // and the screen. + bool invert((camera_aspect > 1.0f && aspect_ratio > camera_aspect) || (camera_aspect < 1.0f && aspect_ratio < camera_aspect)); + + // To calculate the optimum viewing distance we will need the angle of the shorter side of the view rectangle. + // In portrait mode this is the width, and in landscape it is the height. + // We then calculate the distance based on the corresponding side of the object bbox (width for portrait, height for landscape) + // We will add half the depth of the bounding box, as the distance projection uses the center point of the bbox. + if (camera_aspect < 1.0f || invert) + { + angle_of_view = llmax(0.1f, LLViewerCamera::getInstance()->getView() * LLViewerCamera::getInstance()->getAspect()); + distance = width * 0.5 * 1.1 / tanf(angle_of_view * 0.5f); + } + else + { + angle_of_view = llmax(0.1f, LLViewerCamera::getInstance()->getView()); + distance = height * 0.5 * 1.1 / tanf(angle_of_view * 0.5f); + } + + distance += depth * 0.5; + + // Verify that the bounding box isn't inside the near clip. Using OBB-plane intersection to check if the + // near-clip plane intersects with the bounding box, and if it does, adjust the distance such that the + // object doesn't clip. + LLVector3d bbox_extents(bbox.getExtentLocal()); + LLVector3d axis_x = LLVector3d(1, 0, 0) * bbox.getRotation(); + LLVector3d axis_y = LLVector3d(0, 1, 0) * bbox.getRotation(); + LLVector3d axis_z = LLVector3d(0, 0, 1) * bbox.getRotation(); + //Normal of nearclip plane is camera_dir. + F32 min_near_clip_dist = bbox_extents.mdV[VX] * (camera_dir * axis_x) + bbox_extents.mdV[VY] * (camera_dir * axis_y) + bbox_extents.mdV[VZ] * (camera_dir * axis_z); // http://www.gamasutra.com/view/feature/131790/simple_intersection_tests_for_games.php?page=7 + F32 camera_to_near_clip_dist(LLViewerCamera::getInstance()->getNear()); + F32 min_camera_dist(min_near_clip_dist + camera_to_near_clip_dist); + if (distance < min_camera_dist) + { + // Camera is too close to object, some parts MIGHT clip. Move camera away to the position where clipping barely doesn't happen. + distance = min_camera_dist; + } + + LLVector3d camera_pos(target_pos + camera_dir * distance); + + if (camera_dir == LLVector3d::z_axis || camera_dir == LLVector3d::z_axis_neg) + { + // If the direction points directly up, the camera will "flip" around. + // We try to avoid this by adjusting the target camera position a + // smidge towards current camera position + // *NOTE: this solution is not perfect. All it attempts to solve is the + // "looking down" problem where the camera flips around when it animates + // to that position. You still are not guaranteed to be looking at the + // object in the correct orientation. What this solution does is it will + // put the camera into position keeping as best it can the current + // orientation with respect to the direction wanted. In other words, if + // before zoom the object appears "upside down" from the camera, after + /// zooming it will still be upside down, but at least it will not flip. + LLVector3d cur_camera_pos = LLVector3d(gAgentCamera.getCameraPositionGlobal()); + LLVector3d delta = (cur_camera_pos - camera_pos); + F64 len = delta.length(); + delta.normalize(); + // Move 1% of the distance towards original camera location + camera_pos += 0.01 * len * delta; + } + + gAgentCamera.setCameraPosAndFocusGlobal(camera_pos, target_pos, objectp->getID()); + + // *TODO: Re-enable joystick flycam if we disabled it earlier... Have to find some form of callback as re-enabling at this point causes the camera motion to not happen. ~Cron + //if (fly_cam_status) + //{ + // LLViewerJoystick::getInstance()->toggleFlycam(); + //} + } +} + +// EOF diff --git a/indra/newview/fsfloaterperformance.h b/indra/newview/fsfloaterperformance.h new file mode 100644 index 0000000000..034c772ae2 --- /dev/null +++ b/indra/newview/fsfloaterperformance.h @@ -0,0 +1,98 @@ +/** + * @file fsfloaterperformance.h + * + * This is forked directly from an early access release of llfloaterperformance.h + * + * $LicenseInfo:firstyear=2021&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2021, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef FS_FLOATERPERFORMANCE_H +#define FS_FLOATERPERFORMANCE_H + +#include "llfloater.h" +#include "lllistcontextmenu.h" + +class LLCharacter; +class LLNameListCtrl; +class LLComboBox; + +class FSFloaterPerformance : public LLFloater +{ +public: + FSFloaterPerformance(const LLSD& key); + virtual ~FSFloaterPerformance(); + + /*virtual*/ BOOL postBuild(); + /*virtual*/ void draw(); + + void showSelectedPanel(LLPanel* selected_panel); + void showMainPanel(); + void hidePanels(); + + void detachItem(const LLUUID& item_id); + + void onAvatarListRightClick(LLUICtrl* ctrl, S32 x, S32 y); + + void onCustomAction (const LLSD& userdata, const LLUUID& av_id); + bool isActionChecked(const LLSD& userdata, const LLUUID& av_id); + void onExtendedAction(const LLSD& userdata, const LLUUID& av_id); + +private: + void initBackBtn(LLPanel* panel); + void populateHUDList(); + void populateObjectList(); + void populateNearbyList(); + + void onChangeQuality(const LLSD& data); + void onClickHideAvatars(); + void onClickExceptions(); + void onClickFocusAvatar(); + + void updateMaxComplexity(); + void updateComplexityText(); + void updateMaxRenderTime(); + void updateMaxRenderTimeText(); + + void getNearbyAvatars(std::vector &valid_nearby_avs); + + LLPanel* mMainPanel; + LLPanel* mNearbyPanel; + LLPanel* mComplexityPanel; + LLPanel* mHUDsPanel; + LLPanel* mSettingsPanel; + LLPanel* mAutoTunePanel; + LLNameListCtrl* mHUDList; + LLNameListCtrl* mObjectList; + LLNameListCtrl* mNearbyList; + LLComboBox* mNearbyCombo; + + LLListContextMenu* mContextMenu; + + LLTimer* mUpdateTimer; + + S32 mNearbyMaxComplexity; + + boost::signals2::connection mComplexityChangedSignal; + boost::signals2::connection mMaxARTChangedSignal; +}; + +#endif // FS_FLOATERPERFORMANCE_H diff --git a/indra/newview/fsfloatersearch.cpp b/indra/newview/fsfloatersearch.cpp index fd5e39d3a7..2ee7106cb4 100644 --- a/indra/newview/fsfloatersearch.cpp +++ b/indra/newview/fsfloatersearch.cpp @@ -57,6 +57,7 @@ #include "llparcel.h" #include "llproductinforequest.h" #include "llqueryflags.h" +#include "llregionhandle.h" #include "llremoteparcelrequest.h" #include "lltimer.h" #include "lltrans.h" @@ -64,6 +65,7 @@ #include "llviewergenericmessage.h" #include "llviewernetwork.h" #include "llviewerregion.h" +#include "llworldmapmessage.h" #include "message.h" #include #include @@ -82,8 +84,9 @@ void fillSearchComboBox(LLSearchComboBox* search_combo); class FSSearchRemoteParcelInfoObserver : public LLRemoteParcelInfoObserver { public: - FSSearchRemoteParcelInfoObserver(FSFloaterSearch* floater) : LLRemoteParcelInfoObserver(), - mParent(floater) + FSSearchRemoteParcelInfoObserver(FSFloaterSearch* floater, bool for_events) : LLRemoteParcelInfoObserver(), + mParent(floater), + mForEvents(for_events) {} ~FSSearchRemoteParcelInfoObserver() @@ -102,7 +105,14 @@ public: { if (mParent) { - mParent->displayParcelDetails(parcel_data); + if (mForEvents) + { + mParent->displayEventParcelImage(parcel_data); + } + else + { + mParent->displayParcelDetails(parcel_data); + } } mParcelIDs.erase(parcel_data.parcel_id); LLRemoteParcelInfoProcessor::getInstance()->removeObserver(parcel_data.parcel_id, this); @@ -125,6 +135,7 @@ public: private: std::set mParcelIDs; FSFloaterSearch* mParent; + bool mForEvents; }; ///// Avatar Properties Observer ///// @@ -234,13 +245,15 @@ SearchQuery::SearchQuery() FSFloaterSearch::FSFloaterSearch(const Params& key) : LLFloater(key) { - mRemoteParcelObserver = new FSSearchRemoteParcelInfoObserver(this); + mRemoteParcelObserver = new FSSearchRemoteParcelInfoObserver(this, false); + mRemoteParcelEventLocationObserver = new FSSearchRemoteParcelInfoObserver(this, true); mAvatarPropertiesObserver = new FSSearchAvatarPropertiesObserver(this); } FSFloaterSearch::~FSFloaterSearch() { delete mRemoteParcelObserver; + delete mRemoteParcelEventLocationObserver; delete mAvatarPropertiesObserver; gGenericDispatcher.addHandler("classifiedclickthrough", nullptr); } @@ -312,6 +325,7 @@ BOOL FSFloaterSearch::postBuild() mDetailAux2 = getChild("aux2"); mDetailLocation = getChild("location"); mDetailSnapshot = getChild("snapshot"); + mDetailSnapshotParcel = getChild("snapshot_parcel"); mDetailMaturity = getChild("maturity_icon"); mTabContainer = getChild("ls_tabs"); @@ -349,6 +363,18 @@ void FSFloaterSearch::onTabChange() { mDetailsPanel->setVisible(mHasSelection); } + + if (active_panel == mPanelPeople || active_panel == mPanelGroups) + { + mDetailSnapshotParcel->setVisible(FALSE); + mDetailSnapshot->setVisible(TRUE); + } + else if (active_panel == mPanelPlaces || active_panel == mPanelLand || + active_panel == mPanelEvents || active_panel == mPanelClassifieds) + { + mDetailSnapshot->setVisible(FALSE); + mDetailSnapshotParcel->setVisible(TRUE); + } } //static @@ -457,7 +483,7 @@ void FSFloaterSearch::displayParcelDetails(const LLParcelData& parcel_data) mDetailAux1->setValue(getString("string.traffic", map)); mDetailAux2->setValue(getString("string.area", map)); mDetailLocation->setValue(getString("string.location", map)); - mDetailSnapshot->setValue(parcel_data.snapshot_id); + mDetailSnapshotParcel->setValue(parcel_data.snapshot_id); childSetVisible("teleport_btn", true); childSetVisible("map_btn", true); setLoadingProgress(false); @@ -539,7 +565,7 @@ void FSFloaterSearch::displayClassifiedDetails(LLAvatarClassifiedInfo*& c_info) mParcelGlobal = c_info->pos_global; mDetailTitle->setValue(c_info->name); mDetailDesc->setValue(c_info->description); - mDetailSnapshot->setValue(c_info->snapshot_id); + mDetailSnapshotParcel->setValue(c_info->snapshot_id); mDetailAux1->setValue(getString("string.listing_price", map)); mDetailLocation->setValue(getString("string.slurl", map)); childSetVisible("teleport_btn", true); @@ -587,9 +613,34 @@ void FSFloaterSearch::displayEventDetails(U32 eventId, F64 eventEpoch, const std mDetailDesc->setValue(eventDesc); mDetailAux1->setValue(getString("string.duration", map)); mDetailLocation->setValue(getString("string.location", map)); + mDetailSnapshotParcel->setValue(LLUUID::null); childSetVisible("teleport_btn", true); childSetVisible("map_btn", true); childSetVisible("event_reminder_btn", true); + + LLWorldMapMessage::getInstance()->sendNamedRegionRequest(simName, boost::bind(&FSFloaterSearch::regionHandleCallback, this, _1, eventGlobalPos), "", false); +} + +void FSFloaterSearch::regionHandleCallback(U64 region_handle, LLVector3d pos_global) +{ + std::string url = gAgent.getRegionCapability("RemoteParcelRequest"); + if (!url.empty()) + { + auto region_origin = from_region_handle(region_handle); + LLVector3 pos_region(LLVector3(pos_global - region_origin)); + + LLRemoteParcelInfoProcessor::getInstance()->requestRegionParcelInfo(url, + LLUUID::null, pos_region, pos_global, mRemoteParcelEventLocationObserver->getObserverHandle()); + } + else + { + setLoadingProgress(false); + } +} + +void FSFloaterSearch::displayEventParcelImage(const LLParcelData& parcel_data) +{ + mDetailSnapshotParcel->setValue(parcel_data.snapshot_id); setLoadingProgress(false); } @@ -2886,17 +2937,41 @@ FSPanelSearchWeb::FSPanelSearchWeb() : FSSearchPanelBase() , mWebBrowser(nullptr) , mResetFocusOnLoad(false) { - // declare a map that transforms a category name into - // the URL suffix that is used to search that category + // Second Life grids use a different URL format now mCategoryPaths = LLSD::emptyMap(); - mCategoryPaths["all"] = "search"; - mCategoryPaths["people"] = "search/people"; - mCategoryPaths["places"] = "search/places"; - mCategoryPaths["events"] = "search/events"; - mCategoryPaths["groups"] = "search/groups"; - mCategoryPaths["wiki"] = "search/wiki"; - mCategoryPaths["destinations"] = "destinations"; - mCategoryPaths["classifieds"] = "classifieds"; + if (LLGridManager::getInstance()->isInSecondLife()) + { + // declare a map that transforms a category name into + // the parameter list that is used to search that category + mCategoryPaths["people"] = "collection_chosen=people"; + mCategoryPaths["places"] = "collection_chosen=places"; + mCategoryPaths["events"] = "collection_chosen=events"; + mCategoryPaths["groups"] = "collection_chosen=groups"; + mCategoryPaths["destinations"] = "collection_chosen=destinations"; + + mCategoryPaths["classifieds"] = "search_type=classified"; + mCategoryPaths["wiki"] = "search/wiki"; // not sure if this is still a thing in the new search + + mCategoryPaths["all"] = mCategoryPaths["people"].asString() + "&" + + mCategoryPaths["places"].asString() + "&" + + mCategoryPaths["events"].asString() + "&" + + mCategoryPaths["groups"].asString() + "&" + + mCategoryPaths["destinations"].asString(); + } + // OpenSim currently still uses the old URL format + else + { + // declare a map that transforms a category name into + // the URL suffix that is used to search that category + mCategoryPaths["all"] = "search"; + mCategoryPaths["people"] = "search/people"; + mCategoryPaths["places"] = "search/places"; + mCategoryPaths["events"] = "search/events"; + mCategoryPaths["groups"] = "search/groups"; + mCategoryPaths["wiki"] = "search/wiki"; + mCategoryPaths["destinations"] = "destinations"; + mCategoryPaths["classifieds"] = "classifieds"; + } } BOOL FSPanelSearchWeb::postBuild() @@ -2912,8 +2987,15 @@ void FSPanelSearchWeb::loadURL(const SearchQuery &p) return; } - // work out the subdir to use based on the requested category - LLSD subs = LLSD().with("CATEGORY", (mCategoryPaths.has(p.category) ? mCategoryPaths[p.category].asString() : mCategoryPaths["all"].asString())); + // CATEGORY is no longer used as part of the path on Second Life grids + LLSD subs = LLSD().with("CATEGORY", ""); + + // on OpenSim grids it probably is currently still being used, so keep the old behavior + if (!LLGridManager::getInstance()->isInSecondLife()) + { + // work out the subdir to use based on the requested category + LLSD subs = LLSD().with("CATEGORY", (mCategoryPaths.has(p.category) ? mCategoryPaths[p.category].asString() : mCategoryPaths["all"].asString())); + } // add the search query string subs["QUERY"] = LLURI::escape(p.query); @@ -2929,19 +3011,43 @@ void FSPanelSearchWeb::loadURL(const SearchQuery &p) // add the user's preferred maturity (can be changed via prefs) std::string maturity; - if (gAgent.prefersAdult()) + + // on Second Life grids, the maturity level is now a "&maturity" parameter that's not in the provided search URL + if (LLGridManager::getInstance()->isInSecondLife()) { - maturity = "42"; // PG,Mature,Adult - } - else if (gAgent.prefersMature()) - { - maturity = "21"; // PG,Mature + if (gAgent.prefersAdult()) + { + maturity = "gma"; // PG,Mature,Adult + } + else if (gAgent.prefersMature()) + { + maturity = "gm"; // PG,Mature + } + else + { + maturity = "g"; // PG + } + + // not used on the SL search anymore, so clear out the respective parameter + subs["MATURITY"] = ""; } + // OpenSim probably still uses the old maturity variant, so keep the old behavior here else { - maturity = "13"; // PG + if (gAgent.prefersAdult()) + { + maturity = "42"; // PG,Mature,Adult + } + else if (gAgent.prefersMature()) + { + maturity = "21"; // PG,Mature + } + else + { + maturity = "13"; // PG + } + subs["MATURITY"] = maturity; } - subs["MATURITY"] = maturity; // add the user's god status subs["GODLIKE"] = gAgent.isGodlike() ? "1" : "0"; @@ -2949,17 +3055,24 @@ void FSPanelSearchWeb::loadURL(const SearchQuery &p) // Get the search URL and expand all of the substitutions // (also adds things like [LANGUAGE], [VERSION], [OS], etc.) std::string url; - -#ifdef OPENSIM - std::string debug_url = gSavedSettings.getString("SearchURLDebug"); - if (gSavedSettings.getBOOL("DebugSearch") && !debug_url.empty()) + + // add the maturity and category variables to the new Second Life search URL + if (LLGridManager::getInstance()->isInSecondLife()) { - url = debug_url; + url = LFSimFeatureHandler::instance().searchURL() + "&maturity=" + maturity + "&" + mCategoryPaths[p.category].asString(); } + // for OpenSim, do the same as in earlier versions else -#endif // OPENSIM { - url = LFSimFeatureHandler::instance().searchURL(); + std::string debug_url = gSavedSettings.getString("SearchURLDebug"); + if (gSavedSettings.getBOOL("DebugSearch") && !debug_url.empty()) + { + url = debug_url; + } + else + { + url = LFSimFeatureHandler::instance().searchURL(); + } } url = LLWeb::expandURLSubstitutions(url, subs); diff --git a/indra/newview/fsfloatersearch.h b/indra/newview/fsfloatersearch.h index eff98d68c8..8ef70656e7 100644 --- a/indra/newview/fsfloatersearch.h +++ b/indra/newview/fsfloatersearch.h @@ -42,7 +42,7 @@ #include "llscrolllistctrl.h" #include "lltabcontainer.h" -class LLRemoteParcelInfoObserver; +class FSSearchRemoteParcelInfoObserver; class LLAvatarPropertiesObserver; class LLGroupMgrObserver; class LLSearchEditor; @@ -360,6 +360,7 @@ public: U32 eventFlags, U32 eventCover, LLVector3d eventGlobalPos); + void displayEventParcelImage(const LLParcelData& parcel_data); void setLoadingProgress(bool started); template @@ -386,7 +387,10 @@ private: void onBtnTeleport(); void onBtnMap(); - LLRemoteParcelInfoObserver* mRemoteParcelObserver; + void regionHandleCallback(U64 region_handle, LLVector3d pos_global); + + FSSearchRemoteParcelInfoObserver* mRemoteParcelObserver; + FSSearchRemoteParcelInfoObserver* mRemoteParcelEventLocationObserver; LLAvatarPropertiesObserver* mAvatarPropertiesObserver; LLGroupMgrObserver* mGroupPropertiesRequest; @@ -405,6 +409,7 @@ private: LLTextEditor* mDetailAux2; LLTextEditor* mDetailLocation; LLTextureCtrl* mDetailSnapshot; + LLTextureCtrl* mDetailSnapshotParcel; LLIconCtrl* mDetailMaturity; LLTabContainer* mTabContainer; FSPanelProfile* mPanelProfile; diff --git a/indra/newview/fspanelcontactsets.cpp b/indra/newview/fspanelcontactsets.cpp index a6fb47ed86..eeb2403955 100644 --- a/indra/newview/fspanelcontactsets.cpp +++ b/indra/newview/fspanelcontactsets.cpp @@ -62,15 +62,15 @@ FSPanelContactSets::~FSPanelContactSets() BOOL FSPanelContactSets::postBuild() { - childSetAction("add_set_btn", boost::bind(&FSPanelContactSets::onClickAddSet, this)); - childSetAction("remove_set_btn", boost::bind(&FSPanelContactSets::onClickRemoveSet, this)); - childSetAction("config_btn", boost::bind(&FSPanelContactSets::onClickConfigureSet, this, _1)); - childSetAction("add_btn", boost::bind(&FSPanelContactSets::onClickAddAvatar, this, _1)); - childSetAction("remove_btn", boost::bind(&FSPanelContactSets::onClickRemoveAvatar, this)); - childSetAction("profile_btn", boost::bind(&FSPanelContactSets::onClickOpenProfile, this)); - childSetAction("start_im_btn", boost::bind(&FSPanelContactSets::onClickStartIM, this)); - childSetAction("offer_teleport_btn", boost::bind(&FSPanelContactSets::onClickOfferTeleport, this)); - childSetAction("set_pseudonym_btn", boost::bind(&FSPanelContactSets::onClickSetPseudonym, this)); + childSetAction("add_set_btn", boost::bind(&FSPanelContactSets::onClickAddSet, this)); + childSetAction("remove_set_btn", boost::bind(&FSPanelContactSets::onClickRemoveSet, this)); + childSetAction("config_btn", boost::bind(&FSPanelContactSets::onClickConfigureSet, this, _1)); + childSetAction("add_btn", boost::bind(&FSPanelContactSets::onClickAddAvatar, this, _1)); + childSetAction("remove_btn", boost::bind(&FSPanelContactSets::onClickRemoveAvatar, this)); + childSetAction("profile_btn", boost::bind(&FSPanelContactSets::onClickOpenProfile, this)); + childSetAction("start_im_btn", boost::bind(&FSPanelContactSets::onClickStartIM, this)); + childSetAction("offer_teleport_btn", boost::bind(&FSPanelContactSets::onClickOfferTeleport, this)); + childSetAction("set_pseudonym_btn", boost::bind(&FSPanelContactSets::onClickSetPseudonym, this)); childSetAction("remove_pseudonym_btn", boost::bind(&FSPanelContactSets::onClickRemovePseudonym, this)); childSetAction("remove_displayname_btn", boost::bind(&FSPanelContactSets::onClickRemoveDisplayName, this)); @@ -80,6 +80,7 @@ BOOL FSPanelContactSets::postBuild() mAvatarList = getChild("contact_list"); mAvatarList->setCommitCallback(boost::bind(&FSPanelContactSets::onSelectAvatar, this)); + mAvatarList->setItemDoubleClickCallback(boost::bind(&FSPanelContactSets::onClickStartIM, this)); mAvatarList->setNoItemsCommentText(getString("empty_list")); mAvatarList->setContextMenu(&LLPanelPeopleMenus::gPeopleContextMenu); generateAvatarList(mContactSetCombo->getValue().asString()); diff --git a/indra/newview/fsperfstats.cpp b/indra/newview/fsperfstats.cpp new file mode 100644 index 0000000000..1febba5f35 --- /dev/null +++ b/indra/newview/fsperfstats.cpp @@ -0,0 +1,419 @@ +/** + * @file fsperfstats.cpp + * @brief Stats collection to support perf floater and auto tune + * + * $LicenseInfo:firstyear=2021&license=fsviewerlgpl$ + * Phoenix Firestorm Viewer Source Code + * Copyright (C) 2021, The Phoenix Firestorm Project, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * The Phoenix Firestorm Project, Inc., 1831 Oakwood Drive, Fairmont, Minnesota 56031-3225 USA + * http://www.firestormviewer.org + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" +#include "fsperfstats.h" +#include "llcontrol.h" +#include "pipeline.h" +#include "llagentcamera.h" +#include "llvoavatar.h" +#include "llworld.h" + +extern LLControlGroup gSavedSettings; + +namespace FSPerfStats +{ + #ifdef USAGE_TRACKING + std::atomic inUse{0}; + std::atomic inUseAvatar{0}; + std::atomic inUseScene{0}; + std::atomic inUseAttachment{0}; + std::atomic inUseAttachmentRigged{0}; + std::atomic inUseAttachmentUnRigged{0}; +#endif + + std::atomic tunedAvatars{0}; + U32 targetFPS; // desired FPS + U64 renderAvatarMaxART_ns{(U64)(ART_UNLIMITED_NANOS)}; // highest render time we'll allow without culling features + U32 fpsTuningStrategy{0}; // linked to FSTuningFPSStrategy + U32 lastGlobalPrefChange{0}; + std::mutex bufferToggleLock{}; + bool autoTune{false}; + + std::atomic StatsRecorder::writeBuffer{0}; + bool StatsRecorder::collectionEnabled{true}; + LLUUID StatsRecorder::focusAv{LLUUID::null}; + std::array StatsRecorder::statsDoubleBuffer{ {} }; + std::array StatsRecorder::max{ {} }; + std::array StatsRecorder::sum{ {} }; + + + StatsRecorder::StatsRecorder():q(1024*16),t(&StatsRecorder::run) + { + // create a queue + // create a thread to consume from the queue + + FSPerfStats::targetFPS = gSavedSettings.getU32("FSTargetFPS"); + FSPerfStats::autoTune = gSavedSettings.getBOOL("FSAutoTuneFPS"); + + updateRenderCostLimitFromSettings(); + + t.detach(); + } + + // static + void StatsRecorder::toggleBuffer() + { + FSZone; + using ST = StatType_t; + + bool unreliable{false}; + static LLCachedControl smoothingPeriods(gSavedSettings, "FSPerfFloaterSmoothingPeriods"); + + auto& sceneStats = statsDoubleBuffer[writeBuffer][static_cast(ObjType_t::OT_GENERAL)][LLUUID::null]; + auto& lastStats = statsDoubleBuffer[writeBuffer ^ 1][static_cast(ObjType_t::OT_GENERAL)][LLUUID::null]; + + static constexpr std::initializer_list sceneStatsToAvg = { + StatType_t::RENDER_FRAME, + StatType_t::RENDER_DISPLAY, + StatType_t::RENDER_HUDS, + StatType_t::RENDER_UI, + StatType_t::RENDER_SWAP, + // RENDER_LFS, + // RENDER_MESHREPO, + StatType_t::RENDER_IDLE }; + + static constexpr std::initializer_list avatarStatsToAvg = { + StatType_t::RENDER_GEOMETRY, + StatType_t::RENDER_SHADOWS, + StatType_t::RENDER_COMBINED, + StatType_t::RENDER_IDLE }; + + + if( sceneStats[static_cast(StatType_t::RENDER_FPSLIMIT)] != 0 || sceneStats[static_cast(StatType_t::RENDER_SLEEP)] != 0 ) + { + unreliable = true; + lastStats[static_cast(StatType_t::RENDER_FPSLIMIT)] = sceneStats[static_cast(StatType_t::RENDER_FPSLIMIT)]; + lastStats[static_cast(StatType_t::RENDER_SLEEP)] = sceneStats[static_cast(StatType_t::RENDER_SLEEP)]; + } + + if(!unreliable) + { + // only use these stats when things are reliable. + + for(auto & statEntry : sceneStatsToAvg) + { + auto avg = lastStats[static_cast(statEntry)]; + auto val = sceneStats[static_cast(statEntry)]; + sceneStats[static_cast(statEntry)] = avg + (val/smoothingPeriods) - (avg/smoothingPeriods); + // LL_INFOS("scenestats") << "Scenestat: " << static_cast(statEntry) << " before=" << avg << " new=" << val << " newavg=" << statsDoubleBuffer[writeBuffer][static_cast(ObjType_t::OT_GENERAL)][LLUUID::null][static_cast(statEntry)] << LL_ENDL; + } + + auto& statsMap = statsDoubleBuffer[writeBuffer][static_cast(ObjType_t::OT_ATTACHMENT)]; + for(auto& stat_entry : statsMap) + { + auto val = stat_entry.second[static_cast(ST::RENDER_COMBINED)]; + if(val>smoothingPeriods){ + auto avg = statsDoubleBuffer[writeBuffer ^ 1][static_cast(ObjType_t::OT_ATTACHMENT)][stat_entry.first][static_cast(ST::RENDER_COMBINED)]; + stat_entry.second[static_cast(ST::RENDER_COMBINED)] = avg + (val/smoothingPeriods) - (avg/smoothingPeriods); + } + } + + + auto& statsMapAv = statsDoubleBuffer[writeBuffer][static_cast(ObjType_t::OT_AVATAR)]; + for(auto& stat_entry : statsMapAv) + { + for(auto& stat : avatarStatsToAvg) + { + auto val = stat_entry.second[static_cast(stat)]; + if(val>smoothingPeriods) + { + auto avg = statsDoubleBuffer[writeBuffer ^ 1][static_cast(ObjType_t::OT_AVATAR)][stat_entry.first][static_cast(stat)]; + stat_entry.second[static_cast(stat)] = avg + (val/smoothingPeriods) - (avg/smoothingPeriods); + } + } + } + + // swap the buffers + if(enabled()) + { + std::lock_guard lock{bufferToggleLock}; + writeBuffer ^= 1; + }; // note we are relying on atomic updates here. The risk is low and would cause minor errors in the stats display. + } + + // clean the write maps in all cases. + auto& statsTypeMatrix = statsDoubleBuffer[writeBuffer]; + for(auto& statsMap : statsTypeMatrix) + { + FSZoneN("Clear stats maps"); + for(auto& stat_entry : statsMap) + { + std::fill_n(stat_entry.second.begin() ,static_cast(ST::STATS_COUNT),0); + } + statsMap.clear(); + } + for(int i=0; i< static_cast(ObjType_t::OT_COUNT); i++) + { + FSZoneN("clear max/sum"); + max[writeBuffer][i].fill(0); + sum[writeBuffer][i].fill(0); + } + + // and now adjust the visuals. + if(autoTune) + { + updateAvatarParams(); + } + } + + // clear buffers when we change region or need a hard reset. + // static + void StatsRecorder::clearStatsBuffers() + { + FSZone; + using ST = StatType_t; + + auto& statsTypeMatrix = statsDoubleBuffer[writeBuffer]; + for(auto& statsMap : statsTypeMatrix) + { + FSZoneN("Clear stats maps"); + for(auto& stat_entry : statsMap) + { + std::fill_n(stat_entry.second.begin() ,static_cast(ST::STATS_COUNT),0); + } + statsMap.clear(); + } + for(int i=0; i< static_cast(ObjType_t::OT_COUNT); i++) + { + FSZoneN("clear max/sum"); + max[writeBuffer][i].fill(0); + sum[writeBuffer][i].fill(0); + } + // swap the clean buffers in + if(enabled()) + { + std::lock_guard lock{bufferToggleLock}; + writeBuffer ^= 1; + }; + // repeat before we start processing new stuff + for(auto& statsMap : statsTypeMatrix) + { + FSZoneN("Clear stats maps"); + for(auto& stat_entry : statsMap) + { + std::fill_n(stat_entry.second.begin() ,static_cast(ST::STATS_COUNT),0); + } + statsMap.clear(); + } + for(int i=0; i< static_cast(ObjType_t::OT_COUNT); i++) + { + FSZoneN("clear max/sum"); + max[writeBuffer][i].fill(0); + sum[writeBuffer][i].fill(0); + } + } + + // static + void StatsRecorder::updateSettingsFromRenderCostLimit() + { + static LLCachedControl maxRenderCost_us(gSavedSettings, "FSRenderAvatarMaxART"); + if( (F32)maxRenderCost_us != log10( ( (F32)FSPerfStats::renderAvatarMaxART_ns )/1000 ) ) + { + if( FSPerfStats::renderAvatarMaxART_ns != 0 ) + { + gSavedSettings.setF32( "FSRenderAvatarMaxART", log10( ( (F32)FSPerfStats::renderAvatarMaxART_ns )/1000 ) ); + } + else + { + gSavedSettings.setF32( "FSRenderAvatarMaxART",log10( FSPerfStats::ART_UNLIMITED_NANOS/1000 ) ); + } + } + } + + // static + void StatsRecorder::updateRenderCostLimitFromSettings() + { + const auto newval = gSavedSettings.getF32("FSRenderAvatarMaxART"); + if(newval < log10(FSPerfStats::ART_UNLIMITED_NANOS/1000)) + { + FSPerfStats::renderAvatarMaxART_ns = pow(10,newval)*1000; + } + else + { + FSPerfStats::renderAvatarMaxART_ns = 0; + }; + } + + //static + int StatsRecorder::countNearbyAvatars(S32 distance) + { + const auto our_pos = gAgentCamera.getCameraPositionGlobal(); + + std::vector positions; + uuid_vec_t avatar_ids; + LLWorld::getInstance()->getAvatars(&avatar_ids, &positions, our_pos, distance); + return positions.size(); + } + + // static + void StatsRecorder::updateAvatarParams() + { + static LLCachedControl drawDistance(gSavedSettings, "RenderFarClip"); + static LLCachedControl userMinDrawDistance(gSavedSettings, "FSAutoTuneRenderFarClipMin"); + static LLCachedControl userTargetDrawDistance(gSavedSettings, "FSAutoTuneRenderFarClipTarget"); + static LLCachedControl impostorDistance(gSavedSettings, "FSAutoTuneImpostorFarAwayDistance"); + static LLCachedControl impostorDistanceTuning(gSavedSettings, "FSAutoTuneImpostorByDistEnabled"); + static LLCachedControl maxNonImpostors (gSavedSettings, "IndirectMaxNonImpostors"); + + if(impostorDistanceTuning) + { + // if we have less than the user's "max Non-Impostors" avatars within the desired range then adjust the limit. + // also adjusts back up again for nearby crowds. + auto count = countNearbyAvatars(std::min(drawDistance, impostorDistance)); + if( count != maxNonImpostors ) + { + gSavedSettings.setU32("IndirectMaxNonImpostors", (count < LLVOAvatar::NON_IMPOSTORS_MAX_SLIDER)?count : LLVOAvatar::NON_IMPOSTORS_MAX_SLIDER); + LL_DEBUGS("AutoTune") << "There are " << count << "avatars within " << std::min(drawDistance, impostorDistance) << "m of the camera" << LL_ENDL; + } + } + + auto av_render_max_raw = FSPerfStats::StatsRecorder::getMax(ObjType_t::OT_AVATAR, FSPerfStats::StatType_t::RENDER_COMBINED); + // Is our target frame time lower than current? If so we need to take action to reduce draw overheads. + // cumulative avatar time (includes idle processing, attachments and base av) + auto tot_avatar_time_raw = FSPerfStats::StatsRecorder::getSum(ObjType_t::OT_AVATAR, FSPerfStats::StatType_t::RENDER_COMBINED); + // sleep time is basically forced sleep when window out of focus + auto tot_sleep_time_raw = FSPerfStats::StatsRecorder::getSceneStat(FSPerfStats::StatType_t::RENDER_SLEEP); + // similar to sleep time, induced by FPS limit + auto tot_limit_time_raw = FSPerfStats::StatsRecorder::getSceneStat(FSPerfStats::StatType_t::RENDER_FPSLIMIT); + + + // the time spent this frame on the "doFrame" call. Treated as "tot time for frame" + auto tot_frame_time_raw = FSPerfStats::StatsRecorder::getSceneStat(FSPerfStats::StatType_t::RENDER_FRAME); + + if( tot_sleep_time_raw != 0 ) + { + // Note: we do not average sleep + // if at some point we need to, the averaging will need to take this into account or + // we forever think we're in the background due to residuals. + LL_DEBUGS() << "No tuning when not in focus" << LL_ENDL; + return; + } + + // The frametime budget we have based on the target FPS selected + auto target_frame_time_raw = (U64)llround((F64)LLTrace::BlockTimer::countsPerSecond()/(targetFPS==0?1:targetFPS)); + // LL_INFOS() << "Effective FPS(raw):" << tot_frame_time_raw << " Target:" << target_frame_time_raw << LL_ENDL; + + if( tot_limit_time_raw != 0) + { + // This could be problematic. + tot_frame_time_raw -= tot_limit_time_raw; + } + // 1) Is the target frame tim lower than current? + if( target_frame_time_raw <= tot_frame_time_raw ) + { + // if so we've got work to do + + // how much of the frame was spent on non avatar related work? + U32 non_avatar_time_raw = tot_frame_time_raw - tot_avatar_time_raw; + + // If the target frame time < non avatar frame time thne adjusting avatars is only goin gto get us so far. + U64 target_avatar_time_raw; + if(target_frame_time_raw < non_avatar_time_raw) + { + // we cannnot do this by avatar adjustment alone. + if((gFrameCount - FSPerfStats::lastGlobalPrefChange) > 10) // give changes a short time to take effect. + { + if(FSPerfStats::fpsTuningStrategy == 1) + { + // 1 - hack the water to opaque. all non opaque have a significant hit, this is a big boost for (arguably) a minor visual hit. + // the other reflection options make comparatively little change and iof this overshoots we'll be stepping back up later + if(LLPipeline::RenderReflectionDetail != -2) + { + gSavedSettings.setS32("RenderReflectionDetail", -2); + FSPerfStats::lastGlobalPrefChange = gFrameCount; + return; + } + else // deliberately "else" here so we only do these in steps + { + // step down the DD by 10m per update + auto new_dd = (drawDistance-10>userMinDrawDistance)?(drawDistance - 10) : userMinDrawDistance; + if(new_dd != drawDistance) + { + gSavedSettings.setF32("RenderFarClip", new_dd); + FSPerfStats::lastGlobalPrefChange = gFrameCount; + return; + } + } + } + } + target_avatar_time_raw = 0; + } + else + { + // desired avatar budget. + target_avatar_time_raw = target_frame_time_raw - non_avatar_time_raw; + } + + if( target_avatar_time_raw < tot_avatar_time_raw ) + { + // we need to spend less time drawing avatars to meet our budget + // Note: working in usecs now cos reasons. + auto new_render_limit_ns {renderAvatarMaxART_ns}; + // max render this frame may be higher than the last (cos new entrants and jitter) so make sure we are heading in the right direction + if(FSPerfStats::raw_to_ns(av_render_max_raw) < renderAvatarMaxART_ns) + { + new_render_limit_ns = FSPerfStats::raw_to_ns(av_render_max_raw); + } + else + { + new_render_limit_ns = renderAvatarMaxART_ns; + } + new_render_limit_ns -= FSPerfStats::ART_MIN_ADJUST_DOWN_NANOS; + + // bounce at the bottom to prevent "no limit" + new_render_limit_ns = std::max((U64)new_render_limit_ns, (U64)FSPerfStats::ART_MINIMUM_NANOS); + + // assign the new value + renderAvatarMaxART_ns = new_render_limit_ns; + // LL_DEBUGS() << "AUTO_TUNE: avatar_budget adjusted to:" << new_render_limit_ns << LL_ENDL; + } + // LL_DEBUGS() << "AUTO_TUNE: Target frame time:"<< FSPerfStats::raw_to_us(target_frame_time_raw) << "usecs (non_avatar is " << FSPerfStats::raw_to_us(non_avatar_time_raw) << "usecs) Max cost limited=" << renderAvatarMaxART_ns << LL_ENDL; + } + else if( FSPerfStats::raw_to_ns(target_frame_time_raw) > (FSPerfStats::raw_to_ns(tot_frame_time_raw) + renderAvatarMaxART_ns) ) + { + if( FSPerfStats::tunedAvatars >= 0 ) + { + // if we have more time to spare let's shift up little in the hope we'll restore an avatar. + renderAvatarMaxART_ns += FSPerfStats::ART_MIN_ADJUST_UP_NANOS; + } + if( drawDistance < userTargetDrawDistance ) + { + gSavedSettings.setF32("RenderFarClip", drawDistance + 10.); + } + if( (target_frame_time_raw * 1.5) > tot_frame_time_raw && + FSPerfStats::tunedAvatars == 0 && + drawDistance >= userTargetDrawDistance) + { + // if everything else is "max" and we have 50% headroom let's knock the water quality up a notch at a time. + auto water = gSavedSettings.getS32("RenderReflectionDetail"); + gSavedSettings.setS32("RenderReflectionDetail", water+1); + } + } + updateSettingsFromRenderCostLimit(); + } +} \ No newline at end of file diff --git a/indra/newview/fsperfstats.h b/indra/newview/fsperfstats.h new file mode 100644 index 0000000000..49a7e8e6d1 --- /dev/null +++ b/indra/newview/fsperfstats.h @@ -0,0 +1,498 @@ +#pragma once +#ifndef FS_PERFSTATS_H_INCLUDED +#define FS_PERFSTATS_H_INCLUDED +/** + * @file fsperfstats.h + * @brief Statistics collection to support autotune and perf flaoter. + * + * $LicenseInfo:firstyear=2021&license=fsviewerlgpl$ + * Phoenix Firestorm Viewer Source Code + * Copyright (C) 2021, The Phoenix Firestorm Project, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * The Phoenix Firestorm Project, Inc., 1831 Oakwood Drive, Fairmont, Minnesota 56031-3225 USA + * http://www.firestormviewer.org + * $/LicenseInfo$ + */ + +#include +#include +#include +#include +#include +#include "lluuid.h" +#include "llfasttimer.h" +#include "blockingconcurrentqueue.h" +#include "llapp.h" +#include "fstelemetry.h" +#include "pipeline.h" + +// Additional logging options. These can skew inworld numbers so onyl use for debugging and tracking issues +#ifdef FS_HAS_TELEMETRY_SUPPORT +// USAGE_TRACKING - displays overlapping stats that may imply double counting. +// ATTACHMENT_TRACKING - displays detailed tracking info for Avatar and Attachment. very heavy overhead. +// #define USAGE_TRACKING +// #define ATTACHMENT_TRACKING +#else +#undef USAGE_TRACKING +#undef ATTACHMENT_TRACKING +#endif + +extern U32 gFrameCount; +extern LLUUID gAgentID; +namespace FSPerfStats +{ +#ifdef USAGE_TRACKING + extern std::atomic inUse; + extern std::atomic inUseAvatar; + extern std::atomic inUseScene; + extern std::atomic inUseAttachment; + extern std::atomic inUseAttachmentRigged; + extern std::atomic inUseAttachmentUnRigged; +#endif +// Note if changing these, they should correspond with the log range of the correpsonding sliders + constexpr U64 ART_UNLIMITED_NANOS{50000000}; + constexpr U64 ART_MINIMUM_NANOS{100000}; + constexpr U64 ART_MIN_ADJUST_UP_NANOS{10000}; + constexpr U64 ART_MIN_ADJUST_DOWN_NANOS{10000}; + + constexpr F32 PREFERRED_DD{180}; + + extern std::atomic tunedAvatars; + extern U32 targetFPS; // desired FPS + extern U64 renderAvatarMaxART_ns; + extern U32 fpsTuningStrategy; + extern U32 lastGlobalPrefChange; + extern std::mutex bufferToggleLock; + extern bool autoTune; + + enum class ObjType_t{ + OT_GENERAL=0, // Also Unknown. Used for n/a type stats such as scenery + OT_AVATAR, + OT_ATTACHMENT, + OT_HUD, + OT_COUNT + }; + enum class StatType_t{ + RENDER_GEOMETRY=0, + RENDER_SHADOWS, + RENDER_HUDS, + RENDER_UI, + RENDER_COMBINED, + RENDER_SWAP, + RENDER_FRAME, + RENDER_DISPLAY, + RENDER_SLEEP, + RENDER_LFS, + RENDER_MESHREPO, + RENDER_FPSLIMIT, + RENDER_FPS, + RENDER_IDLE, + RENDER_DONE, // toggle buffer & clearbuffer (see processUpdate for hackery) + STATS_COUNT + }; + + struct StatsRecord + { + StatType_t statType; + ObjType_t objType; + LLUUID avID; + LLUUID objID; + uint64_t time; + bool isRigged; + bool isHUD; + }; + + class StatsRecorder{ + using Queue = moodycamel::BlockingConcurrentQueue; + public: + + static inline StatsRecorder& getInstance() + { + static StatsRecorder instance; + // volatile int dummy{}; + return instance; + } + static inline void setFocusAv(const LLUUID& avID){focusAv = avID;}; + static inline const LLUUID& getFocusAv(){return (focusAv);}; + static inline void send(StatsRecord&& u){StatsRecorder::getInstance().q.enqueue(u);}; + static void endFrame(){StatsRecorder::getInstance().q.enqueue(StatsRecord{StatType_t::RENDER_DONE, ObjType_t::OT_GENERAL, LLUUID::null, LLUUID::null, 0});}; + static void clearStats(){StatsRecorder::getInstance().q.enqueue(StatsRecord{StatType_t::RENDER_DONE, ObjType_t::OT_GENERAL, LLUUID::null, LLUUID::null, 1});}; + + static inline void setEnabled(bool on_or_off){collectionEnabled=on_or_off;}; + static inline void enable() { collectionEnabled=true; }; + static inline void disable() { collectionEnabled=false; }; + static inline bool enabled() { return(collectionEnabled); }; + + static inline int getReadBufferIndex() { return (writeBuffer ^ 1); }; + // static inline const StatsTypeMatrix& getCurrentStatsMatrix(){ return statsDoubleBuffer[getReadBufferIndex()];} + static inline uint64_t get(ObjType_t otype, LLUUID id, StatType_t type) + { + return statsDoubleBuffer[getReadBufferIndex()][static_cast(otype)][id][static_cast(type)]; + } + static inline uint64_t getSceneStat(StatType_t type) + { + return statsDoubleBuffer[getReadBufferIndex()][static_cast(ObjType_t::OT_GENERAL)][LLUUID::null][static_cast(type)]; + } + + static inline uint64_t getSum(ObjType_t otype, StatType_t type) + { + return sum[getReadBufferIndex()][static_cast(otype)][static_cast(type)]; + } + static inline uint64_t getMax(ObjType_t otype, StatType_t type) + { + return max[getReadBufferIndex()][static_cast(otype)][static_cast(type)]; + } + static void updateSettingsFromRenderCostLimit(); + static void updateRenderCostLimitFromSettings(); + static void updateAvatarParams(); + private: + StatsRecorder(); + + static int countNearbyAvatars(S32 distance); +// StatsArray is a uint64_t for each possible statistic type. + using StatsArray = std::array(FSPerfStats::StatType_t::STATS_COUNT)>; + using StatsMap = std::unordered_map; + using StatsTypeMatrix = std::array(FSPerfStats::ObjType_t::OT_COUNT)>; + using StatsSummaryArray = std::array(FSPerfStats::ObjType_t::OT_COUNT)>; + + static std::atomic writeBuffer; + static LLUUID focusAv; + static std::array statsDoubleBuffer; + static std::array max; + static std::array sum; + static bool collectionEnabled; + + + void processUpdate(const StatsRecord& upd) + { + FSZone; + // LL_INFOS("perfstats") << "processing update:" << LL_ENDL; + using ST = StatType_t; + // Note: nullptr is used as the key for global stats + #ifdef FS_HAS_TELEMETRY_SUPPORT + static char avstr[36]; + static char obstr[36]; + #endif + + if(upd.statType == StatType_t::RENDER_DONE && upd.objType == ObjType_t::OT_GENERAL && upd.time == 0) + { + // LL_INFOS("perfstats") << "End of Frame Toggle Buffer:" << gFrameCount << LL_ENDL; + toggleBuffer(); + return; + } + if(upd.statType == StatType_t::RENDER_DONE && upd.objType == ObjType_t::OT_GENERAL && upd.time == 1) + { + // LL_INFOS("perfstats") << "New region - clear buffers:" << gFrameCount << LL_ENDL; + clearStatsBuffers(); + return; + } + + auto ot{upd.objType}; + auto& key{upd.objID}; + auto& avKey{upd.avID}; + auto type {upd.statType}; + auto val {upd.time}; + + #ifdef FS_HAS_TELEMETRY_SUPPORT + FSZoneText(key.toStringFast(obstr),36); + FSZoneText(avKey.toStringFast(avstr),36); + FSZoneValue(val); + #endif + + if(ot == ObjType_t::OT_GENERAL) + { + // LL_INFOS("perfstats") << "General update:" << LL_ENDL; + doUpd(key, ot, type,val); + return; + } + + if(ot == ObjType_t::OT_AVATAR) + { + // LL_INFOS("perfstats") << "Avatar update:" << LL_ENDL; + doUpd(avKey, ot, type, val); + return; + } + + if(ot == ObjType_t::OT_ATTACHMENT) + { + if( !upd.isRigged && !upd.isHUD ) + { + // For all attachments that are not rigged we add them to the avatar (for all avatars) cost. + doUpd(avKey, ObjType_t::OT_AVATAR, type, val); + } + if( avKey == focusAv ) + { + // For attachments that are for the focusAv (self for now) we record them for the attachment/complexity view + if(upd.isHUD) + { + ot = ObjType_t::OT_HUD; + } + // LL_INFOS("perfstats") << "frame: " << gFrameCount << " Attachment update("<< (type==StatType_t::RENDER_GEOMETRY?"GEOMETRY":"SHADOW") << ": " << key.asString() << " = " << val << LL_ENDL; + doUpd(key, ot, type, val); + } + else + { + // LL_INFOS("perfstats") << "frame: " << gFrameCount << " non-self Att update("<< (type==StatType_t::RENDER_GEOMETRY?"GEOMETRY":"SHADOW") << ": " << key.asString() << " = " << val << " for av " << avKey.asString() << LL_ENDL; + } + } + + } + + static inline void doUpd(const LLUUID& key, ObjType_t ot, StatType_t type, uint64_t val) + { + FSZone; + using ST = StatType_t; + StatsMap& stm {statsDoubleBuffer[writeBuffer][static_cast(ot)]}; + auto& thisAsset = stm[key]; + + thisAsset[static_cast(type)] += val; + thisAsset[static_cast(ST::RENDER_COMBINED)] += val; + + sum[writeBuffer][static_cast(ot)][static_cast(type)] += val; + sum[writeBuffer][static_cast(ot)][static_cast(ST::RENDER_COMBINED)] += val; + + if(max[writeBuffer][static_cast(ot)][static_cast(type)] < thisAsset[static_cast(type)]) + { + max[writeBuffer][static_cast(ot)][static_cast(type)] = thisAsset[static_cast(type)]; + } + if(max[writeBuffer][static_cast(ot)][static_cast(ST::RENDER_COMBINED)] < thisAsset[static_cast(ST::RENDER_COMBINED)]) + { + max[writeBuffer][static_cast(ot)][static_cast(ST::RENDER_COMBINED)] = thisAsset[static_cast(ST::RENDER_COMBINED)]; + } + } + + static void toggleBuffer(); + static void clearStatsBuffers(); + + // thread entry + static void run() + { + StatsRecord upd[10]; + auto& instance {StatsRecorder::getInstance()}; + FSThreadName( "PerfStats" ); + + while( enabled() && !LLApp::isExiting() ) + { + auto count = instance.q.wait_dequeue_bulk_timed(upd, 10, std::chrono::milliseconds(10)); + if(count) + { + // LL_INFOS("perfstats") << "processing " << count << " updates." << LL_ENDL; + for(auto i =0; i < count; i++) + { + instance.processUpdate(upd[i]); + } + } + } + } + + Queue q; + std::thread t; + + ~StatsRecorder() = default; + StatsRecorder(const StatsRecorder&) = delete; + StatsRecorder& operator=(const StatsRecorder&) = delete; + + }; + + template + class RecordTime + { + + private: + RecordTime(const RecordTime&) = delete; + RecordTime() = delete; + U64 start; + public: + StatsRecord stat; + + RecordTime( const LLUUID& av, const LLUUID& id, StatType_t type, bool isRiggedAtt=false, bool isHUDAtt=false): + start{LLTrace::BlockTimer::getCPUClockCount64()}, + stat{type, ObjTypeDiscriminator, std::move(av), std::move(id), 0, isRiggedAtt, isHUDAtt} + { + FSZoneC(tracy::Color::Orange); + #ifdef USAGE_TRACKING + if(stat.objType == FSPerfStats::ObjType_t::OT_ATTACHMENT) + { + if(!stat.isRigged && FSPerfStats::inUseAvatar){FSZoneText("OVERLAP AVATAR",14);} + + FSPlotSq("InUse", (int64_t)FSPerfStats::inUse, (int64_t)FSPerfStats::inUse+1); + FSPerfStats::inUse++; + FSPlotSq("InUseAttachment", (int64_t)FSPerfStats::inUseAttachment, (int64_t)FSPerfStats::inUseAttachment+1); + FSPerfStats::inUseAttachment++; + if (stat.isRigged) + { + FSPlotSq("InUseAttachmentRigged", (int64_t)FSPerfStats::inUseAttachmentRigged,(int64_t)FSPerfStats::inUseAttachmentRigged+1); + FSPerfStats::inUseAttachmentRigged++; + } + else + { + FSPlotSq("InUseAttachmentUnRigged", (int64_t)FSPerfStats::inUseAttachmentUnRigged,(int64_t)FSPerfStats::inUseAttachmentUnRigged+1); + FSPerfStats::inUseAttachmentUnRigged++; + } + } + #endif + + }; + + template < ObjType_t OD = ObjTypeDiscriminator, + std::enable_if_t * = nullptr> + RecordTime( StatType_t type ):RecordTime(LLUUID::null, LLUUID::null, type ) + { + FSZone; + #ifdef USAGE_TRACKING + FSPlotSq("InUseScene", (int64_t)FSPerfStats::inUseScene, (int64_t)FSPerfStats::inUseScene+1); + FSPerfStats::inUseScene++; + FSPlotSq("InUse", (int64_t)FSPerfStats::inUse, (int64_t)FSPerfStats::inUse+1); + FSPerfStats::inUse++; + #endif + }; + + template < ObjType_t OD = ObjTypeDiscriminator, + std::enable_if_t * = nullptr> + RecordTime( const LLUUID & av, StatType_t type ):RecordTime(std::move(av), LLUUID::null, type) + { + FSZoneC(tracy::Color::Purple); + + #ifdef USAGE_TRACKING + if(FSPerfStats::inUseAvatar){FSZoneText("OVERLAP AVATAR",14);} + + FSPlotSq("InUseAv", (int64_t)FSPerfStats::inUseAvatar, (int64_t)FSPerfStats::inUseAvatar+1); + FSPerfStats::inUseAvatar++; + FSPlotSq("InUse", (int64_t)FSPerfStats::inUse, (int64_t)FSPerfStats::inUse+1); + FSPerfStats::inUse++; + + #endif + + }; + + ~RecordTime() + { + if(!FSPerfStats::StatsRecorder::enabled()) + { + return; + } + + + FSZoneC(tracy::Color::Red); + + #ifdef USAGE_TRACKING + FSPlotSq("InUse", (int64_t)FSPerfStats::inUse,(int64_t)FSPerfStats::inUse-1); + --FSPerfStats::inUse; + if (stat.objType == FSPerfStats::ObjType_t::OT_ATTACHMENT) + { + FSPlotSq("InUseAttachment", (int64_t)FSPerfStats::inUseAttachment,(int64_t)FSPerfStats::inUseAttachment-1); + --FSPerfStats::inUseAttachment; + if (stat.isRigged) + { + FSPlotSq("InUseAttachmentRigged", (int64_t)FSPerfStats::inUseAttachmentRigged,(int64_t)FSPerfStats::inUseAttachmentRigged-1); + --FSPerfStats::inUseAttachmentRigged; + } + else + { + FSPlotSq("InUseAttachmentUnRigged", (int64_t)FSPerfStats::inUseAttachmentUnRigged,(int64_t)FSPerfStats::inUseAttachmentUnRigged-1); + --FSPerfStats::inUseAttachmentUnRigged; + } + } + if (stat.objType == FSPerfStats::ObjType_t::OT_GENERAL) + { + FSPlotSq("InUseScene", (int64_t)FSPerfStats::inUseScene,(int64_t)FSPerfStats::inUseScene-1); + --FSPerfStats::inUseScene; + } + if( stat.objType == FSPerfStats::ObjType_t::OT_AVATAR ) + { + FSPlotSq("InUseAv", (int64_t)FSPerfStats::inUseAvatar, (int64_t)FSPerfStats::inUseAvatar-1); + --FSPerfStats::inUseAvatar; + } + #endif + stat.time = LLTrace::BlockTimer::getCPUClockCount64() - start; + + #ifdef ATTACHMENT_TRACKING + static char obstr[36]; + static char avstr[36]; + FSZoneValue(static_cast(stat.objType)); + FSZoneText(stat.avID.toStringFast(avstr), 36); + FSZoneText(stat.objID.toStringFast(obstr), 36); + FSZoneValue(stat.time); + #endif + + StatsRecorder::send(std::move(stat)); + }; + + + }; + + + inline double raw_to_ns(U64 raw) { return (static_cast(raw) * 1000000000.0) / (F64)LLTrace::BlockTimer::countsPerSecond(); }; + inline double raw_to_us(U64 raw) { return (static_cast(raw) * 1000000.0) / (F64)LLTrace::BlockTimer::countsPerSecond(); }; + inline double raw_to_ms(U64 raw) { return (static_cast(raw) * 1000.0) / (F64)LLTrace::BlockTimer::countsPerSecond(); }; + + using RecordSceneTime = RecordTime; + using RecordAvatarTime = RecordTime; + using RecordAttachmentTime = RecordTime; + using RecordHudAttachmentTime = RecordTime; + +};// namespace FSPerfStats + +// helper functions +using RATptr = std::unique_ptr; + +template +static inline void trackAttachments(const T * vobj, bool isRigged, RATptr* ratPtrp) +{ + if( !vobj ){ ratPtrp->reset(); return;}; + + const T* rootAtt{vobj}; + if( rootAtt->isAttachment() ) + { + FSZone; + + while( !rootAtt->isRootEdit() ) + { + rootAtt = (T*)(rootAtt->getParent()); + } + + auto avPtr = (T*)(rootAtt->getParent()); + if(!avPtr){ratPtrp->reset(); return;} + + auto& av = avPtr->getID(); + auto& obj = rootAtt->getAttachmentItemID(); + if(!*ratPtrp || (*ratPtrp)->stat.objID != obj || (*ratPtrp)->stat.avID != av ) + { + #if TRACY_ENABLE && defined(ATTACHMENT_TRACKING) + FSZoneNC( "trackAttachments:new", tracy::Color::Red ); + auto& str = rootAtt->getAttachmentItemName(); + FSZoneText(str.c_str(), str.size()); + FSZoneText(isRigged?"Rigged ":"Unrigged",8); + static char avStr[36]; + av.toStringFast(avStr); + static char obStr[4]; + obj.toShortString(obStr); + FSZoneText( avStr, 36); + FSZoneText( obStr, 4); + #endif + if(*ratPtrp){ratPtrp->reset();}; // deliberately reset to ensure destruction before construction of replacement. + *ratPtrp = std::make_unique( av, + obj, + ( (LLPipeline::sShadowRender)?FSPerfStats::StatType_t::RENDER_SHADOWS : FSPerfStats::StatType_t::RENDER_GEOMETRY ), + isRigged, + rootAtt->isHUDAttachment()); + } + } + return; +}; + +#endif \ No newline at end of file diff --git a/indra/newview/fsradar.cpp b/indra/newview/fsradar.cpp index 4d495c6470..0277474047 100644 --- a/indra/newview/fsradar.cpp +++ b/indra/newview/fsradar.cpp @@ -232,7 +232,7 @@ void FSRadar::updateRadarList() mRadarOffsetRequests.clear(); mRadarEntriesData.clear(); mAvatarStats.clear(); - + //STEP 1: Update our basic data model: detect Avatars & Positions in our defined range std::vector positions; uuid_vec_t avatar_ids; @@ -375,12 +375,20 @@ void FSRadar::updateRadarList() mRadarOffsetRequests.push_back(avId); ent->mLastZOffsetTime = now; } - } + } F32 avRange = (avPos[VZ] != AVATAR_UNKNOWN_Z_OFFSET ? dist_vec(avPos, posSelf) : AVATAR_UNKNOWN_RANGE); ent->mRange = avRange; ent->mGlobalPos = avPos; ent->mRegion = avRegion; - + + // Double-check range here since limiting range on calling LLWorld::getAvatars does + // not work if other avatar is beyond draw distance and above 1020m height. Need to + // use LSL bridge result to filter those out. + if (sLimitRange && avRange > sNearMeRange) + { + continue; + } + // //2b. Process newly detected avatars // @@ -436,7 +444,7 @@ void FSRadar::updateRadarList() } } } - + // // 2c. Process previously detected avatars // @@ -504,7 +512,7 @@ void FSRadar::updateRadarList() mRadarEnterAlerts.push_back(avId); } } - + // //2d. Prepare data for presentation view for this avatar // @@ -569,7 +577,7 @@ void FSRadar::updateRadarList() range_color = colortable.getColor("AvatarListItemBeyondShoutRange", LLColor4::white); } } - else + else { range_color = colortable.getColor("AvatarListItemBeyondShoutRange", LLColor4::white); } @@ -642,11 +650,11 @@ void FSRadar::updateRadarList() entry_data["options"] = entry_options; mRadarEntriesData.push_back(entry_data); } // End STEP 2, all model/presentation row processing complete. - + // //STEP 3, process any bulk actions that require the whole model to be known first // - + // //3a. dispatch requests for ZOffset updates, working around minimap's inaccurate height // @@ -680,7 +688,7 @@ void FSRadar::updateRadarList() mRadarOffsetRequests.clear(); mRadarLastBulkOffsetRequestTime = now; } - + // //3b: process alerts for avatars that where here last frame, but gone this frame (ie, they left) // as well as dispatch all earlier detected alerts for crossing range thresholds. @@ -787,7 +795,7 @@ void FSRadar::updateRadarList() // //STEP 4: Cache our current model data, so we can compare it with the next fresh group of model data for fast change detection. // - + mLastRadarSweep.clear(); em_it_end = mEntryList.end(); for (entry_map_t::iterator em_it = mEntryList.begin(); em_it != em_it_end; ++em_it) diff --git a/indra/newview/generate_breakpad_symbols.py b/indra/newview/generate_breakpad_symbols.py deleted file mode 100755 index d351c406bc..0000000000 --- a/indra/newview/generate_breakpad_symbols.py +++ /dev/null @@ -1,166 +0,0 @@ -#!/usr/bin/env python -"""\ -@file generate_breakpad_symbols.py -@author Brad Kittenbrink -@brief Simple tool for generating google_breakpad symbol information - for the crash reporter. - -$LicenseInfo:firstyear=2010&license=viewerlgpl$ -Second Life Viewer Source Code -Copyright (C) 2010-2011, Linden Research, Inc. - -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; -version 2.1 of the License only. - -This library is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA -$/LicenseInfo$ -""" - - -import collections -import fnmatch -import itertools -import os -import re -import sys -import shlex -import subprocess -import tarfile -import StringIO -import pprint - -DEBUG=False - -def usage(): - print >>sys.stderr, "usage: %s search_dirs viewer_exes libs_suffix dump_syms_tool viewer_symbol_file" % sys.argv[0] - -class MissingModuleError(Exception): - def __init__(self, modules): - Exception.__init__(self, "Failed to find required modules: %r" % modules) - self.modules = modules - -def main(configuration, search_dirs, viewer_exes, libs_suffix, dump_syms_tool, viewer_symbol_file): - print "generate_breakpad_symbols run with args: %s" % str((configuration, search_dirs, viewer_exes, libs_suffix, dump_syms_tool, viewer_symbol_file)) - - if not re.match("release", configuration, re.IGNORECASE): - print "skipping breakpad symbol generation for non-release build." - return 0 - - # split up list of viewer_exes - # "'Second Life' SLPlugin" becomes ['Second Life', 'SLPlugin'] - viewer_exes = shlex.split(viewer_exes) - - found_required = dict([(module, False) for module in viewer_exes]) - - def matches(f): - if f in viewer_exes: - found_required[f] = True - return True - return fnmatch.fnmatch(f, libs_suffix) - - search_dirs = search_dirs.split(";") - - def list_files(): - for search_dir in search_dirs: - for (dirname, subdirs, filenames) in os.walk(search_dir): - if DEBUG: - print "scanning '%s' for modules..." % dirname - for f in itertools.ifilter(matches, filenames): - yield os.path.join(dirname, f) - - def dump_module(m): - print "dumping module '%s' with '%s'..." % (m, dump_syms_tool) - dsym_full_path = m - child = subprocess.Popen([dump_syms_tool, dsym_full_path] , stdout=subprocess.PIPE) - out, err = child.communicate() - return (m,child.returncode, out, err) - - - modules = {} - - for m in list_files(): - if DEBUG: - print "examining module '%s' ... " % m, - filename=os.path.basename(m) - if -1 != m.find("DWARF"): - # Just use this module; it has the symbols we want. - modules[filename] = m - if DEBUG: - print "found dSYM entry" - elif filename not in modules: - # Only use this if we don't already have a (possibly better) entry. - modules[filename] = m - if DEBUG: - print "found new entry" - elif DEBUG: - print "ignoring entry" - - - print "Found these following modules:" - pprint.pprint( modules ) - - out = tarfile.open(viewer_symbol_file, 'w:bz2') - for (filename,status,symbols,err) in itertools.imap(dump_module, modules.values()): - if status == 0: - module_line = symbols[:symbols.index('\n')] - module_line = module_line.split() - hash_id = module_line[3] - module = ' '.join(module_line[4:]) - if sys.platform in ['win32', 'cygwin']: - mod_name = module[:module.rindex('.pdb')] - else: - mod_name = module - symbolfile = StringIO.StringIO(symbols) - info = tarfile.TarInfo("%(module)s/%(hash_id)s/%(mod_name)s.sym" % dict(module=module, hash_id=hash_id, mod_name=mod_name)) - info.size = symbolfile.len - out.addfile(info, symbolfile) - else: - print >>sys.stderr, "warning: failed to dump symbols for '%s': %s" % (filename, err) - - out.close() - - missing_modules = [m for (m,_) in - itertools.ifilter(lambda (k,v): not v, found_required.iteritems()) - ] - if missing_modules: - print >> sys.stderr, "failed to generate %s" % viewer_symbol_file - os.remove(viewer_symbol_file) - raise MissingModuleError(missing_modules) - - symbols = tarfile.open(viewer_symbol_file, 'r:bz2') - tarfile_members = symbols.getnames() - symbols.close() - - for required_module in viewer_exes: - def match_module_basename(m): - return os.path.splitext(required_module)[0].lower() \ - == os.path.splitext(os.path.basename(m))[0].lower() - # there must be at least one .sym file in tarfile_members that matches - # each required module (ignoring file extensions) - if not any(itertools.imap(match_module_basename, tarfile_members)): - print >> sys.stderr, "failed to find required %s in generated %s" \ - % (required_module, viewer_symbol_file) - os.remove(viewer_symbol_file) - raise MissingModuleError([required_module]) - - print "successfully generated %s including required modules '%s'" % (viewer_symbol_file, viewer_exes) - - return 0 - -if __name__ == "__main__": - if len(sys.argv) != 7: - usage() - sys.exit(1) - sys.exit(main(*sys.argv[1:])) - diff --git a/indra/newview/installers/darwin/apple-notarize.sh b/indra/newview/installers/darwin/apple-notarize.sh new file mode 100755 index 0000000000..466898ecda --- /dev/null +++ b/indra/newview/installers/darwin/apple-notarize.sh @@ -0,0 +1,54 @@ +#!/bin/sh +if [[ $SKIP_NOTARIZATION == "true" ]]; then + echo "Skipping notarization" + exit 0 +fi + +CONFIG_FILE="$build_secrets_checkout/code-signing-osx/notarize_creds.sh" +if [ -f "$CONFIG_FILE" ]; then + source $CONFIG_FILE + app_file="$1" + zip_file=${app_file/app/zip} + ditto -c -k --keepParent "$app_file" "$zip_file" + if [ -f "$zip_file" ]; then + res=$(xcrun altool --notarize-app --primary-bundle-id "com.secondlife.viewer" \ + --username $USERNAME \ + --password $PASSWORD \ + --asc-provider $ASC_PROVIDER \ + --file "$zip_file" 2>&1) + requestUUID=$(echo $res | awk '/RequestUUID/ { print $NF; }') + + echo "Apple Notarization RequestUUID: $requestUUID" + + if [[ -n $requestUUID ]]; then + status="in progress" + while [[ "$status" == "in progress" ]]; do + sleep 30 + status=$(xcrun altool --notarization-info "$requestUUID" \ + --username $USERNAME \ + --password $PASSWORD 2>&1 \ + | awk -F ': ' '/Status:/ { print $2; }' ) + echo "$status" + done + # log results + xcrun altool --notarization-info "$requestUUID" \ + --username $USERNAME \ + --password $PASSWORD + + #remove temporary file + rm "$zip_file" + + if [["$status" == "success"]]; then + xcrun stapler staple "$app_file" + elif [["$status" == "invalid"]]; then + echo "Notarization error: failed to process the app file" + exit 1 + fi + else + echo "Notarization error: couldn't get request UUID" + echo $res + exit 1 + fi + fi +fi + diff --git a/indra/newview/installers/darwin/firestorm-beta-dmg/VivoxAUP.txt b/indra/newview/installers/darwin/firestorm-beta-dmg/VivoxAUP.txt deleted file mode 100644 index 6413f8b16a..0000000000 --- a/indra/newview/installers/darwin/firestorm-beta-dmg/VivoxAUP.txt +++ /dev/null @@ -1,23 +0,0 @@ -Acceptable Use Policy (AUP) - - 1. BACKGROUND: Users of the online voice services provided by Vivox, Inc. ("Vivox") (the "Service"), through the act of utilizing the Service, agree to adhere to this Acceptable Use Policy (the "Policy"). Vivox reserves the right to immediately terminate a user's access to the Service if the user engages in any of the activities prohibited by this Policy or uses the Service contrary to this Policy. Each user is responsible for all activities conducted under its account. The user is also responsible for adhering to any policy set forth by any other service provider accessed through the Service; Vivox, and its suppliers and providers, assume no responsibility or liability for a user's failure to comply with the Policy. The user acknowledges that Vivox may have access to information about or provided by the user, including diagnostic information sent automatically after a problem or error, and agrees to such access and use. - - 2. PROHIBITED USES AND ACTIVITIES: Users shall not provide inaccurate or misleading information to Vivox or use the Service to: (i) access any other person's computer or computer system, software, or data without their knowledge and consent; or breach the security of another user; or attempt to circumvent the user authentication or security of any host, network, system, or account, which includes, but is not limited to, accessing data not intended for the user, logging into or making use of a server or account the user is not expressly authorized to access, or probing the security of other hosts, networks, or accounts; or use automated means (such as robots and spiders) to obtain information from Vivox's website or, though it, from other websites; (ii) interfere with computer networking or telecommunications service to any user, host or network, including, without limitation, denial of service attacks, flooding of a network, overloading a service, improper seizing and abuse of operator privileges and attempts to "crash" a host; (iii) violate the rules, regulations, or policies applicable to any network, server, computer database, or service that accessed by the user; (iv) transmit, re-transmit, or store any content or to engage in any activity that infringes the intellectual property rights or privacy rights of Vivox or any individual, group or entity, including but not limited to any rights protected by any copyright, patent, trademark, trade secret, trade dress, right of privacy, right of publicity, moral rights or other intellectual property right now known or later recognized by statute, judicial decision or regulation; (v) host, post, transmit, or re-transmit any content or material that is threatening, harassing, obscene, indecent, pornographic, hateful, malicious, racist, defamatory, libelous, treasonous, excessively violent or promotes the use of violence, or provides instruction, information or assistance in causing or carrying out violence against any government, organization, group or individual, or provides guidance, information or assistance with respect to causing damage or security breaches to or Vivox's network or to the network of any other service provider; (vi) commit an act that constitutes a criminal offense, gives rise to civil liability, or otherwise violates any applicable local, state, federal or international law, or (vii) encourage conduct that would constitute a criminal offense, give rise to civil liability, or otherwise violate any applicable local, state, federal or international law. - - 3. SECURITY: In all cases, the user is solely responsible for the security of any device or application it chooses to connect to the Service, including any data stored on or communications passed. - - 4. TRADEMARKS AND COPYRIGHTS. "Vivox," "Powered by Vivox" and similar marks are the property of Vivox. All other names, graphics, logos, marks and trade names used in connection with this Service, are the property of their owners and suppliers and may not be used without permission for any purpose. The copyright in the Vivox website and Service and all related materials are owned by Vivox or its suppliers unless otherwise stated. - - 5. DISCLAIMER OF WARRANTIES. THE SERVICE IS PROVIDED "AS IS" AND "WITH ALL FAULTS," AND PROVIDER AND VIVOX HEREBY DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION (I) WARRANTIES OF MERCHANTIBILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT, AND (II) ANY WARRANTIES CONCERNING THE SECURITY, RELIABILITY OR PERFORMANCE OF THE SERVICE. Certain states prohibit the disclaimer of warranties in certain cases, so the above may not apply to all users in all instances. - - THE DOWNLOADING OR SUBMISSION OF ANY MATERIALS IS DONE AT THE USER'S OWN RISK, AND THE USER IS SOLELY RESPONSIBLE FOR ANY LOSS OR DAMAGE TO ANY CONTENT, IMAGE, COMPUTER SYSTEM OR DATA THAT MAY RESULT FROM USING THE SERVICE. - - 6. EXCLUSION OF DAMAGES. TO THE FULLEST EXTENT ALLOWED BY LAW, VIVOX SHALL NOT BE LIABLE FOR ANY INDIRECT OR CONSEQUENTIAL DAMAGES, INCLUDING INCIDENTAL, SPECIAL, EXEMPLARY AND PUNITIVE DAMAGES, RESULTING FROM THE USE OR PROVISION OF THE SERVICE, EVEN IF THE POSSIBILITY OF SUCH DAMAGES IS KNOWN. Certain states prohibit the limitation of liability in certain cases, so the above may not apply to the user in all instances. - - 7. ENFORCEMENT OF THIS POLICY: Vivox does not routinely monitors the activity of Service accounts for violation of this Policy. Vivox reserves the right at any time to monitor usage, transmissions, and content from time to time to operate the Service; to identify violations of this Policy; and/or to protect the network, the Service and/or other users. If the Service is used in a way that Vivox, in their sole discretion, believe violate this Policy, it may take any responsive actions they deem appropriate, including, but are not limited to, the immediate suspension or termination of all or any portion of the Service. Vivox will have no liability for any of these responsive actions. These actions are not exclusive remedies and Vivox may take any other legal or technical action deemed appropriate. The user expressly authorizes Vivox to cooperate with (i) law enforcement authorities in the investigation of suspected legal violations, and (ii) any system administrators at other Internet service providers or other network or computing facilities in order to enforce this Policy. This cooperation may include making available personally identifiable information about users to law enforcement or system administrators. The failure to enforce this Policy, for whatever reason or for no reason, shall not be construed as a waiver of any right to do so at any time. The user agrees that if any portion of this Policy is held invalid or unenforceable, such portion will be construed consistent with applicable law as nearly as possible, and the remaining portions will remain in full force and effect. The user agrees to indemnify, defend and hold harmless Vivox and its affiliates, suppliers, providers, and agents against all claims and expenses (including reasonable attorney fees) resulting from users engaging in any of the prohibited activities listed in this Policy or resulting from users violating the Policy or any other posted policy related to the Service. The foregoing user indemnification will survive any termination of the user's agreements with Vivox . - - 8. ARBITRATION. Except for the right of a party to seek equitable relief, any disputes arising under or related to this Agreement ("Dispute"), excluding any Dispute relating to the validity or infringement of any intellectual property right, will be resolved by negotiation, mediation and, if necessary, arbitration, as follows. The party raising such Dispute will promptly advise the other party in writing describing in reasonable detail the nature of such Dispute ("Notice of Dispute"). The parties will negotiate in good faith to resolve the Dispute, but if they have not done so within thirty (30) days, the parties will submit the Dispute to a mutually agreed mediation organization. If the parties are unable to resolve the Dispute within sixty (60) days after delivery of the Notice of Dispute, then the Dispute will be resolved by a single arbitrator in a final and binding arbitration under the then current procedural rules of the American Arbitration Association. All proceedings will be conducted in the English language in Boston, Massachusetts. The arbitrator will have no power to modify the terms or conditions of this Agreement, or to award punitive damages. Any award rendered in such arbitration may be enforced by either party in any Court of competent jurisdiction. - - 9. GENERAL TERMS. This Agreement is governed by the laws of the Commonwealth of Massachusetts. No agency, partnership, joint venture, employment or franchise relationship is intended or created by this Agreement. This AUP constitute the entire agreement between the parties concerning the use of the Service. If any provision of this Agreement is found to be unenforceable, it shall be deemed modified to the least extent needed to make the provision enforceable; the remaining terms of this Agreement shall remain in full force and effect. Vivox reserves the right to disclose any information about any user as required by a court order or as recommended by counsel in the context of any action by any government entity or other third party. - - 10. CHANGES TO THIS POLICY. Vivox may revise its Acceptable Use Policy from time to time without prior notice. Any changes will be presented in the latest version at the Vivox web site. All revised copies of the Policy are effective immediately upon a user's first use of the Service after the change has been posted. \ No newline at end of file diff --git a/indra/newview/installers/darwin/firestorm-beta-dmg/background.png b/indra/newview/installers/darwin/firestorm-beta-dmg/background.png index deafaac687..5e90b18d4e 100755 Binary files a/indra/newview/installers/darwin/firestorm-beta-dmg/background.png and b/indra/newview/installers/darwin/firestorm-beta-dmg/background.png differ diff --git a/indra/newview/installers/darwin/firestorm-nightly-dmg/LGPL-license.txt b/indra/newview/installers/darwin/firestorm-nightly-dmg/LGPL-license.txt deleted file mode 100644 index 4362b49151..0000000000 --- a/indra/newview/installers/darwin/firestorm-nightly-dmg/LGPL-license.txt +++ /dev/null @@ -1,502 +0,0 @@ - GNU LESSER GENERAL PUBLIC LICENSE - Version 2.1, February 1999 - - Copyright (C) 1991, 1999 Free Software Foundation, Inc. - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - -[This is the first released version of the Lesser GPL. It also counts - as the successor of the GNU Library Public License, version 2, hence - the version number 2.1.] - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -Licenses are intended to guarantee your freedom to share and change -free software--to make sure the software is free for all its users. - - This license, the Lesser General Public License, applies to some -specially designated software packages--typically libraries--of the -Free Software Foundation and other authors who decide to use it. You -can use it too, but we suggest you first think carefully about whether -this license or the ordinary General Public License is the better -strategy to use in any particular case, based on the explanations below. - - When we speak of free software, we are referring to freedom of use, -not price. Our General Public Licenses are designed to make sure that -you have the freedom to distribute copies of free software (and charge -for this service if you wish); that you receive source code or can get -it if you want it; that you can change the software and use pieces of -it in new free programs; and that you are informed that you can do -these things. - - To protect your rights, we need to make restrictions that forbid -distributors to deny you these rights or to ask you to surrender these -rights. These restrictions translate to certain responsibilities for -you if you distribute copies of the library or if you modify it. - - For example, if you distribute copies of the library, whether gratis -or for a fee, you must give the recipients all the rights that we gave -you. You must make sure that they, too, receive or can get the source -code. If you link other code with the library, you must provide -complete object files to the recipients, so that they can relink them -with the library after making changes to the library and recompiling -it. And you must show them these terms so they know their rights. - - We protect your rights with a two-step method: (1) we copyright the -library, and (2) we offer you this license, which gives you legal -permission to copy, distribute and/or modify the library. - - To protect each distributor, we want to make it very clear that -there is no warranty for the free library. Also, if the library is -modified by someone else and passed on, the recipients should know -that what they have is not the original version, so that the original -author's reputation will not be affected by problems that might be -introduced by others. - - Finally, software patents pose a constant threat to the existence of -any free program. We wish to make sure that a company cannot -effectively restrict the users of a free program by obtaining a -restrictive license from a patent holder. Therefore, we insist that -any patent license obtained for a version of the library must be -consistent with the full freedom of use specified in this license. - - Most GNU software, including some libraries, is covered by the -ordinary GNU General Public License. This license, the GNU Lesser -General Public License, applies to certain designated libraries, and -is quite different from the ordinary General Public License. We use -this license for certain libraries in order to permit linking those -libraries into non-free programs. - - When a program is linked with a library, whether statically or using -a shared library, the combination of the two is legally speaking a -combined work, a derivative of the original library. The ordinary -General Public License therefore permits such linking only if the -entire combination fits its criteria of freedom. The Lesser General -Public License permits more lax criteria for linking other code with -the library. - - We call this license the "Lesser" General Public License because it -does Less to protect the user's freedom than the ordinary General -Public License. It also provides other free software developers Less -of an advantage over competing non-free programs. These disadvantages -are the reason we use the ordinary General Public License for many -libraries. However, the Lesser license provides advantages in certain -special circumstances. - - For example, on rare occasions, there may be a special need to -encourage the widest possible use of a certain library, so that it becomes -a de-facto standard. To achieve this, non-free programs must be -allowed to use the library. A more frequent case is that a free -library does the same job as widely used non-free libraries. In this -case, there is little to gain by limiting the free library to free -software only, so we use the Lesser General Public License. - - In other cases, permission to use a particular library in non-free -programs enables a greater number of people to use a large body of -free software. For example, permission to use the GNU C Library in -non-free programs enables many more people to use the whole GNU -operating system, as well as its variant, the GNU/Linux operating -system. - - Although the Lesser General Public License is Less protective of the -users' freedom, it does ensure that the user of a program that is -linked with the Library has the freedom and the wherewithal to run -that program using a modified version of the Library. - - The precise terms and conditions for copying, distribution and -modification follow. Pay close attention to the difference between a -"work based on the library" and a "work that uses the library". The -former contains code derived from the library, whereas the latter must -be combined with the library in order to run. - - GNU LESSER GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License Agreement applies to any software library or other -program which contains a notice placed by the copyright holder or -other authorized party saying it may be distributed under the terms of -this Lesser General Public License (also called "this License"). -Each licensee is addressed as "you". - - A "library" means a collection of software functions and/or data -prepared so as to be conveniently linked with application programs -(which use some of those functions and data) to form executables. - - The "Library", below, refers to any such software library or work -which has been distributed under these terms. A "work based on the -Library" means either the Library or any derivative work under -copyright law: that is to say, a work containing the Library or a -portion of it, either verbatim or with modifications and/or translated -straightforwardly into another language. (Hereinafter, translation is -included without limitation in the term "modification".) - - "Source code" for a work means the preferred form of the work for -making modifications to it. For a library, complete source code means -all the source code for all modules it contains, plus any associated -interface definition files, plus the scripts used to control compilation -and installation of the library. - - Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running a program using the Library is not restricted, and output from -such a program is covered only if its contents constitute a work based -on the Library (independent of the use of the Library in a tool for -writing it). Whether that is true depends on what the Library does -and what the program that uses the Library does. - - 1. You may copy and distribute verbatim copies of the Library's -complete source code as you receive it, in any medium, provided that -you conspicuously and appropriately publish on each copy an -appropriate copyright notice and disclaimer of warranty; keep intact -all the notices that refer to this License and to the absence of any -warranty; and distribute a copy of this License along with the -Library. - - You may charge a fee for the physical act of transferring a copy, -and you may at your option offer warranty protection in exchange for a -fee. - - 2. You may modify your copy or copies of the Library or any portion -of it, thus forming a work based on the Library, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) The modified work must itself be a software library. - - b) You must cause the files modified to carry prominent notices - stating that you changed the files and the date of any change. - - c) You must cause the whole of the work to be licensed at no - charge to all third parties under the terms of this License. - - d) If a facility in the modified Library refers to a function or a - table of data to be supplied by an application program that uses - the facility, other than as an argument passed when the facility - is invoked, then you must make a good faith effort to ensure that, - in the event an application does not supply such function or - table, the facility still operates, and performs whatever part of - its purpose remains meaningful. - - (For example, a function in a library to compute square roots has - a purpose that is entirely well-defined independent of the - application. Therefore, Subsection 2d requires that any - application-supplied function or table used by this function must - be optional: if the application does not supply it, the square - root function must still compute square roots.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Library, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Library, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote -it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Library. - -In addition, mere aggregation of another work not based on the Library -with the Library (or with a work based on the Library) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may opt to apply the terms of the ordinary GNU General Public -License instead of this License to a given copy of the Library. To do -this, you must alter all the notices that refer to this License, so -that they refer to the ordinary GNU General Public License, version 2, -instead of to this License. (If a newer version than version 2 of the -ordinary GNU General Public License has appeared, then you can specify -that version instead if you wish.) Do not make any other change in -these notices. - - Once this change is made in a given copy, it is irreversible for -that copy, so the ordinary GNU General Public License applies to all -subsequent copies and derivative works made from that copy. - - This option is useful when you wish to copy part of the code of -the Library into a program that is not a library. - - 4. You may copy and distribute the Library (or a portion or -derivative of it, under Section 2) in object code or executable form -under the terms of Sections 1 and 2 above provided that you accompany -it with the complete corresponding machine-readable source code, which -must be distributed under the terms of Sections 1 and 2 above on a -medium customarily used for software interchange. - - If distribution of object code is made by offering access to copy -from a designated place, then offering equivalent access to copy the -source code from the same place satisfies the requirement to -distribute the source code, even though third parties are not -compelled to copy the source along with the object code. - - 5. A program that contains no derivative of any portion of the -Library, but is designed to work with the Library by being compiled or -linked with it, is called a "work that uses the Library". Such a -work, in isolation, is not a derivative work of the Library, and -therefore falls outside the scope of this License. - - However, linking a "work that uses the Library" with the Library -creates an executable that is a derivative of the Library (because it -contains portions of the Library), rather than a "work that uses the -library". The executable is therefore covered by this License. -Section 6 states terms for distribution of such executables. - - When a "work that uses the Library" uses material from a header file -that is part of the Library, the object code for the work may be a -derivative work of the Library even though the source code is not. -Whether this is true is especially significant if the work can be -linked without the Library, or if the work is itself a library. The -threshold for this to be true is not precisely defined by law. - - If such an object file uses only numerical parameters, data -structure layouts and accessors, and small macros and small inline -functions (ten lines or less in length), then the use of the object -file is unrestricted, regardless of whether it is legally a derivative -work. (Executables containing this object code plus portions of the -Library will still fall under Section 6.) - - Otherwise, if the work is a derivative of the Library, you may -distribute the object code for the work under the terms of Section 6. -Any executables containing that work also fall under Section 6, -whether or not they are linked directly with the Library itself. - - 6. As an exception to the Sections above, you may also combine or -link a "work that uses the Library" with the Library to produce a -work containing portions of the Library, and distribute that work -under terms of your choice, provided that the terms permit -modification of the work for the customer's own use and reverse -engineering for debugging such modifications. - - You must give prominent notice with each copy of the work that the -Library is used in it and that the Library and its use are covered by -this License. You must supply a copy of this License. If the work -during execution displays copyright notices, you must include the -copyright notice for the Library among them, as well as a reference -directing the user to the copy of this License. Also, you must do one -of these things: - - a) Accompany the work with the complete corresponding - machine-readable source code for the Library including whatever - changes were used in the work (which must be distributed under - Sections 1 and 2 above); and, if the work is an executable linked - with the Library, with the complete machine-readable "work that - uses the Library", as object code and/or source code, so that the - user can modify the Library and then relink to produce a modified - executable containing the modified Library. (It is understood - that the user who changes the contents of definitions files in the - Library will not necessarily be able to recompile the application - to use the modified definitions.) - - b) Use a suitable shared library mechanism for linking with the - Library. A suitable mechanism is one that (1) uses at run time a - copy of the library already present on the user's computer system, - rather than copying library functions into the executable, and (2) - will operate properly with a modified version of the library, if - the user installs one, as long as the modified version is - interface-compatible with the version that the work was made with. - - c) Accompany the work with a written offer, valid for at - least three years, to give the same user the materials - specified in Subsection 6a, above, for a charge no more - than the cost of performing this distribution. - - d) If distribution of the work is made by offering access to copy - from a designated place, offer equivalent access to copy the above - specified materials from the same place. - - e) Verify that the user has already received a copy of these - materials or that you have already sent this user a copy. - - For an executable, the required form of the "work that uses the -Library" must include any data and utility programs needed for -reproducing the executable from it. However, as a special exception, -the materials to be distributed need not include anything that is -normally distributed (in either source or binary form) with the major -components (compiler, kernel, and so on) of the operating system on -which the executable runs, unless that component itself accompanies -the executable. - - It may happen that this requirement contradicts the license -restrictions of other proprietary libraries that do not normally -accompany the operating system. Such a contradiction means you cannot -use both them and the Library together in an executable that you -distribute. - - 7. You may place library facilities that are a work based on the -Library side-by-side in a single library together with other library -facilities not covered by this License, and distribute such a combined -library, provided that the separate distribution of the work based on -the Library and of the other library facilities is otherwise -permitted, and provided that you do these two things: - - a) Accompany the combined library with a copy of the same work - based on the Library, uncombined with any other library - facilities. This must be distributed under the terms of the - Sections above. - - b) Give prominent notice with the combined library of the fact - that part of it is a work based on the Library, and explaining - where to find the accompanying uncombined form of the same work. - - 8. You may not copy, modify, sublicense, link with, or distribute -the Library except as expressly provided under this License. Any -attempt otherwise to copy, modify, sublicense, link with, or -distribute the Library is void, and will automatically terminate your -rights under this License. However, parties who have received copies, -or rights, from you under this License will not have their licenses -terminated so long as such parties remain in full compliance. - - 9. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Library or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Library (or any work based on the -Library), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Library or works based on it. - - 10. Each time you redistribute the Library (or any work based on the -Library), the recipient automatically receives a license from the -original licensor to copy, distribute, link with or modify the Library -subject to these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties with -this License. - - 11. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Library at all. For example, if a patent -license would not permit royalty-free redistribution of the Library by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Library. - -If any portion of this section is held invalid or unenforceable under any -particular circumstance, the balance of the section is intended to apply, -and the section as a whole is intended to apply in other circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 12. If the distribution and/or use of the Library is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Library under this License may add -an explicit geographical distribution limitation excluding those countries, -so that distribution is permitted only in or among countries not thus -excluded. In such case, this License incorporates the limitation as if -written in the body of this License. - - 13. The Free Software Foundation may publish revised and/or new -versions of the Lesser General Public License from time to time. -Such new versions will be similar in spirit to the present version, -but may differ in detail to address new problems or concerns. - -Each version is given a distinguishing version number. If the Library -specifies a version number of this License which applies to it and -"any later version", you have the option of following the terms and -conditions either of that version or of any later version published by -the Free Software Foundation. If the Library does not specify a -license version number, you may choose any version ever published by -the Free Software Foundation. - - 14. If you wish to incorporate parts of the Library into other free -programs whose distribution conditions are incompatible with these, -write to the author to ask for permission. For software which is -copyrighted by the Free Software Foundation, write to the Free -Software Foundation; we sometimes make exceptions for this. Our -decision will be guided by the two goals of preserving the free status -of all derivatives of our free software and of promoting the sharing -and reuse of software generally. - - NO WARRANTY - - 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO -WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. -EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR -OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY -KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE -LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME -THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN -WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY -AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU -FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR -CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE -LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING -RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A -FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF -SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH -DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Libraries - - If you develop a new library, and you want it to be of the greatest -possible use to the public, we recommend making it free software that -everyone can redistribute and change. You can do so by permitting -redistribution under these terms (or, alternatively, under the terms of the -ordinary General Public License). - - To apply these terms, attach the following notices to the library. It is -safest to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least the -"copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -Also add information on how to contact you by electronic and paper mail. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the library, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the - library `Frob' (a library for tweaking knobs) written by James Random Hacker. - - , 1 April 1990 - Ty Coon, President of Vice - -That's all there is to it! diff --git a/indra/newview/installers/darwin/firestorm-nightly-dmg/VivoxAUP.txt b/indra/newview/installers/darwin/firestorm-nightly-dmg/VivoxAUP.txt deleted file mode 100644 index 6413f8b16a..0000000000 --- a/indra/newview/installers/darwin/firestorm-nightly-dmg/VivoxAUP.txt +++ /dev/null @@ -1,23 +0,0 @@ -Acceptable Use Policy (AUP) - - 1. BACKGROUND: Users of the online voice services provided by Vivox, Inc. ("Vivox") (the "Service"), through the act of utilizing the Service, agree to adhere to this Acceptable Use Policy (the "Policy"). Vivox reserves the right to immediately terminate a user's access to the Service if the user engages in any of the activities prohibited by this Policy or uses the Service contrary to this Policy. Each user is responsible for all activities conducted under its account. The user is also responsible for adhering to any policy set forth by any other service provider accessed through the Service; Vivox, and its suppliers and providers, assume no responsibility or liability for a user's failure to comply with the Policy. The user acknowledges that Vivox may have access to information about or provided by the user, including diagnostic information sent automatically after a problem or error, and agrees to such access and use. - - 2. PROHIBITED USES AND ACTIVITIES: Users shall not provide inaccurate or misleading information to Vivox or use the Service to: (i) access any other person's computer or computer system, software, or data without their knowledge and consent; or breach the security of another user; or attempt to circumvent the user authentication or security of any host, network, system, or account, which includes, but is not limited to, accessing data not intended for the user, logging into or making use of a server or account the user is not expressly authorized to access, or probing the security of other hosts, networks, or accounts; or use automated means (such as robots and spiders) to obtain information from Vivox's website or, though it, from other websites; (ii) interfere with computer networking or telecommunications service to any user, host or network, including, without limitation, denial of service attacks, flooding of a network, overloading a service, improper seizing and abuse of operator privileges and attempts to "crash" a host; (iii) violate the rules, regulations, or policies applicable to any network, server, computer database, or service that accessed by the user; (iv) transmit, re-transmit, or store any content or to engage in any activity that infringes the intellectual property rights or privacy rights of Vivox or any individual, group or entity, including but not limited to any rights protected by any copyright, patent, trademark, trade secret, trade dress, right of privacy, right of publicity, moral rights or other intellectual property right now known or later recognized by statute, judicial decision or regulation; (v) host, post, transmit, or re-transmit any content or material that is threatening, harassing, obscene, indecent, pornographic, hateful, malicious, racist, defamatory, libelous, treasonous, excessively violent or promotes the use of violence, or provides instruction, information or assistance in causing or carrying out violence against any government, organization, group or individual, or provides guidance, information or assistance with respect to causing damage or security breaches to or Vivox's network or to the network of any other service provider; (vi) commit an act that constitutes a criminal offense, gives rise to civil liability, or otherwise violates any applicable local, state, federal or international law, or (vii) encourage conduct that would constitute a criminal offense, give rise to civil liability, or otherwise violate any applicable local, state, federal or international law. - - 3. SECURITY: In all cases, the user is solely responsible for the security of any device or application it chooses to connect to the Service, including any data stored on or communications passed. - - 4. TRADEMARKS AND COPYRIGHTS. "Vivox," "Powered by Vivox" and similar marks are the property of Vivox. All other names, graphics, logos, marks and trade names used in connection with this Service, are the property of their owners and suppliers and may not be used without permission for any purpose. The copyright in the Vivox website and Service and all related materials are owned by Vivox or its suppliers unless otherwise stated. - - 5. DISCLAIMER OF WARRANTIES. THE SERVICE IS PROVIDED "AS IS" AND "WITH ALL FAULTS," AND PROVIDER AND VIVOX HEREBY DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION (I) WARRANTIES OF MERCHANTIBILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT, AND (II) ANY WARRANTIES CONCERNING THE SECURITY, RELIABILITY OR PERFORMANCE OF THE SERVICE. Certain states prohibit the disclaimer of warranties in certain cases, so the above may not apply to all users in all instances. - - THE DOWNLOADING OR SUBMISSION OF ANY MATERIALS IS DONE AT THE USER'S OWN RISK, AND THE USER IS SOLELY RESPONSIBLE FOR ANY LOSS OR DAMAGE TO ANY CONTENT, IMAGE, COMPUTER SYSTEM OR DATA THAT MAY RESULT FROM USING THE SERVICE. - - 6. EXCLUSION OF DAMAGES. TO THE FULLEST EXTENT ALLOWED BY LAW, VIVOX SHALL NOT BE LIABLE FOR ANY INDIRECT OR CONSEQUENTIAL DAMAGES, INCLUDING INCIDENTAL, SPECIAL, EXEMPLARY AND PUNITIVE DAMAGES, RESULTING FROM THE USE OR PROVISION OF THE SERVICE, EVEN IF THE POSSIBILITY OF SUCH DAMAGES IS KNOWN. Certain states prohibit the limitation of liability in certain cases, so the above may not apply to the user in all instances. - - 7. ENFORCEMENT OF THIS POLICY: Vivox does not routinely monitors the activity of Service accounts for violation of this Policy. Vivox reserves the right at any time to monitor usage, transmissions, and content from time to time to operate the Service; to identify violations of this Policy; and/or to protect the network, the Service and/or other users. If the Service is used in a way that Vivox, in their sole discretion, believe violate this Policy, it may take any responsive actions they deem appropriate, including, but are not limited to, the immediate suspension or termination of all or any portion of the Service. Vivox will have no liability for any of these responsive actions. These actions are not exclusive remedies and Vivox may take any other legal or technical action deemed appropriate. The user expressly authorizes Vivox to cooperate with (i) law enforcement authorities in the investigation of suspected legal violations, and (ii) any system administrators at other Internet service providers or other network or computing facilities in order to enforce this Policy. This cooperation may include making available personally identifiable information about users to law enforcement or system administrators. The failure to enforce this Policy, for whatever reason or for no reason, shall not be construed as a waiver of any right to do so at any time. The user agrees that if any portion of this Policy is held invalid or unenforceable, such portion will be construed consistent with applicable law as nearly as possible, and the remaining portions will remain in full force and effect. The user agrees to indemnify, defend and hold harmless Vivox and its affiliates, suppliers, providers, and agents against all claims and expenses (including reasonable attorney fees) resulting from users engaging in any of the prohibited activities listed in this Policy or resulting from users violating the Policy or any other posted policy related to the Service. The foregoing user indemnification will survive any termination of the user's agreements with Vivox . - - 8. ARBITRATION. Except for the right of a party to seek equitable relief, any disputes arising under or related to this Agreement ("Dispute"), excluding any Dispute relating to the validity or infringement of any intellectual property right, will be resolved by negotiation, mediation and, if necessary, arbitration, as follows. The party raising such Dispute will promptly advise the other party in writing describing in reasonable detail the nature of such Dispute ("Notice of Dispute"). The parties will negotiate in good faith to resolve the Dispute, but if they have not done so within thirty (30) days, the parties will submit the Dispute to a mutually agreed mediation organization. If the parties are unable to resolve the Dispute within sixty (60) days after delivery of the Notice of Dispute, then the Dispute will be resolved by a single arbitrator in a final and binding arbitration under the then current procedural rules of the American Arbitration Association. All proceedings will be conducted in the English language in Boston, Massachusetts. The arbitrator will have no power to modify the terms or conditions of this Agreement, or to award punitive damages. Any award rendered in such arbitration may be enforced by either party in any Court of competent jurisdiction. - - 9. GENERAL TERMS. This Agreement is governed by the laws of the Commonwealth of Massachusetts. No agency, partnership, joint venture, employment or franchise relationship is intended or created by this Agreement. This AUP constitute the entire agreement between the parties concerning the use of the Service. If any provision of this Agreement is found to be unenforceable, it shall be deemed modified to the least extent needed to make the provision enforceable; the remaining terms of this Agreement shall remain in full force and effect. Vivox reserves the right to disclose any information about any user as required by a court order or as recommended by counsel in the context of any action by any government entity or other third party. - - 10. CHANGES TO THIS POLICY. Vivox may revise its Acceptable Use Policy from time to time without prior notice. Any changes will be presented in the latest version at the Vivox web site. All revised copies of the Policy are effective immediately upon a user's first use of the Service after the change has been posted. \ No newline at end of file diff --git a/indra/newview/installers/darwin/firestorm-nightly-dmg/background.png b/indra/newview/installers/darwin/firestorm-nightly-dmg/background.png index 28012bbbc5..5e90b18d4e 100755 Binary files a/indra/newview/installers/darwin/firestorm-nightly-dmg/background.png and b/indra/newview/installers/darwin/firestorm-nightly-dmg/background.png differ diff --git a/indra/newview/installers/darwin/firestorm-private-dmg/LGPL-license.txt b/indra/newview/installers/darwin/firestorm-private-dmg/LGPL-license.txt deleted file mode 100644 index 4362b49151..0000000000 --- a/indra/newview/installers/darwin/firestorm-private-dmg/LGPL-license.txt +++ /dev/null @@ -1,502 +0,0 @@ - GNU LESSER GENERAL PUBLIC LICENSE - Version 2.1, February 1999 - - Copyright (C) 1991, 1999 Free Software Foundation, Inc. - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - -[This is the first released version of the Lesser GPL. It also counts - as the successor of the GNU Library Public License, version 2, hence - the version number 2.1.] - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -Licenses are intended to guarantee your freedom to share and change -free software--to make sure the software is free for all its users. - - This license, the Lesser General Public License, applies to some -specially designated software packages--typically libraries--of the -Free Software Foundation and other authors who decide to use it. You -can use it too, but we suggest you first think carefully about whether -this license or the ordinary General Public License is the better -strategy to use in any particular case, based on the explanations below. - - When we speak of free software, we are referring to freedom of use, -not price. Our General Public Licenses are designed to make sure that -you have the freedom to distribute copies of free software (and charge -for this service if you wish); that you receive source code or can get -it if you want it; that you can change the software and use pieces of -it in new free programs; and that you are informed that you can do -these things. - - To protect your rights, we need to make restrictions that forbid -distributors to deny you these rights or to ask you to surrender these -rights. These restrictions translate to certain responsibilities for -you if you distribute copies of the library or if you modify it. - - For example, if you distribute copies of the library, whether gratis -or for a fee, you must give the recipients all the rights that we gave -you. You must make sure that they, too, receive or can get the source -code. If you link other code with the library, you must provide -complete object files to the recipients, so that they can relink them -with the library after making changes to the library and recompiling -it. And you must show them these terms so they know their rights. - - We protect your rights with a two-step method: (1) we copyright the -library, and (2) we offer you this license, which gives you legal -permission to copy, distribute and/or modify the library. - - To protect each distributor, we want to make it very clear that -there is no warranty for the free library. Also, if the library is -modified by someone else and passed on, the recipients should know -that what they have is not the original version, so that the original -author's reputation will not be affected by problems that might be -introduced by others. - - Finally, software patents pose a constant threat to the existence of -any free program. We wish to make sure that a company cannot -effectively restrict the users of a free program by obtaining a -restrictive license from a patent holder. Therefore, we insist that -any patent license obtained for a version of the library must be -consistent with the full freedom of use specified in this license. - - Most GNU software, including some libraries, is covered by the -ordinary GNU General Public License. This license, the GNU Lesser -General Public License, applies to certain designated libraries, and -is quite different from the ordinary General Public License. We use -this license for certain libraries in order to permit linking those -libraries into non-free programs. - - When a program is linked with a library, whether statically or using -a shared library, the combination of the two is legally speaking a -combined work, a derivative of the original library. The ordinary -General Public License therefore permits such linking only if the -entire combination fits its criteria of freedom. The Lesser General -Public License permits more lax criteria for linking other code with -the library. - - We call this license the "Lesser" General Public License because it -does Less to protect the user's freedom than the ordinary General -Public License. It also provides other free software developers Less -of an advantage over competing non-free programs. These disadvantages -are the reason we use the ordinary General Public License for many -libraries. However, the Lesser license provides advantages in certain -special circumstances. - - For example, on rare occasions, there may be a special need to -encourage the widest possible use of a certain library, so that it becomes -a de-facto standard. To achieve this, non-free programs must be -allowed to use the library. A more frequent case is that a free -library does the same job as widely used non-free libraries. In this -case, there is little to gain by limiting the free library to free -software only, so we use the Lesser General Public License. - - In other cases, permission to use a particular library in non-free -programs enables a greater number of people to use a large body of -free software. For example, permission to use the GNU C Library in -non-free programs enables many more people to use the whole GNU -operating system, as well as its variant, the GNU/Linux operating -system. - - Although the Lesser General Public License is Less protective of the -users' freedom, it does ensure that the user of a program that is -linked with the Library has the freedom and the wherewithal to run -that program using a modified version of the Library. - - The precise terms and conditions for copying, distribution and -modification follow. Pay close attention to the difference between a -"work based on the library" and a "work that uses the library". The -former contains code derived from the library, whereas the latter must -be combined with the library in order to run. - - GNU LESSER GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License Agreement applies to any software library or other -program which contains a notice placed by the copyright holder or -other authorized party saying it may be distributed under the terms of -this Lesser General Public License (also called "this License"). -Each licensee is addressed as "you". - - A "library" means a collection of software functions and/or data -prepared so as to be conveniently linked with application programs -(which use some of those functions and data) to form executables. - - The "Library", below, refers to any such software library or work -which has been distributed under these terms. A "work based on the -Library" means either the Library or any derivative work under -copyright law: that is to say, a work containing the Library or a -portion of it, either verbatim or with modifications and/or translated -straightforwardly into another language. (Hereinafter, translation is -included without limitation in the term "modification".) - - "Source code" for a work means the preferred form of the work for -making modifications to it. For a library, complete source code means -all the source code for all modules it contains, plus any associated -interface definition files, plus the scripts used to control compilation -and installation of the library. - - Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running a program using the Library is not restricted, and output from -such a program is covered only if its contents constitute a work based -on the Library (independent of the use of the Library in a tool for -writing it). Whether that is true depends on what the Library does -and what the program that uses the Library does. - - 1. You may copy and distribute verbatim copies of the Library's -complete source code as you receive it, in any medium, provided that -you conspicuously and appropriately publish on each copy an -appropriate copyright notice and disclaimer of warranty; keep intact -all the notices that refer to this License and to the absence of any -warranty; and distribute a copy of this License along with the -Library. - - You may charge a fee for the physical act of transferring a copy, -and you may at your option offer warranty protection in exchange for a -fee. - - 2. You may modify your copy or copies of the Library or any portion -of it, thus forming a work based on the Library, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) The modified work must itself be a software library. - - b) You must cause the files modified to carry prominent notices - stating that you changed the files and the date of any change. - - c) You must cause the whole of the work to be licensed at no - charge to all third parties under the terms of this License. - - d) If a facility in the modified Library refers to a function or a - table of data to be supplied by an application program that uses - the facility, other than as an argument passed when the facility - is invoked, then you must make a good faith effort to ensure that, - in the event an application does not supply such function or - table, the facility still operates, and performs whatever part of - its purpose remains meaningful. - - (For example, a function in a library to compute square roots has - a purpose that is entirely well-defined independent of the - application. Therefore, Subsection 2d requires that any - application-supplied function or table used by this function must - be optional: if the application does not supply it, the square - root function must still compute square roots.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Library, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Library, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote -it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Library. - -In addition, mere aggregation of another work not based on the Library -with the Library (or with a work based on the Library) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may opt to apply the terms of the ordinary GNU General Public -License instead of this License to a given copy of the Library. To do -this, you must alter all the notices that refer to this License, so -that they refer to the ordinary GNU General Public License, version 2, -instead of to this License. (If a newer version than version 2 of the -ordinary GNU General Public License has appeared, then you can specify -that version instead if you wish.) Do not make any other change in -these notices. - - Once this change is made in a given copy, it is irreversible for -that copy, so the ordinary GNU General Public License applies to all -subsequent copies and derivative works made from that copy. - - This option is useful when you wish to copy part of the code of -the Library into a program that is not a library. - - 4. You may copy and distribute the Library (or a portion or -derivative of it, under Section 2) in object code or executable form -under the terms of Sections 1 and 2 above provided that you accompany -it with the complete corresponding machine-readable source code, which -must be distributed under the terms of Sections 1 and 2 above on a -medium customarily used for software interchange. - - If distribution of object code is made by offering access to copy -from a designated place, then offering equivalent access to copy the -source code from the same place satisfies the requirement to -distribute the source code, even though third parties are not -compelled to copy the source along with the object code. - - 5. A program that contains no derivative of any portion of the -Library, but is designed to work with the Library by being compiled or -linked with it, is called a "work that uses the Library". Such a -work, in isolation, is not a derivative work of the Library, and -therefore falls outside the scope of this License. - - However, linking a "work that uses the Library" with the Library -creates an executable that is a derivative of the Library (because it -contains portions of the Library), rather than a "work that uses the -library". The executable is therefore covered by this License. -Section 6 states terms for distribution of such executables. - - When a "work that uses the Library" uses material from a header file -that is part of the Library, the object code for the work may be a -derivative work of the Library even though the source code is not. -Whether this is true is especially significant if the work can be -linked without the Library, or if the work is itself a library. The -threshold for this to be true is not precisely defined by law. - - If such an object file uses only numerical parameters, data -structure layouts and accessors, and small macros and small inline -functions (ten lines or less in length), then the use of the object -file is unrestricted, regardless of whether it is legally a derivative -work. (Executables containing this object code plus portions of the -Library will still fall under Section 6.) - - Otherwise, if the work is a derivative of the Library, you may -distribute the object code for the work under the terms of Section 6. -Any executables containing that work also fall under Section 6, -whether or not they are linked directly with the Library itself. - - 6. As an exception to the Sections above, you may also combine or -link a "work that uses the Library" with the Library to produce a -work containing portions of the Library, and distribute that work -under terms of your choice, provided that the terms permit -modification of the work for the customer's own use and reverse -engineering for debugging such modifications. - - You must give prominent notice with each copy of the work that the -Library is used in it and that the Library and its use are covered by -this License. You must supply a copy of this License. If the work -during execution displays copyright notices, you must include the -copyright notice for the Library among them, as well as a reference -directing the user to the copy of this License. Also, you must do one -of these things: - - a) Accompany the work with the complete corresponding - machine-readable source code for the Library including whatever - changes were used in the work (which must be distributed under - Sections 1 and 2 above); and, if the work is an executable linked - with the Library, with the complete machine-readable "work that - uses the Library", as object code and/or source code, so that the - user can modify the Library and then relink to produce a modified - executable containing the modified Library. (It is understood - that the user who changes the contents of definitions files in the - Library will not necessarily be able to recompile the application - to use the modified definitions.) - - b) Use a suitable shared library mechanism for linking with the - Library. A suitable mechanism is one that (1) uses at run time a - copy of the library already present on the user's computer system, - rather than copying library functions into the executable, and (2) - will operate properly with a modified version of the library, if - the user installs one, as long as the modified version is - interface-compatible with the version that the work was made with. - - c) Accompany the work with a written offer, valid for at - least three years, to give the same user the materials - specified in Subsection 6a, above, for a charge no more - than the cost of performing this distribution. - - d) If distribution of the work is made by offering access to copy - from a designated place, offer equivalent access to copy the above - specified materials from the same place. - - e) Verify that the user has already received a copy of these - materials or that you have already sent this user a copy. - - For an executable, the required form of the "work that uses the -Library" must include any data and utility programs needed for -reproducing the executable from it. However, as a special exception, -the materials to be distributed need not include anything that is -normally distributed (in either source or binary form) with the major -components (compiler, kernel, and so on) of the operating system on -which the executable runs, unless that component itself accompanies -the executable. - - It may happen that this requirement contradicts the license -restrictions of other proprietary libraries that do not normally -accompany the operating system. Such a contradiction means you cannot -use both them and the Library together in an executable that you -distribute. - - 7. You may place library facilities that are a work based on the -Library side-by-side in a single library together with other library -facilities not covered by this License, and distribute such a combined -library, provided that the separate distribution of the work based on -the Library and of the other library facilities is otherwise -permitted, and provided that you do these two things: - - a) Accompany the combined library with a copy of the same work - based on the Library, uncombined with any other library - facilities. This must be distributed under the terms of the - Sections above. - - b) Give prominent notice with the combined library of the fact - that part of it is a work based on the Library, and explaining - where to find the accompanying uncombined form of the same work. - - 8. You may not copy, modify, sublicense, link with, or distribute -the Library except as expressly provided under this License. Any -attempt otherwise to copy, modify, sublicense, link with, or -distribute the Library is void, and will automatically terminate your -rights under this License. However, parties who have received copies, -or rights, from you under this License will not have their licenses -terminated so long as such parties remain in full compliance. - - 9. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Library or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Library (or any work based on the -Library), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Library or works based on it. - - 10. Each time you redistribute the Library (or any work based on the -Library), the recipient automatically receives a license from the -original licensor to copy, distribute, link with or modify the Library -subject to these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties with -this License. - - 11. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Library at all. For example, if a patent -license would not permit royalty-free redistribution of the Library by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Library. - -If any portion of this section is held invalid or unenforceable under any -particular circumstance, the balance of the section is intended to apply, -and the section as a whole is intended to apply in other circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 12. If the distribution and/or use of the Library is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Library under this License may add -an explicit geographical distribution limitation excluding those countries, -so that distribution is permitted only in or among countries not thus -excluded. In such case, this License incorporates the limitation as if -written in the body of this License. - - 13. The Free Software Foundation may publish revised and/or new -versions of the Lesser General Public License from time to time. -Such new versions will be similar in spirit to the present version, -but may differ in detail to address new problems or concerns. - -Each version is given a distinguishing version number. If the Library -specifies a version number of this License which applies to it and -"any later version", you have the option of following the terms and -conditions either of that version or of any later version published by -the Free Software Foundation. If the Library does not specify a -license version number, you may choose any version ever published by -the Free Software Foundation. - - 14. If you wish to incorporate parts of the Library into other free -programs whose distribution conditions are incompatible with these, -write to the author to ask for permission. For software which is -copyrighted by the Free Software Foundation, write to the Free -Software Foundation; we sometimes make exceptions for this. Our -decision will be guided by the two goals of preserving the free status -of all derivatives of our free software and of promoting the sharing -and reuse of software generally. - - NO WARRANTY - - 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO -WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. -EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR -OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY -KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE -LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME -THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN -WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY -AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU -FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR -CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE -LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING -RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A -FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF -SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH -DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Libraries - - If you develop a new library, and you want it to be of the greatest -possible use to the public, we recommend making it free software that -everyone can redistribute and change. You can do so by permitting -redistribution under these terms (or, alternatively, under the terms of the -ordinary General Public License). - - To apply these terms, attach the following notices to the library. It is -safest to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least the -"copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -Also add information on how to contact you by electronic and paper mail. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the library, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the - library `Frob' (a library for tweaking knobs) written by James Random Hacker. - - , 1 April 1990 - Ty Coon, President of Vice - -That's all there is to it! diff --git a/indra/newview/installers/darwin/firestorm-private-dmg/VivoxAUP.txt b/indra/newview/installers/darwin/firestorm-private-dmg/VivoxAUP.txt deleted file mode 100644 index 6413f8b16a..0000000000 --- a/indra/newview/installers/darwin/firestorm-private-dmg/VivoxAUP.txt +++ /dev/null @@ -1,23 +0,0 @@ -Acceptable Use Policy (AUP) - - 1. BACKGROUND: Users of the online voice services provided by Vivox, Inc. ("Vivox") (the "Service"), through the act of utilizing the Service, agree to adhere to this Acceptable Use Policy (the "Policy"). Vivox reserves the right to immediately terminate a user's access to the Service if the user engages in any of the activities prohibited by this Policy or uses the Service contrary to this Policy. Each user is responsible for all activities conducted under its account. The user is also responsible for adhering to any policy set forth by any other service provider accessed through the Service; Vivox, and its suppliers and providers, assume no responsibility or liability for a user's failure to comply with the Policy. The user acknowledges that Vivox may have access to information about or provided by the user, including diagnostic information sent automatically after a problem or error, and agrees to such access and use. - - 2. PROHIBITED USES AND ACTIVITIES: Users shall not provide inaccurate or misleading information to Vivox or use the Service to: (i) access any other person's computer or computer system, software, or data without their knowledge and consent; or breach the security of another user; or attempt to circumvent the user authentication or security of any host, network, system, or account, which includes, but is not limited to, accessing data not intended for the user, logging into or making use of a server or account the user is not expressly authorized to access, or probing the security of other hosts, networks, or accounts; or use automated means (such as robots and spiders) to obtain information from Vivox's website or, though it, from other websites; (ii) interfere with computer networking or telecommunications service to any user, host or network, including, without limitation, denial of service attacks, flooding of a network, overloading a service, improper seizing and abuse of operator privileges and attempts to "crash" a host; (iii) violate the rules, regulations, or policies applicable to any network, server, computer database, or service that accessed by the user; (iv) transmit, re-transmit, or store any content or to engage in any activity that infringes the intellectual property rights or privacy rights of Vivox or any individual, group or entity, including but not limited to any rights protected by any copyright, patent, trademark, trade secret, trade dress, right of privacy, right of publicity, moral rights or other intellectual property right now known or later recognized by statute, judicial decision or regulation; (v) host, post, transmit, or re-transmit any content or material that is threatening, harassing, obscene, indecent, pornographic, hateful, malicious, racist, defamatory, libelous, treasonous, excessively violent or promotes the use of violence, or provides instruction, information or assistance in causing or carrying out violence against any government, organization, group or individual, or provides guidance, information or assistance with respect to causing damage or security breaches to or Vivox's network or to the network of any other service provider; (vi) commit an act that constitutes a criminal offense, gives rise to civil liability, or otherwise violates any applicable local, state, federal or international law, or (vii) encourage conduct that would constitute a criminal offense, give rise to civil liability, or otherwise violate any applicable local, state, federal or international law. - - 3. SECURITY: In all cases, the user is solely responsible for the security of any device or application it chooses to connect to the Service, including any data stored on or communications passed. - - 4. TRADEMARKS AND COPYRIGHTS. "Vivox," "Powered by Vivox" and similar marks are the property of Vivox. All other names, graphics, logos, marks and trade names used in connection with this Service, are the property of their owners and suppliers and may not be used without permission for any purpose. The copyright in the Vivox website and Service and all related materials are owned by Vivox or its suppliers unless otherwise stated. - - 5. DISCLAIMER OF WARRANTIES. THE SERVICE IS PROVIDED "AS IS" AND "WITH ALL FAULTS," AND PROVIDER AND VIVOX HEREBY DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION (I) WARRANTIES OF MERCHANTIBILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT, AND (II) ANY WARRANTIES CONCERNING THE SECURITY, RELIABILITY OR PERFORMANCE OF THE SERVICE. Certain states prohibit the disclaimer of warranties in certain cases, so the above may not apply to all users in all instances. - - THE DOWNLOADING OR SUBMISSION OF ANY MATERIALS IS DONE AT THE USER'S OWN RISK, AND THE USER IS SOLELY RESPONSIBLE FOR ANY LOSS OR DAMAGE TO ANY CONTENT, IMAGE, COMPUTER SYSTEM OR DATA THAT MAY RESULT FROM USING THE SERVICE. - - 6. EXCLUSION OF DAMAGES. TO THE FULLEST EXTENT ALLOWED BY LAW, VIVOX SHALL NOT BE LIABLE FOR ANY INDIRECT OR CONSEQUENTIAL DAMAGES, INCLUDING INCIDENTAL, SPECIAL, EXEMPLARY AND PUNITIVE DAMAGES, RESULTING FROM THE USE OR PROVISION OF THE SERVICE, EVEN IF THE POSSIBILITY OF SUCH DAMAGES IS KNOWN. Certain states prohibit the limitation of liability in certain cases, so the above may not apply to the user in all instances. - - 7. ENFORCEMENT OF THIS POLICY: Vivox does not routinely monitors the activity of Service accounts for violation of this Policy. Vivox reserves the right at any time to monitor usage, transmissions, and content from time to time to operate the Service; to identify violations of this Policy; and/or to protect the network, the Service and/or other users. If the Service is used in a way that Vivox, in their sole discretion, believe violate this Policy, it may take any responsive actions they deem appropriate, including, but are not limited to, the immediate suspension or termination of all or any portion of the Service. Vivox will have no liability for any of these responsive actions. These actions are not exclusive remedies and Vivox may take any other legal or technical action deemed appropriate. The user expressly authorizes Vivox to cooperate with (i) law enforcement authorities in the investigation of suspected legal violations, and (ii) any system administrators at other Internet service providers or other network or computing facilities in order to enforce this Policy. This cooperation may include making available personally identifiable information about users to law enforcement or system administrators. The failure to enforce this Policy, for whatever reason or for no reason, shall not be construed as a waiver of any right to do so at any time. The user agrees that if any portion of this Policy is held invalid or unenforceable, such portion will be construed consistent with applicable law as nearly as possible, and the remaining portions will remain in full force and effect. The user agrees to indemnify, defend and hold harmless Vivox and its affiliates, suppliers, providers, and agents against all claims and expenses (including reasonable attorney fees) resulting from users engaging in any of the prohibited activities listed in this Policy or resulting from users violating the Policy or any other posted policy related to the Service. The foregoing user indemnification will survive any termination of the user's agreements with Vivox . - - 8. ARBITRATION. Except for the right of a party to seek equitable relief, any disputes arising under or related to this Agreement ("Dispute"), excluding any Dispute relating to the validity or infringement of any intellectual property right, will be resolved by negotiation, mediation and, if necessary, arbitration, as follows. The party raising such Dispute will promptly advise the other party in writing describing in reasonable detail the nature of such Dispute ("Notice of Dispute"). The parties will negotiate in good faith to resolve the Dispute, but if they have not done so within thirty (30) days, the parties will submit the Dispute to a mutually agreed mediation organization. If the parties are unable to resolve the Dispute within sixty (60) days after delivery of the Notice of Dispute, then the Dispute will be resolved by a single arbitrator in a final and binding arbitration under the then current procedural rules of the American Arbitration Association. All proceedings will be conducted in the English language in Boston, Massachusetts. The arbitrator will have no power to modify the terms or conditions of this Agreement, or to award punitive damages. Any award rendered in such arbitration may be enforced by either party in any Court of competent jurisdiction. - - 9. GENERAL TERMS. This Agreement is governed by the laws of the Commonwealth of Massachusetts. No agency, partnership, joint venture, employment or franchise relationship is intended or created by this Agreement. This AUP constitute the entire agreement between the parties concerning the use of the Service. If any provision of this Agreement is found to be unenforceable, it shall be deemed modified to the least extent needed to make the provision enforceable; the remaining terms of this Agreement shall remain in full force and effect. Vivox reserves the right to disclose any information about any user as required by a court order or as recommended by counsel in the context of any action by any government entity or other third party. - - 10. CHANGES TO THIS POLICY. Vivox may revise its Acceptable Use Policy from time to time without prior notice. Any changes will be presented in the latest version at the Vivox web site. All revised copies of the Policy are effective immediately upon a user's first use of the Service after the change has been posted. \ No newline at end of file diff --git a/indra/newview/installers/darwin/firestorm-private-dmg/background.png b/indra/newview/installers/darwin/firestorm-private-dmg/background.png index b41190d81b..5e90b18d4e 100755 Binary files a/indra/newview/installers/darwin/firestorm-private-dmg/background.png and b/indra/newview/installers/darwin/firestorm-private-dmg/background.png differ diff --git a/indra/newview/installers/darwin/firestorm-release-dmg/LGPL-license.txt b/indra/newview/installers/darwin/firestorm-release-dmg/LGPL-license.txt deleted file mode 100644 index 4362b49151..0000000000 --- a/indra/newview/installers/darwin/firestorm-release-dmg/LGPL-license.txt +++ /dev/null @@ -1,502 +0,0 @@ - GNU LESSER GENERAL PUBLIC LICENSE - Version 2.1, February 1999 - - Copyright (C) 1991, 1999 Free Software Foundation, Inc. - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - -[This is the first released version of the Lesser GPL. It also counts - as the successor of the GNU Library Public License, version 2, hence - the version number 2.1.] - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -Licenses are intended to guarantee your freedom to share and change -free software--to make sure the software is free for all its users. - - This license, the Lesser General Public License, applies to some -specially designated software packages--typically libraries--of the -Free Software Foundation and other authors who decide to use it. You -can use it too, but we suggest you first think carefully about whether -this license or the ordinary General Public License is the better -strategy to use in any particular case, based on the explanations below. - - When we speak of free software, we are referring to freedom of use, -not price. Our General Public Licenses are designed to make sure that -you have the freedom to distribute copies of free software (and charge -for this service if you wish); that you receive source code or can get -it if you want it; that you can change the software and use pieces of -it in new free programs; and that you are informed that you can do -these things. - - To protect your rights, we need to make restrictions that forbid -distributors to deny you these rights or to ask you to surrender these -rights. These restrictions translate to certain responsibilities for -you if you distribute copies of the library or if you modify it. - - For example, if you distribute copies of the library, whether gratis -or for a fee, you must give the recipients all the rights that we gave -you. You must make sure that they, too, receive or can get the source -code. If you link other code with the library, you must provide -complete object files to the recipients, so that they can relink them -with the library after making changes to the library and recompiling -it. And you must show them these terms so they know their rights. - - We protect your rights with a two-step method: (1) we copyright the -library, and (2) we offer you this license, which gives you legal -permission to copy, distribute and/or modify the library. - - To protect each distributor, we want to make it very clear that -there is no warranty for the free library. Also, if the library is -modified by someone else and passed on, the recipients should know -that what they have is not the original version, so that the original -author's reputation will not be affected by problems that might be -introduced by others. - - Finally, software patents pose a constant threat to the existence of -any free program. We wish to make sure that a company cannot -effectively restrict the users of a free program by obtaining a -restrictive license from a patent holder. Therefore, we insist that -any patent license obtained for a version of the library must be -consistent with the full freedom of use specified in this license. - - Most GNU software, including some libraries, is covered by the -ordinary GNU General Public License. This license, the GNU Lesser -General Public License, applies to certain designated libraries, and -is quite different from the ordinary General Public License. We use -this license for certain libraries in order to permit linking those -libraries into non-free programs. - - When a program is linked with a library, whether statically or using -a shared library, the combination of the two is legally speaking a -combined work, a derivative of the original library. The ordinary -General Public License therefore permits such linking only if the -entire combination fits its criteria of freedom. The Lesser General -Public License permits more lax criteria for linking other code with -the library. - - We call this license the "Lesser" General Public License because it -does Less to protect the user's freedom than the ordinary General -Public License. It also provides other free software developers Less -of an advantage over competing non-free programs. These disadvantages -are the reason we use the ordinary General Public License for many -libraries. However, the Lesser license provides advantages in certain -special circumstances. - - For example, on rare occasions, there may be a special need to -encourage the widest possible use of a certain library, so that it becomes -a de-facto standard. To achieve this, non-free programs must be -allowed to use the library. A more frequent case is that a free -library does the same job as widely used non-free libraries. In this -case, there is little to gain by limiting the free library to free -software only, so we use the Lesser General Public License. - - In other cases, permission to use a particular library in non-free -programs enables a greater number of people to use a large body of -free software. For example, permission to use the GNU C Library in -non-free programs enables many more people to use the whole GNU -operating system, as well as its variant, the GNU/Linux operating -system. - - Although the Lesser General Public License is Less protective of the -users' freedom, it does ensure that the user of a program that is -linked with the Library has the freedom and the wherewithal to run -that program using a modified version of the Library. - - The precise terms and conditions for copying, distribution and -modification follow. Pay close attention to the difference between a -"work based on the library" and a "work that uses the library". The -former contains code derived from the library, whereas the latter must -be combined with the library in order to run. - - GNU LESSER GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License Agreement applies to any software library or other -program which contains a notice placed by the copyright holder or -other authorized party saying it may be distributed under the terms of -this Lesser General Public License (also called "this License"). -Each licensee is addressed as "you". - - A "library" means a collection of software functions and/or data -prepared so as to be conveniently linked with application programs -(which use some of those functions and data) to form executables. - - The "Library", below, refers to any such software library or work -which has been distributed under these terms. A "work based on the -Library" means either the Library or any derivative work under -copyright law: that is to say, a work containing the Library or a -portion of it, either verbatim or with modifications and/or translated -straightforwardly into another language. (Hereinafter, translation is -included without limitation in the term "modification".) - - "Source code" for a work means the preferred form of the work for -making modifications to it. For a library, complete source code means -all the source code for all modules it contains, plus any associated -interface definition files, plus the scripts used to control compilation -and installation of the library. - - Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running a program using the Library is not restricted, and output from -such a program is covered only if its contents constitute a work based -on the Library (independent of the use of the Library in a tool for -writing it). Whether that is true depends on what the Library does -and what the program that uses the Library does. - - 1. You may copy and distribute verbatim copies of the Library's -complete source code as you receive it, in any medium, provided that -you conspicuously and appropriately publish on each copy an -appropriate copyright notice and disclaimer of warranty; keep intact -all the notices that refer to this License and to the absence of any -warranty; and distribute a copy of this License along with the -Library. - - You may charge a fee for the physical act of transferring a copy, -and you may at your option offer warranty protection in exchange for a -fee. - - 2. You may modify your copy or copies of the Library or any portion -of it, thus forming a work based on the Library, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) The modified work must itself be a software library. - - b) You must cause the files modified to carry prominent notices - stating that you changed the files and the date of any change. - - c) You must cause the whole of the work to be licensed at no - charge to all third parties under the terms of this License. - - d) If a facility in the modified Library refers to a function or a - table of data to be supplied by an application program that uses - the facility, other than as an argument passed when the facility - is invoked, then you must make a good faith effort to ensure that, - in the event an application does not supply such function or - table, the facility still operates, and performs whatever part of - its purpose remains meaningful. - - (For example, a function in a library to compute square roots has - a purpose that is entirely well-defined independent of the - application. Therefore, Subsection 2d requires that any - application-supplied function or table used by this function must - be optional: if the application does not supply it, the square - root function must still compute square roots.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Library, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Library, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote -it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Library. - -In addition, mere aggregation of another work not based on the Library -with the Library (or with a work based on the Library) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may opt to apply the terms of the ordinary GNU General Public -License instead of this License to a given copy of the Library. To do -this, you must alter all the notices that refer to this License, so -that they refer to the ordinary GNU General Public License, version 2, -instead of to this License. (If a newer version than version 2 of the -ordinary GNU General Public License has appeared, then you can specify -that version instead if you wish.) Do not make any other change in -these notices. - - Once this change is made in a given copy, it is irreversible for -that copy, so the ordinary GNU General Public License applies to all -subsequent copies and derivative works made from that copy. - - This option is useful when you wish to copy part of the code of -the Library into a program that is not a library. - - 4. You may copy and distribute the Library (or a portion or -derivative of it, under Section 2) in object code or executable form -under the terms of Sections 1 and 2 above provided that you accompany -it with the complete corresponding machine-readable source code, which -must be distributed under the terms of Sections 1 and 2 above on a -medium customarily used for software interchange. - - If distribution of object code is made by offering access to copy -from a designated place, then offering equivalent access to copy the -source code from the same place satisfies the requirement to -distribute the source code, even though third parties are not -compelled to copy the source along with the object code. - - 5. A program that contains no derivative of any portion of the -Library, but is designed to work with the Library by being compiled or -linked with it, is called a "work that uses the Library". Such a -work, in isolation, is not a derivative work of the Library, and -therefore falls outside the scope of this License. - - However, linking a "work that uses the Library" with the Library -creates an executable that is a derivative of the Library (because it -contains portions of the Library), rather than a "work that uses the -library". The executable is therefore covered by this License. -Section 6 states terms for distribution of such executables. - - When a "work that uses the Library" uses material from a header file -that is part of the Library, the object code for the work may be a -derivative work of the Library even though the source code is not. -Whether this is true is especially significant if the work can be -linked without the Library, or if the work is itself a library. The -threshold for this to be true is not precisely defined by law. - - If such an object file uses only numerical parameters, data -structure layouts and accessors, and small macros and small inline -functions (ten lines or less in length), then the use of the object -file is unrestricted, regardless of whether it is legally a derivative -work. (Executables containing this object code plus portions of the -Library will still fall under Section 6.) - - Otherwise, if the work is a derivative of the Library, you may -distribute the object code for the work under the terms of Section 6. -Any executables containing that work also fall under Section 6, -whether or not they are linked directly with the Library itself. - - 6. As an exception to the Sections above, you may also combine or -link a "work that uses the Library" with the Library to produce a -work containing portions of the Library, and distribute that work -under terms of your choice, provided that the terms permit -modification of the work for the customer's own use and reverse -engineering for debugging such modifications. - - You must give prominent notice with each copy of the work that the -Library is used in it and that the Library and its use are covered by -this License. You must supply a copy of this License. If the work -during execution displays copyright notices, you must include the -copyright notice for the Library among them, as well as a reference -directing the user to the copy of this License. Also, you must do one -of these things: - - a) Accompany the work with the complete corresponding - machine-readable source code for the Library including whatever - changes were used in the work (which must be distributed under - Sections 1 and 2 above); and, if the work is an executable linked - with the Library, with the complete machine-readable "work that - uses the Library", as object code and/or source code, so that the - user can modify the Library and then relink to produce a modified - executable containing the modified Library. (It is understood - that the user who changes the contents of definitions files in the - Library will not necessarily be able to recompile the application - to use the modified definitions.) - - b) Use a suitable shared library mechanism for linking with the - Library. A suitable mechanism is one that (1) uses at run time a - copy of the library already present on the user's computer system, - rather than copying library functions into the executable, and (2) - will operate properly with a modified version of the library, if - the user installs one, as long as the modified version is - interface-compatible with the version that the work was made with. - - c) Accompany the work with a written offer, valid for at - least three years, to give the same user the materials - specified in Subsection 6a, above, for a charge no more - than the cost of performing this distribution. - - d) If distribution of the work is made by offering access to copy - from a designated place, offer equivalent access to copy the above - specified materials from the same place. - - e) Verify that the user has already received a copy of these - materials or that you have already sent this user a copy. - - For an executable, the required form of the "work that uses the -Library" must include any data and utility programs needed for -reproducing the executable from it. However, as a special exception, -the materials to be distributed need not include anything that is -normally distributed (in either source or binary form) with the major -components (compiler, kernel, and so on) of the operating system on -which the executable runs, unless that component itself accompanies -the executable. - - It may happen that this requirement contradicts the license -restrictions of other proprietary libraries that do not normally -accompany the operating system. Such a contradiction means you cannot -use both them and the Library together in an executable that you -distribute. - - 7. You may place library facilities that are a work based on the -Library side-by-side in a single library together with other library -facilities not covered by this License, and distribute such a combined -library, provided that the separate distribution of the work based on -the Library and of the other library facilities is otherwise -permitted, and provided that you do these two things: - - a) Accompany the combined library with a copy of the same work - based on the Library, uncombined with any other library - facilities. This must be distributed under the terms of the - Sections above. - - b) Give prominent notice with the combined library of the fact - that part of it is a work based on the Library, and explaining - where to find the accompanying uncombined form of the same work. - - 8. You may not copy, modify, sublicense, link with, or distribute -the Library except as expressly provided under this License. Any -attempt otherwise to copy, modify, sublicense, link with, or -distribute the Library is void, and will automatically terminate your -rights under this License. However, parties who have received copies, -or rights, from you under this License will not have their licenses -terminated so long as such parties remain in full compliance. - - 9. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Library or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Library (or any work based on the -Library), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Library or works based on it. - - 10. Each time you redistribute the Library (or any work based on the -Library), the recipient automatically receives a license from the -original licensor to copy, distribute, link with or modify the Library -subject to these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties with -this License. - - 11. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Library at all. For example, if a patent -license would not permit royalty-free redistribution of the Library by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Library. - -If any portion of this section is held invalid or unenforceable under any -particular circumstance, the balance of the section is intended to apply, -and the section as a whole is intended to apply in other circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 12. If the distribution and/or use of the Library is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Library under this License may add -an explicit geographical distribution limitation excluding those countries, -so that distribution is permitted only in or among countries not thus -excluded. In such case, this License incorporates the limitation as if -written in the body of this License. - - 13. The Free Software Foundation may publish revised and/or new -versions of the Lesser General Public License from time to time. -Such new versions will be similar in spirit to the present version, -but may differ in detail to address new problems or concerns. - -Each version is given a distinguishing version number. If the Library -specifies a version number of this License which applies to it and -"any later version", you have the option of following the terms and -conditions either of that version or of any later version published by -the Free Software Foundation. If the Library does not specify a -license version number, you may choose any version ever published by -the Free Software Foundation. - - 14. If you wish to incorporate parts of the Library into other free -programs whose distribution conditions are incompatible with these, -write to the author to ask for permission. For software which is -copyrighted by the Free Software Foundation, write to the Free -Software Foundation; we sometimes make exceptions for this. Our -decision will be guided by the two goals of preserving the free status -of all derivatives of our free software and of promoting the sharing -and reuse of software generally. - - NO WARRANTY - - 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO -WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. -EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR -OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY -KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE -LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME -THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN -WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY -AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU -FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR -CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE -LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING -RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A -FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF -SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH -DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Libraries - - If you develop a new library, and you want it to be of the greatest -possible use to the public, we recommend making it free software that -everyone can redistribute and change. You can do so by permitting -redistribution under these terms (or, alternatively, under the terms of the -ordinary General Public License). - - To apply these terms, attach the following notices to the library. It is -safest to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least the -"copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -Also add information on how to contact you by electronic and paper mail. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the library, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the - library `Frob' (a library for tweaking knobs) written by James Random Hacker. - - , 1 April 1990 - Ty Coon, President of Vice - -That's all there is to it! diff --git a/indra/newview/installers/darwin/firestorm-release-dmg/VivoxAUP.txt b/indra/newview/installers/darwin/firestorm-release-dmg/VivoxAUP.txt deleted file mode 100644 index 6413f8b16a..0000000000 --- a/indra/newview/installers/darwin/firestorm-release-dmg/VivoxAUP.txt +++ /dev/null @@ -1,23 +0,0 @@ -Acceptable Use Policy (AUP) - - 1. BACKGROUND: Users of the online voice services provided by Vivox, Inc. ("Vivox") (the "Service"), through the act of utilizing the Service, agree to adhere to this Acceptable Use Policy (the "Policy"). Vivox reserves the right to immediately terminate a user's access to the Service if the user engages in any of the activities prohibited by this Policy or uses the Service contrary to this Policy. Each user is responsible for all activities conducted under its account. The user is also responsible for adhering to any policy set forth by any other service provider accessed through the Service; Vivox, and its suppliers and providers, assume no responsibility or liability for a user's failure to comply with the Policy. The user acknowledges that Vivox may have access to information about or provided by the user, including diagnostic information sent automatically after a problem or error, and agrees to such access and use. - - 2. PROHIBITED USES AND ACTIVITIES: Users shall not provide inaccurate or misleading information to Vivox or use the Service to: (i) access any other person's computer or computer system, software, or data without their knowledge and consent; or breach the security of another user; or attempt to circumvent the user authentication or security of any host, network, system, or account, which includes, but is not limited to, accessing data not intended for the user, logging into or making use of a server or account the user is not expressly authorized to access, or probing the security of other hosts, networks, or accounts; or use automated means (such as robots and spiders) to obtain information from Vivox's website or, though it, from other websites; (ii) interfere with computer networking or telecommunications service to any user, host or network, including, without limitation, denial of service attacks, flooding of a network, overloading a service, improper seizing and abuse of operator privileges and attempts to "crash" a host; (iii) violate the rules, regulations, or policies applicable to any network, server, computer database, or service that accessed by the user; (iv) transmit, re-transmit, or store any content or to engage in any activity that infringes the intellectual property rights or privacy rights of Vivox or any individual, group or entity, including but not limited to any rights protected by any copyright, patent, trademark, trade secret, trade dress, right of privacy, right of publicity, moral rights or other intellectual property right now known or later recognized by statute, judicial decision or regulation; (v) host, post, transmit, or re-transmit any content or material that is threatening, harassing, obscene, indecent, pornographic, hateful, malicious, racist, defamatory, libelous, treasonous, excessively violent or promotes the use of violence, or provides instruction, information or assistance in causing or carrying out violence against any government, organization, group or individual, or provides guidance, information or assistance with respect to causing damage or security breaches to or Vivox's network or to the network of any other service provider; (vi) commit an act that constitutes a criminal offense, gives rise to civil liability, or otherwise violates any applicable local, state, federal or international law, or (vii) encourage conduct that would constitute a criminal offense, give rise to civil liability, or otherwise violate any applicable local, state, federal or international law. - - 3. SECURITY: In all cases, the user is solely responsible for the security of any device or application it chooses to connect to the Service, including any data stored on or communications passed. - - 4. TRADEMARKS AND COPYRIGHTS. "Vivox," "Powered by Vivox" and similar marks are the property of Vivox. All other names, graphics, logos, marks and trade names used in connection with this Service, are the property of their owners and suppliers and may not be used without permission for any purpose. The copyright in the Vivox website and Service and all related materials are owned by Vivox or its suppliers unless otherwise stated. - - 5. DISCLAIMER OF WARRANTIES. THE SERVICE IS PROVIDED "AS IS" AND "WITH ALL FAULTS," AND PROVIDER AND VIVOX HEREBY DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION (I) WARRANTIES OF MERCHANTIBILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT, AND (II) ANY WARRANTIES CONCERNING THE SECURITY, RELIABILITY OR PERFORMANCE OF THE SERVICE. Certain states prohibit the disclaimer of warranties in certain cases, so the above may not apply to all users in all instances. - - THE DOWNLOADING OR SUBMISSION OF ANY MATERIALS IS DONE AT THE USER'S OWN RISK, AND THE USER IS SOLELY RESPONSIBLE FOR ANY LOSS OR DAMAGE TO ANY CONTENT, IMAGE, COMPUTER SYSTEM OR DATA THAT MAY RESULT FROM USING THE SERVICE. - - 6. EXCLUSION OF DAMAGES. TO THE FULLEST EXTENT ALLOWED BY LAW, VIVOX SHALL NOT BE LIABLE FOR ANY INDIRECT OR CONSEQUENTIAL DAMAGES, INCLUDING INCIDENTAL, SPECIAL, EXEMPLARY AND PUNITIVE DAMAGES, RESULTING FROM THE USE OR PROVISION OF THE SERVICE, EVEN IF THE POSSIBILITY OF SUCH DAMAGES IS KNOWN. Certain states prohibit the limitation of liability in certain cases, so the above may not apply to the user in all instances. - - 7. ENFORCEMENT OF THIS POLICY: Vivox does not routinely monitors the activity of Service accounts for violation of this Policy. Vivox reserves the right at any time to monitor usage, transmissions, and content from time to time to operate the Service; to identify violations of this Policy; and/or to protect the network, the Service and/or other users. If the Service is used in a way that Vivox, in their sole discretion, believe violate this Policy, it may take any responsive actions they deem appropriate, including, but are not limited to, the immediate suspension or termination of all or any portion of the Service. Vivox will have no liability for any of these responsive actions. These actions are not exclusive remedies and Vivox may take any other legal or technical action deemed appropriate. The user expressly authorizes Vivox to cooperate with (i) law enforcement authorities in the investigation of suspected legal violations, and (ii) any system administrators at other Internet service providers or other network or computing facilities in order to enforce this Policy. This cooperation may include making available personally identifiable information about users to law enforcement or system administrators. The failure to enforce this Policy, for whatever reason or for no reason, shall not be construed as a waiver of any right to do so at any time. The user agrees that if any portion of this Policy is held invalid or unenforceable, such portion will be construed consistent with applicable law as nearly as possible, and the remaining portions will remain in full force and effect. The user agrees to indemnify, defend and hold harmless Vivox and its affiliates, suppliers, providers, and agents against all claims and expenses (including reasonable attorney fees) resulting from users engaging in any of the prohibited activities listed in this Policy or resulting from users violating the Policy or any other posted policy related to the Service. The foregoing user indemnification will survive any termination of the user's agreements with Vivox . - - 8. ARBITRATION. Except for the right of a party to seek equitable relief, any disputes arising under or related to this Agreement ("Dispute"), excluding any Dispute relating to the validity or infringement of any intellectual property right, will be resolved by negotiation, mediation and, if necessary, arbitration, as follows. The party raising such Dispute will promptly advise the other party in writing describing in reasonable detail the nature of such Dispute ("Notice of Dispute"). The parties will negotiate in good faith to resolve the Dispute, but if they have not done so within thirty (30) days, the parties will submit the Dispute to a mutually agreed mediation organization. If the parties are unable to resolve the Dispute within sixty (60) days after delivery of the Notice of Dispute, then the Dispute will be resolved by a single arbitrator in a final and binding arbitration under the then current procedural rules of the American Arbitration Association. All proceedings will be conducted in the English language in Boston, Massachusetts. The arbitrator will have no power to modify the terms or conditions of this Agreement, or to award punitive damages. Any award rendered in such arbitration may be enforced by either party in any Court of competent jurisdiction. - - 9. GENERAL TERMS. This Agreement is governed by the laws of the Commonwealth of Massachusetts. No agency, partnership, joint venture, employment or franchise relationship is intended or created by this Agreement. This AUP constitute the entire agreement between the parties concerning the use of the Service. If any provision of this Agreement is found to be unenforceable, it shall be deemed modified to the least extent needed to make the provision enforceable; the remaining terms of this Agreement shall remain in full force and effect. Vivox reserves the right to disclose any information about any user as required by a court order or as recommended by counsel in the context of any action by any government entity or other third party. - - 10. CHANGES TO THIS POLICY. Vivox may revise its Acceptable Use Policy from time to time without prior notice. Any changes will be presented in the latest version at the Vivox web site. All revised copies of the Policy are effective immediately upon a user's first use of the Service after the change has been posted. \ No newline at end of file diff --git a/indra/newview/installers/darwin/firestorm-release-dmg/background.png b/indra/newview/installers/darwin/firestorm-release-dmg/background.png old mode 100755 new mode 100644 index e0f43cf6a9..5e90b18d4e Binary files a/indra/newview/installers/darwin/firestorm-release-dmg/background.png and b/indra/newview/installers/darwin/firestorm-release-dmg/background.png differ diff --git a/indra/newview/installers/darwin/firestormos-beta-dmg/LGPL-license.txt b/indra/newview/installers/darwin/firestormos-beta-dmg/LGPL-license.txt deleted file mode 100644 index 4362b49151..0000000000 --- a/indra/newview/installers/darwin/firestormos-beta-dmg/LGPL-license.txt +++ /dev/null @@ -1,502 +0,0 @@ - GNU LESSER GENERAL PUBLIC LICENSE - Version 2.1, February 1999 - - Copyright (C) 1991, 1999 Free Software Foundation, Inc. - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - -[This is the first released version of the Lesser GPL. It also counts - as the successor of the GNU Library Public License, version 2, hence - the version number 2.1.] - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -Licenses are intended to guarantee your freedom to share and change -free software--to make sure the software is free for all its users. - - This license, the Lesser General Public License, applies to some -specially designated software packages--typically libraries--of the -Free Software Foundation and other authors who decide to use it. You -can use it too, but we suggest you first think carefully about whether -this license or the ordinary General Public License is the better -strategy to use in any particular case, based on the explanations below. - - When we speak of free software, we are referring to freedom of use, -not price. Our General Public Licenses are designed to make sure that -you have the freedom to distribute copies of free software (and charge -for this service if you wish); that you receive source code or can get -it if you want it; that you can change the software and use pieces of -it in new free programs; and that you are informed that you can do -these things. - - To protect your rights, we need to make restrictions that forbid -distributors to deny you these rights or to ask you to surrender these -rights. These restrictions translate to certain responsibilities for -you if you distribute copies of the library or if you modify it. - - For example, if you distribute copies of the library, whether gratis -or for a fee, you must give the recipients all the rights that we gave -you. You must make sure that they, too, receive or can get the source -code. If you link other code with the library, you must provide -complete object files to the recipients, so that they can relink them -with the library after making changes to the library and recompiling -it. And you must show them these terms so they know their rights. - - We protect your rights with a two-step method: (1) we copyright the -library, and (2) we offer you this license, which gives you legal -permission to copy, distribute and/or modify the library. - - To protect each distributor, we want to make it very clear that -there is no warranty for the free library. Also, if the library is -modified by someone else and passed on, the recipients should know -that what they have is not the original version, so that the original -author's reputation will not be affected by problems that might be -introduced by others. - - Finally, software patents pose a constant threat to the existence of -any free program. We wish to make sure that a company cannot -effectively restrict the users of a free program by obtaining a -restrictive license from a patent holder. Therefore, we insist that -any patent license obtained for a version of the library must be -consistent with the full freedom of use specified in this license. - - Most GNU software, including some libraries, is covered by the -ordinary GNU General Public License. This license, the GNU Lesser -General Public License, applies to certain designated libraries, and -is quite different from the ordinary General Public License. We use -this license for certain libraries in order to permit linking those -libraries into non-free programs. - - When a program is linked with a library, whether statically or using -a shared library, the combination of the two is legally speaking a -combined work, a derivative of the original library. The ordinary -General Public License therefore permits such linking only if the -entire combination fits its criteria of freedom. The Lesser General -Public License permits more lax criteria for linking other code with -the library. - - We call this license the "Lesser" General Public License because it -does Less to protect the user's freedom than the ordinary General -Public License. It also provides other free software developers Less -of an advantage over competing non-free programs. These disadvantages -are the reason we use the ordinary General Public License for many -libraries. However, the Lesser license provides advantages in certain -special circumstances. - - For example, on rare occasions, there may be a special need to -encourage the widest possible use of a certain library, so that it becomes -a de-facto standard. To achieve this, non-free programs must be -allowed to use the library. A more frequent case is that a free -library does the same job as widely used non-free libraries. In this -case, there is little to gain by limiting the free library to free -software only, so we use the Lesser General Public License. - - In other cases, permission to use a particular library in non-free -programs enables a greater number of people to use a large body of -free software. For example, permission to use the GNU C Library in -non-free programs enables many more people to use the whole GNU -operating system, as well as its variant, the GNU/Linux operating -system. - - Although the Lesser General Public License is Less protective of the -users' freedom, it does ensure that the user of a program that is -linked with the Library has the freedom and the wherewithal to run -that program using a modified version of the Library. - - The precise terms and conditions for copying, distribution and -modification follow. Pay close attention to the difference between a -"work based on the library" and a "work that uses the library". The -former contains code derived from the library, whereas the latter must -be combined with the library in order to run. - - GNU LESSER GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License Agreement applies to any software library or other -program which contains a notice placed by the copyright holder or -other authorized party saying it may be distributed under the terms of -this Lesser General Public License (also called "this License"). -Each licensee is addressed as "you". - - A "library" means a collection of software functions and/or data -prepared so as to be conveniently linked with application programs -(which use some of those functions and data) to form executables. - - The "Library", below, refers to any such software library or work -which has been distributed under these terms. A "work based on the -Library" means either the Library or any derivative work under -copyright law: that is to say, a work containing the Library or a -portion of it, either verbatim or with modifications and/or translated -straightforwardly into another language. (Hereinafter, translation is -included without limitation in the term "modification".) - - "Source code" for a work means the preferred form of the work for -making modifications to it. For a library, complete source code means -all the source code for all modules it contains, plus any associated -interface definition files, plus the scripts used to control compilation -and installation of the library. - - Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running a program using the Library is not restricted, and output from -such a program is covered only if its contents constitute a work based -on the Library (independent of the use of the Library in a tool for -writing it). Whether that is true depends on what the Library does -and what the program that uses the Library does. - - 1. You may copy and distribute verbatim copies of the Library's -complete source code as you receive it, in any medium, provided that -you conspicuously and appropriately publish on each copy an -appropriate copyright notice and disclaimer of warranty; keep intact -all the notices that refer to this License and to the absence of any -warranty; and distribute a copy of this License along with the -Library. - - You may charge a fee for the physical act of transferring a copy, -and you may at your option offer warranty protection in exchange for a -fee. - - 2. You may modify your copy or copies of the Library or any portion -of it, thus forming a work based on the Library, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) The modified work must itself be a software library. - - b) You must cause the files modified to carry prominent notices - stating that you changed the files and the date of any change. - - c) You must cause the whole of the work to be licensed at no - charge to all third parties under the terms of this License. - - d) If a facility in the modified Library refers to a function or a - table of data to be supplied by an application program that uses - the facility, other than as an argument passed when the facility - is invoked, then you must make a good faith effort to ensure that, - in the event an application does not supply such function or - table, the facility still operates, and performs whatever part of - its purpose remains meaningful. - - (For example, a function in a library to compute square roots has - a purpose that is entirely well-defined independent of the - application. Therefore, Subsection 2d requires that any - application-supplied function or table used by this function must - be optional: if the application does not supply it, the square - root function must still compute square roots.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Library, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Library, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote -it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Library. - -In addition, mere aggregation of another work not based on the Library -with the Library (or with a work based on the Library) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may opt to apply the terms of the ordinary GNU General Public -License instead of this License to a given copy of the Library. To do -this, you must alter all the notices that refer to this License, so -that they refer to the ordinary GNU General Public License, version 2, -instead of to this License. (If a newer version than version 2 of the -ordinary GNU General Public License has appeared, then you can specify -that version instead if you wish.) Do not make any other change in -these notices. - - Once this change is made in a given copy, it is irreversible for -that copy, so the ordinary GNU General Public License applies to all -subsequent copies and derivative works made from that copy. - - This option is useful when you wish to copy part of the code of -the Library into a program that is not a library. - - 4. You may copy and distribute the Library (or a portion or -derivative of it, under Section 2) in object code or executable form -under the terms of Sections 1 and 2 above provided that you accompany -it with the complete corresponding machine-readable source code, which -must be distributed under the terms of Sections 1 and 2 above on a -medium customarily used for software interchange. - - If distribution of object code is made by offering access to copy -from a designated place, then offering equivalent access to copy the -source code from the same place satisfies the requirement to -distribute the source code, even though third parties are not -compelled to copy the source along with the object code. - - 5. A program that contains no derivative of any portion of the -Library, but is designed to work with the Library by being compiled or -linked with it, is called a "work that uses the Library". Such a -work, in isolation, is not a derivative work of the Library, and -therefore falls outside the scope of this License. - - However, linking a "work that uses the Library" with the Library -creates an executable that is a derivative of the Library (because it -contains portions of the Library), rather than a "work that uses the -library". The executable is therefore covered by this License. -Section 6 states terms for distribution of such executables. - - When a "work that uses the Library" uses material from a header file -that is part of the Library, the object code for the work may be a -derivative work of the Library even though the source code is not. -Whether this is true is especially significant if the work can be -linked without the Library, or if the work is itself a library. The -threshold for this to be true is not precisely defined by law. - - If such an object file uses only numerical parameters, data -structure layouts and accessors, and small macros and small inline -functions (ten lines or less in length), then the use of the object -file is unrestricted, regardless of whether it is legally a derivative -work. (Executables containing this object code plus portions of the -Library will still fall under Section 6.) - - Otherwise, if the work is a derivative of the Library, you may -distribute the object code for the work under the terms of Section 6. -Any executables containing that work also fall under Section 6, -whether or not they are linked directly with the Library itself. - - 6. As an exception to the Sections above, you may also combine or -link a "work that uses the Library" with the Library to produce a -work containing portions of the Library, and distribute that work -under terms of your choice, provided that the terms permit -modification of the work for the customer's own use and reverse -engineering for debugging such modifications. - - You must give prominent notice with each copy of the work that the -Library is used in it and that the Library and its use are covered by -this License. You must supply a copy of this License. If the work -during execution displays copyright notices, you must include the -copyright notice for the Library among them, as well as a reference -directing the user to the copy of this License. Also, you must do one -of these things: - - a) Accompany the work with the complete corresponding - machine-readable source code for the Library including whatever - changes were used in the work (which must be distributed under - Sections 1 and 2 above); and, if the work is an executable linked - with the Library, with the complete machine-readable "work that - uses the Library", as object code and/or source code, so that the - user can modify the Library and then relink to produce a modified - executable containing the modified Library. (It is understood - that the user who changes the contents of definitions files in the - Library will not necessarily be able to recompile the application - to use the modified definitions.) - - b) Use a suitable shared library mechanism for linking with the - Library. A suitable mechanism is one that (1) uses at run time a - copy of the library already present on the user's computer system, - rather than copying library functions into the executable, and (2) - will operate properly with a modified version of the library, if - the user installs one, as long as the modified version is - interface-compatible with the version that the work was made with. - - c) Accompany the work with a written offer, valid for at - least three years, to give the same user the materials - specified in Subsection 6a, above, for a charge no more - than the cost of performing this distribution. - - d) If distribution of the work is made by offering access to copy - from a designated place, offer equivalent access to copy the above - specified materials from the same place. - - e) Verify that the user has already received a copy of these - materials or that you have already sent this user a copy. - - For an executable, the required form of the "work that uses the -Library" must include any data and utility programs needed for -reproducing the executable from it. However, as a special exception, -the materials to be distributed need not include anything that is -normally distributed (in either source or binary form) with the major -components (compiler, kernel, and so on) of the operating system on -which the executable runs, unless that component itself accompanies -the executable. - - It may happen that this requirement contradicts the license -restrictions of other proprietary libraries that do not normally -accompany the operating system. Such a contradiction means you cannot -use both them and the Library together in an executable that you -distribute. - - 7. You may place library facilities that are a work based on the -Library side-by-side in a single library together with other library -facilities not covered by this License, and distribute such a combined -library, provided that the separate distribution of the work based on -the Library and of the other library facilities is otherwise -permitted, and provided that you do these two things: - - a) Accompany the combined library with a copy of the same work - based on the Library, uncombined with any other library - facilities. This must be distributed under the terms of the - Sections above. - - b) Give prominent notice with the combined library of the fact - that part of it is a work based on the Library, and explaining - where to find the accompanying uncombined form of the same work. - - 8. You may not copy, modify, sublicense, link with, or distribute -the Library except as expressly provided under this License. Any -attempt otherwise to copy, modify, sublicense, link with, or -distribute the Library is void, and will automatically terminate your -rights under this License. However, parties who have received copies, -or rights, from you under this License will not have their licenses -terminated so long as such parties remain in full compliance. - - 9. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Library or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Library (or any work based on the -Library), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Library or works based on it. - - 10. Each time you redistribute the Library (or any work based on the -Library), the recipient automatically receives a license from the -original licensor to copy, distribute, link with or modify the Library -subject to these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties with -this License. - - 11. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Library at all. For example, if a patent -license would not permit royalty-free redistribution of the Library by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Library. - -If any portion of this section is held invalid or unenforceable under any -particular circumstance, the balance of the section is intended to apply, -and the section as a whole is intended to apply in other circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 12. If the distribution and/or use of the Library is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Library under this License may add -an explicit geographical distribution limitation excluding those countries, -so that distribution is permitted only in or among countries not thus -excluded. In such case, this License incorporates the limitation as if -written in the body of this License. - - 13. The Free Software Foundation may publish revised and/or new -versions of the Lesser General Public License from time to time. -Such new versions will be similar in spirit to the present version, -but may differ in detail to address new problems or concerns. - -Each version is given a distinguishing version number. If the Library -specifies a version number of this License which applies to it and -"any later version", you have the option of following the terms and -conditions either of that version or of any later version published by -the Free Software Foundation. If the Library does not specify a -license version number, you may choose any version ever published by -the Free Software Foundation. - - 14. If you wish to incorporate parts of the Library into other free -programs whose distribution conditions are incompatible with these, -write to the author to ask for permission. For software which is -copyrighted by the Free Software Foundation, write to the Free -Software Foundation; we sometimes make exceptions for this. Our -decision will be guided by the two goals of preserving the free status -of all derivatives of our free software and of promoting the sharing -and reuse of software generally. - - NO WARRANTY - - 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO -WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. -EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR -OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY -KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE -LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME -THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN -WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY -AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU -FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR -CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE -LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING -RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A -FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF -SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH -DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Libraries - - If you develop a new library, and you want it to be of the greatest -possible use to the public, we recommend making it free software that -everyone can redistribute and change. You can do so by permitting -redistribution under these terms (or, alternatively, under the terms of the -ordinary General Public License). - - To apply these terms, attach the following notices to the library. It is -safest to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least the -"copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -Also add information on how to contact you by electronic and paper mail. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the library, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the - library `Frob' (a library for tweaking knobs) written by James Random Hacker. - - , 1 April 1990 - Ty Coon, President of Vice - -That's all there is to it! diff --git a/indra/newview/installers/darwin/firestormos-beta-dmg/VivoxAUP.txt b/indra/newview/installers/darwin/firestormos-beta-dmg/VivoxAUP.txt deleted file mode 100644 index 6413f8b16a..0000000000 --- a/indra/newview/installers/darwin/firestormos-beta-dmg/VivoxAUP.txt +++ /dev/null @@ -1,23 +0,0 @@ -Acceptable Use Policy (AUP) - - 1. BACKGROUND: Users of the online voice services provided by Vivox, Inc. ("Vivox") (the "Service"), through the act of utilizing the Service, agree to adhere to this Acceptable Use Policy (the "Policy"). Vivox reserves the right to immediately terminate a user's access to the Service if the user engages in any of the activities prohibited by this Policy or uses the Service contrary to this Policy. Each user is responsible for all activities conducted under its account. The user is also responsible for adhering to any policy set forth by any other service provider accessed through the Service; Vivox, and its suppliers and providers, assume no responsibility or liability for a user's failure to comply with the Policy. The user acknowledges that Vivox may have access to information about or provided by the user, including diagnostic information sent automatically after a problem or error, and agrees to such access and use. - - 2. PROHIBITED USES AND ACTIVITIES: Users shall not provide inaccurate or misleading information to Vivox or use the Service to: (i) access any other person's computer or computer system, software, or data without their knowledge and consent; or breach the security of another user; or attempt to circumvent the user authentication or security of any host, network, system, or account, which includes, but is not limited to, accessing data not intended for the user, logging into or making use of a server or account the user is not expressly authorized to access, or probing the security of other hosts, networks, or accounts; or use automated means (such as robots and spiders) to obtain information from Vivox's website or, though it, from other websites; (ii) interfere with computer networking or telecommunications service to any user, host or network, including, without limitation, denial of service attacks, flooding of a network, overloading a service, improper seizing and abuse of operator privileges and attempts to "crash" a host; (iii) violate the rules, regulations, or policies applicable to any network, server, computer database, or service that accessed by the user; (iv) transmit, re-transmit, or store any content or to engage in any activity that infringes the intellectual property rights or privacy rights of Vivox or any individual, group or entity, including but not limited to any rights protected by any copyright, patent, trademark, trade secret, trade dress, right of privacy, right of publicity, moral rights or other intellectual property right now known or later recognized by statute, judicial decision or regulation; (v) host, post, transmit, or re-transmit any content or material that is threatening, harassing, obscene, indecent, pornographic, hateful, malicious, racist, defamatory, libelous, treasonous, excessively violent or promotes the use of violence, or provides instruction, information or assistance in causing or carrying out violence against any government, organization, group or individual, or provides guidance, information or assistance with respect to causing damage or security breaches to or Vivox's network or to the network of any other service provider; (vi) commit an act that constitutes a criminal offense, gives rise to civil liability, or otherwise violates any applicable local, state, federal or international law, or (vii) encourage conduct that would constitute a criminal offense, give rise to civil liability, or otherwise violate any applicable local, state, federal or international law. - - 3. SECURITY: In all cases, the user is solely responsible for the security of any device or application it chooses to connect to the Service, including any data stored on or communications passed. - - 4. TRADEMARKS AND COPYRIGHTS. "Vivox," "Powered by Vivox" and similar marks are the property of Vivox. All other names, graphics, logos, marks and trade names used in connection with this Service, are the property of their owners and suppliers and may not be used without permission for any purpose. The copyright in the Vivox website and Service and all related materials are owned by Vivox or its suppliers unless otherwise stated. - - 5. DISCLAIMER OF WARRANTIES. THE SERVICE IS PROVIDED "AS IS" AND "WITH ALL FAULTS," AND PROVIDER AND VIVOX HEREBY DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION (I) WARRANTIES OF MERCHANTIBILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT, AND (II) ANY WARRANTIES CONCERNING THE SECURITY, RELIABILITY OR PERFORMANCE OF THE SERVICE. Certain states prohibit the disclaimer of warranties in certain cases, so the above may not apply to all users in all instances. - - THE DOWNLOADING OR SUBMISSION OF ANY MATERIALS IS DONE AT THE USER'S OWN RISK, AND THE USER IS SOLELY RESPONSIBLE FOR ANY LOSS OR DAMAGE TO ANY CONTENT, IMAGE, COMPUTER SYSTEM OR DATA THAT MAY RESULT FROM USING THE SERVICE. - - 6. EXCLUSION OF DAMAGES. TO THE FULLEST EXTENT ALLOWED BY LAW, VIVOX SHALL NOT BE LIABLE FOR ANY INDIRECT OR CONSEQUENTIAL DAMAGES, INCLUDING INCIDENTAL, SPECIAL, EXEMPLARY AND PUNITIVE DAMAGES, RESULTING FROM THE USE OR PROVISION OF THE SERVICE, EVEN IF THE POSSIBILITY OF SUCH DAMAGES IS KNOWN. Certain states prohibit the limitation of liability in certain cases, so the above may not apply to the user in all instances. - - 7. ENFORCEMENT OF THIS POLICY: Vivox does not routinely monitors the activity of Service accounts for violation of this Policy. Vivox reserves the right at any time to monitor usage, transmissions, and content from time to time to operate the Service; to identify violations of this Policy; and/or to protect the network, the Service and/or other users. If the Service is used in a way that Vivox, in their sole discretion, believe violate this Policy, it may take any responsive actions they deem appropriate, including, but are not limited to, the immediate suspension or termination of all or any portion of the Service. Vivox will have no liability for any of these responsive actions. These actions are not exclusive remedies and Vivox may take any other legal or technical action deemed appropriate. The user expressly authorizes Vivox to cooperate with (i) law enforcement authorities in the investigation of suspected legal violations, and (ii) any system administrators at other Internet service providers or other network or computing facilities in order to enforce this Policy. This cooperation may include making available personally identifiable information about users to law enforcement or system administrators. The failure to enforce this Policy, for whatever reason or for no reason, shall not be construed as a waiver of any right to do so at any time. The user agrees that if any portion of this Policy is held invalid or unenforceable, such portion will be construed consistent with applicable law as nearly as possible, and the remaining portions will remain in full force and effect. The user agrees to indemnify, defend and hold harmless Vivox and its affiliates, suppliers, providers, and agents against all claims and expenses (including reasonable attorney fees) resulting from users engaging in any of the prohibited activities listed in this Policy or resulting from users violating the Policy or any other posted policy related to the Service. The foregoing user indemnification will survive any termination of the user's agreements with Vivox . - - 8. ARBITRATION. Except for the right of a party to seek equitable relief, any disputes arising under or related to this Agreement ("Dispute"), excluding any Dispute relating to the validity or infringement of any intellectual property right, will be resolved by negotiation, mediation and, if necessary, arbitration, as follows. The party raising such Dispute will promptly advise the other party in writing describing in reasonable detail the nature of such Dispute ("Notice of Dispute"). The parties will negotiate in good faith to resolve the Dispute, but if they have not done so within thirty (30) days, the parties will submit the Dispute to a mutually agreed mediation organization. If the parties are unable to resolve the Dispute within sixty (60) days after delivery of the Notice of Dispute, then the Dispute will be resolved by a single arbitrator in a final and binding arbitration under the then current procedural rules of the American Arbitration Association. All proceedings will be conducted in the English language in Boston, Massachusetts. The arbitrator will have no power to modify the terms or conditions of this Agreement, or to award punitive damages. Any award rendered in such arbitration may be enforced by either party in any Court of competent jurisdiction. - - 9. GENERAL TERMS. This Agreement is governed by the laws of the Commonwealth of Massachusetts. No agency, partnership, joint venture, employment or franchise relationship is intended or created by this Agreement. This AUP constitute the entire agreement between the parties concerning the use of the Service. If any provision of this Agreement is found to be unenforceable, it shall be deemed modified to the least extent needed to make the provision enforceable; the remaining terms of this Agreement shall remain in full force and effect. Vivox reserves the right to disclose any information about any user as required by a court order or as recommended by counsel in the context of any action by any government entity or other third party. - - 10. CHANGES TO THIS POLICY. Vivox may revise its Acceptable Use Policy from time to time without prior notice. Any changes will be presented in the latest version at the Vivox web site. All revised copies of the Policy are effective immediately upon a user's first use of the Service after the change has been posted. \ No newline at end of file diff --git a/indra/newview/installers/darwin/firestormos-beta-dmg/background.png b/indra/newview/installers/darwin/firestormos-beta-dmg/background.png index d71a63016d..5e90b18d4e 100755 Binary files a/indra/newview/installers/darwin/firestormos-beta-dmg/background.png and b/indra/newview/installers/darwin/firestormos-beta-dmg/background.png differ diff --git a/indra/newview/installers/darwin/firestormos-nightly-dmg/LGPL-license.txt b/indra/newview/installers/darwin/firestormos-nightly-dmg/LGPL-license.txt deleted file mode 100644 index 4362b49151..0000000000 --- a/indra/newview/installers/darwin/firestormos-nightly-dmg/LGPL-license.txt +++ /dev/null @@ -1,502 +0,0 @@ - GNU LESSER GENERAL PUBLIC LICENSE - Version 2.1, February 1999 - - Copyright (C) 1991, 1999 Free Software Foundation, Inc. - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - -[This is the first released version of the Lesser GPL. It also counts - as the successor of the GNU Library Public License, version 2, hence - the version number 2.1.] - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -Licenses are intended to guarantee your freedom to share and change -free software--to make sure the software is free for all its users. - - This license, the Lesser General Public License, applies to some -specially designated software packages--typically libraries--of the -Free Software Foundation and other authors who decide to use it. You -can use it too, but we suggest you first think carefully about whether -this license or the ordinary General Public License is the better -strategy to use in any particular case, based on the explanations below. - - When we speak of free software, we are referring to freedom of use, -not price. Our General Public Licenses are designed to make sure that -you have the freedom to distribute copies of free software (and charge -for this service if you wish); that you receive source code or can get -it if you want it; that you can change the software and use pieces of -it in new free programs; and that you are informed that you can do -these things. - - To protect your rights, we need to make restrictions that forbid -distributors to deny you these rights or to ask you to surrender these -rights. These restrictions translate to certain responsibilities for -you if you distribute copies of the library or if you modify it. - - For example, if you distribute copies of the library, whether gratis -or for a fee, you must give the recipients all the rights that we gave -you. You must make sure that they, too, receive or can get the source -code. If you link other code with the library, you must provide -complete object files to the recipients, so that they can relink them -with the library after making changes to the library and recompiling -it. And you must show them these terms so they know their rights. - - We protect your rights with a two-step method: (1) we copyright the -library, and (2) we offer you this license, which gives you legal -permission to copy, distribute and/or modify the library. - - To protect each distributor, we want to make it very clear that -there is no warranty for the free library. Also, if the library is -modified by someone else and passed on, the recipients should know -that what they have is not the original version, so that the original -author's reputation will not be affected by problems that might be -introduced by others. - - Finally, software patents pose a constant threat to the existence of -any free program. We wish to make sure that a company cannot -effectively restrict the users of a free program by obtaining a -restrictive license from a patent holder. Therefore, we insist that -any patent license obtained for a version of the library must be -consistent with the full freedom of use specified in this license. - - Most GNU software, including some libraries, is covered by the -ordinary GNU General Public License. This license, the GNU Lesser -General Public License, applies to certain designated libraries, and -is quite different from the ordinary General Public License. We use -this license for certain libraries in order to permit linking those -libraries into non-free programs. - - When a program is linked with a library, whether statically or using -a shared library, the combination of the two is legally speaking a -combined work, a derivative of the original library. The ordinary -General Public License therefore permits such linking only if the -entire combination fits its criteria of freedom. The Lesser General -Public License permits more lax criteria for linking other code with -the library. - - We call this license the "Lesser" General Public License because it -does Less to protect the user's freedom than the ordinary General -Public License. It also provides other free software developers Less -of an advantage over competing non-free programs. These disadvantages -are the reason we use the ordinary General Public License for many -libraries. However, the Lesser license provides advantages in certain -special circumstances. - - For example, on rare occasions, there may be a special need to -encourage the widest possible use of a certain library, so that it becomes -a de-facto standard. To achieve this, non-free programs must be -allowed to use the library. A more frequent case is that a free -library does the same job as widely used non-free libraries. In this -case, there is little to gain by limiting the free library to free -software only, so we use the Lesser General Public License. - - In other cases, permission to use a particular library in non-free -programs enables a greater number of people to use a large body of -free software. For example, permission to use the GNU C Library in -non-free programs enables many more people to use the whole GNU -operating system, as well as its variant, the GNU/Linux operating -system. - - Although the Lesser General Public License is Less protective of the -users' freedom, it does ensure that the user of a program that is -linked with the Library has the freedom and the wherewithal to run -that program using a modified version of the Library. - - The precise terms and conditions for copying, distribution and -modification follow. Pay close attention to the difference between a -"work based on the library" and a "work that uses the library". The -former contains code derived from the library, whereas the latter must -be combined with the library in order to run. - - GNU LESSER GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License Agreement applies to any software library or other -program which contains a notice placed by the copyright holder or -other authorized party saying it may be distributed under the terms of -this Lesser General Public License (also called "this License"). -Each licensee is addressed as "you". - - A "library" means a collection of software functions and/or data -prepared so as to be conveniently linked with application programs -(which use some of those functions and data) to form executables. - - The "Library", below, refers to any such software library or work -which has been distributed under these terms. A "work based on the -Library" means either the Library or any derivative work under -copyright law: that is to say, a work containing the Library or a -portion of it, either verbatim or with modifications and/or translated -straightforwardly into another language. (Hereinafter, translation is -included without limitation in the term "modification".) - - "Source code" for a work means the preferred form of the work for -making modifications to it. For a library, complete source code means -all the source code for all modules it contains, plus any associated -interface definition files, plus the scripts used to control compilation -and installation of the library. - - Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running a program using the Library is not restricted, and output from -such a program is covered only if its contents constitute a work based -on the Library (independent of the use of the Library in a tool for -writing it). Whether that is true depends on what the Library does -and what the program that uses the Library does. - - 1. You may copy and distribute verbatim copies of the Library's -complete source code as you receive it, in any medium, provided that -you conspicuously and appropriately publish on each copy an -appropriate copyright notice and disclaimer of warranty; keep intact -all the notices that refer to this License and to the absence of any -warranty; and distribute a copy of this License along with the -Library. - - You may charge a fee for the physical act of transferring a copy, -and you may at your option offer warranty protection in exchange for a -fee. - - 2. You may modify your copy or copies of the Library or any portion -of it, thus forming a work based on the Library, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) The modified work must itself be a software library. - - b) You must cause the files modified to carry prominent notices - stating that you changed the files and the date of any change. - - c) You must cause the whole of the work to be licensed at no - charge to all third parties under the terms of this License. - - d) If a facility in the modified Library refers to a function or a - table of data to be supplied by an application program that uses - the facility, other than as an argument passed when the facility - is invoked, then you must make a good faith effort to ensure that, - in the event an application does not supply such function or - table, the facility still operates, and performs whatever part of - its purpose remains meaningful. - - (For example, a function in a library to compute square roots has - a purpose that is entirely well-defined independent of the - application. Therefore, Subsection 2d requires that any - application-supplied function or table used by this function must - be optional: if the application does not supply it, the square - root function must still compute square roots.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Library, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Library, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote -it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Library. - -In addition, mere aggregation of another work not based on the Library -with the Library (or with a work based on the Library) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may opt to apply the terms of the ordinary GNU General Public -License instead of this License to a given copy of the Library. To do -this, you must alter all the notices that refer to this License, so -that they refer to the ordinary GNU General Public License, version 2, -instead of to this License. (If a newer version than version 2 of the -ordinary GNU General Public License has appeared, then you can specify -that version instead if you wish.) Do not make any other change in -these notices. - - Once this change is made in a given copy, it is irreversible for -that copy, so the ordinary GNU General Public License applies to all -subsequent copies and derivative works made from that copy. - - This option is useful when you wish to copy part of the code of -the Library into a program that is not a library. - - 4. You may copy and distribute the Library (or a portion or -derivative of it, under Section 2) in object code or executable form -under the terms of Sections 1 and 2 above provided that you accompany -it with the complete corresponding machine-readable source code, which -must be distributed under the terms of Sections 1 and 2 above on a -medium customarily used for software interchange. - - If distribution of object code is made by offering access to copy -from a designated place, then offering equivalent access to copy the -source code from the same place satisfies the requirement to -distribute the source code, even though third parties are not -compelled to copy the source along with the object code. - - 5. A program that contains no derivative of any portion of the -Library, but is designed to work with the Library by being compiled or -linked with it, is called a "work that uses the Library". Such a -work, in isolation, is not a derivative work of the Library, and -therefore falls outside the scope of this License. - - However, linking a "work that uses the Library" with the Library -creates an executable that is a derivative of the Library (because it -contains portions of the Library), rather than a "work that uses the -library". The executable is therefore covered by this License. -Section 6 states terms for distribution of such executables. - - When a "work that uses the Library" uses material from a header file -that is part of the Library, the object code for the work may be a -derivative work of the Library even though the source code is not. -Whether this is true is especially significant if the work can be -linked without the Library, or if the work is itself a library. The -threshold for this to be true is not precisely defined by law. - - If such an object file uses only numerical parameters, data -structure layouts and accessors, and small macros and small inline -functions (ten lines or less in length), then the use of the object -file is unrestricted, regardless of whether it is legally a derivative -work. (Executables containing this object code plus portions of the -Library will still fall under Section 6.) - - Otherwise, if the work is a derivative of the Library, you may -distribute the object code for the work under the terms of Section 6. -Any executables containing that work also fall under Section 6, -whether or not they are linked directly with the Library itself. - - 6. As an exception to the Sections above, you may also combine or -link a "work that uses the Library" with the Library to produce a -work containing portions of the Library, and distribute that work -under terms of your choice, provided that the terms permit -modification of the work for the customer's own use and reverse -engineering for debugging such modifications. - - You must give prominent notice with each copy of the work that the -Library is used in it and that the Library and its use are covered by -this License. You must supply a copy of this License. If the work -during execution displays copyright notices, you must include the -copyright notice for the Library among them, as well as a reference -directing the user to the copy of this License. Also, you must do one -of these things: - - a) Accompany the work with the complete corresponding - machine-readable source code for the Library including whatever - changes were used in the work (which must be distributed under - Sections 1 and 2 above); and, if the work is an executable linked - with the Library, with the complete machine-readable "work that - uses the Library", as object code and/or source code, so that the - user can modify the Library and then relink to produce a modified - executable containing the modified Library. (It is understood - that the user who changes the contents of definitions files in the - Library will not necessarily be able to recompile the application - to use the modified definitions.) - - b) Use a suitable shared library mechanism for linking with the - Library. A suitable mechanism is one that (1) uses at run time a - copy of the library already present on the user's computer system, - rather than copying library functions into the executable, and (2) - will operate properly with a modified version of the library, if - the user installs one, as long as the modified version is - interface-compatible with the version that the work was made with. - - c) Accompany the work with a written offer, valid for at - least three years, to give the same user the materials - specified in Subsection 6a, above, for a charge no more - than the cost of performing this distribution. - - d) If distribution of the work is made by offering access to copy - from a designated place, offer equivalent access to copy the above - specified materials from the same place. - - e) Verify that the user has already received a copy of these - materials or that you have already sent this user a copy. - - For an executable, the required form of the "work that uses the -Library" must include any data and utility programs needed for -reproducing the executable from it. However, as a special exception, -the materials to be distributed need not include anything that is -normally distributed (in either source or binary form) with the major -components (compiler, kernel, and so on) of the operating system on -which the executable runs, unless that component itself accompanies -the executable. - - It may happen that this requirement contradicts the license -restrictions of other proprietary libraries that do not normally -accompany the operating system. Such a contradiction means you cannot -use both them and the Library together in an executable that you -distribute. - - 7. You may place library facilities that are a work based on the -Library side-by-side in a single library together with other library -facilities not covered by this License, and distribute such a combined -library, provided that the separate distribution of the work based on -the Library and of the other library facilities is otherwise -permitted, and provided that you do these two things: - - a) Accompany the combined library with a copy of the same work - based on the Library, uncombined with any other library - facilities. This must be distributed under the terms of the - Sections above. - - b) Give prominent notice with the combined library of the fact - that part of it is a work based on the Library, and explaining - where to find the accompanying uncombined form of the same work. - - 8. You may not copy, modify, sublicense, link with, or distribute -the Library except as expressly provided under this License. Any -attempt otherwise to copy, modify, sublicense, link with, or -distribute the Library is void, and will automatically terminate your -rights under this License. However, parties who have received copies, -or rights, from you under this License will not have their licenses -terminated so long as such parties remain in full compliance. - - 9. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Library or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Library (or any work based on the -Library), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Library or works based on it. - - 10. Each time you redistribute the Library (or any work based on the -Library), the recipient automatically receives a license from the -original licensor to copy, distribute, link with or modify the Library -subject to these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties with -this License. - - 11. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Library at all. For example, if a patent -license would not permit royalty-free redistribution of the Library by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Library. - -If any portion of this section is held invalid or unenforceable under any -particular circumstance, the balance of the section is intended to apply, -and the section as a whole is intended to apply in other circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 12. If the distribution and/or use of the Library is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Library under this License may add -an explicit geographical distribution limitation excluding those countries, -so that distribution is permitted only in or among countries not thus -excluded. In such case, this License incorporates the limitation as if -written in the body of this License. - - 13. The Free Software Foundation may publish revised and/or new -versions of the Lesser General Public License from time to time. -Such new versions will be similar in spirit to the present version, -but may differ in detail to address new problems or concerns. - -Each version is given a distinguishing version number. If the Library -specifies a version number of this License which applies to it and -"any later version", you have the option of following the terms and -conditions either of that version or of any later version published by -the Free Software Foundation. If the Library does not specify a -license version number, you may choose any version ever published by -the Free Software Foundation. - - 14. If you wish to incorporate parts of the Library into other free -programs whose distribution conditions are incompatible with these, -write to the author to ask for permission. For software which is -copyrighted by the Free Software Foundation, write to the Free -Software Foundation; we sometimes make exceptions for this. Our -decision will be guided by the two goals of preserving the free status -of all derivatives of our free software and of promoting the sharing -and reuse of software generally. - - NO WARRANTY - - 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO -WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. -EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR -OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY -KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE -LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME -THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN -WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY -AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU -FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR -CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE -LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING -RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A -FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF -SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH -DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Libraries - - If you develop a new library, and you want it to be of the greatest -possible use to the public, we recommend making it free software that -everyone can redistribute and change. You can do so by permitting -redistribution under these terms (or, alternatively, under the terms of the -ordinary General Public License). - - To apply these terms, attach the following notices to the library. It is -safest to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least the -"copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -Also add information on how to contact you by electronic and paper mail. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the library, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the - library `Frob' (a library for tweaking knobs) written by James Random Hacker. - - , 1 April 1990 - Ty Coon, President of Vice - -That's all there is to it! diff --git a/indra/newview/installers/darwin/firestormos-nightly-dmg/VivoxAUP.txt b/indra/newview/installers/darwin/firestormos-nightly-dmg/VivoxAUP.txt deleted file mode 100644 index 6413f8b16a..0000000000 --- a/indra/newview/installers/darwin/firestormos-nightly-dmg/VivoxAUP.txt +++ /dev/null @@ -1,23 +0,0 @@ -Acceptable Use Policy (AUP) - - 1. BACKGROUND: Users of the online voice services provided by Vivox, Inc. ("Vivox") (the "Service"), through the act of utilizing the Service, agree to adhere to this Acceptable Use Policy (the "Policy"). Vivox reserves the right to immediately terminate a user's access to the Service if the user engages in any of the activities prohibited by this Policy or uses the Service contrary to this Policy. Each user is responsible for all activities conducted under its account. The user is also responsible for adhering to any policy set forth by any other service provider accessed through the Service; Vivox, and its suppliers and providers, assume no responsibility or liability for a user's failure to comply with the Policy. The user acknowledges that Vivox may have access to information about or provided by the user, including diagnostic information sent automatically after a problem or error, and agrees to such access and use. - - 2. PROHIBITED USES AND ACTIVITIES: Users shall not provide inaccurate or misleading information to Vivox or use the Service to: (i) access any other person's computer or computer system, software, or data without their knowledge and consent; or breach the security of another user; or attempt to circumvent the user authentication or security of any host, network, system, or account, which includes, but is not limited to, accessing data not intended for the user, logging into or making use of a server or account the user is not expressly authorized to access, or probing the security of other hosts, networks, or accounts; or use automated means (such as robots and spiders) to obtain information from Vivox's website or, though it, from other websites; (ii) interfere with computer networking or telecommunications service to any user, host or network, including, without limitation, denial of service attacks, flooding of a network, overloading a service, improper seizing and abuse of operator privileges and attempts to "crash" a host; (iii) violate the rules, regulations, or policies applicable to any network, server, computer database, or service that accessed by the user; (iv) transmit, re-transmit, or store any content or to engage in any activity that infringes the intellectual property rights or privacy rights of Vivox or any individual, group or entity, including but not limited to any rights protected by any copyright, patent, trademark, trade secret, trade dress, right of privacy, right of publicity, moral rights or other intellectual property right now known or later recognized by statute, judicial decision or regulation; (v) host, post, transmit, or re-transmit any content or material that is threatening, harassing, obscene, indecent, pornographic, hateful, malicious, racist, defamatory, libelous, treasonous, excessively violent or promotes the use of violence, or provides instruction, information or assistance in causing or carrying out violence against any government, organization, group or individual, or provides guidance, information or assistance with respect to causing damage or security breaches to or Vivox's network or to the network of any other service provider; (vi) commit an act that constitutes a criminal offense, gives rise to civil liability, or otherwise violates any applicable local, state, federal or international law, or (vii) encourage conduct that would constitute a criminal offense, give rise to civil liability, or otherwise violate any applicable local, state, federal or international law. - - 3. SECURITY: In all cases, the user is solely responsible for the security of any device or application it chooses to connect to the Service, including any data stored on or communications passed. - - 4. TRADEMARKS AND COPYRIGHTS. "Vivox," "Powered by Vivox" and similar marks are the property of Vivox. All other names, graphics, logos, marks and trade names used in connection with this Service, are the property of their owners and suppliers and may not be used without permission for any purpose. The copyright in the Vivox website and Service and all related materials are owned by Vivox or its suppliers unless otherwise stated. - - 5. DISCLAIMER OF WARRANTIES. THE SERVICE IS PROVIDED "AS IS" AND "WITH ALL FAULTS," AND PROVIDER AND VIVOX HEREBY DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION (I) WARRANTIES OF MERCHANTIBILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT, AND (II) ANY WARRANTIES CONCERNING THE SECURITY, RELIABILITY OR PERFORMANCE OF THE SERVICE. Certain states prohibit the disclaimer of warranties in certain cases, so the above may not apply to all users in all instances. - - THE DOWNLOADING OR SUBMISSION OF ANY MATERIALS IS DONE AT THE USER'S OWN RISK, AND THE USER IS SOLELY RESPONSIBLE FOR ANY LOSS OR DAMAGE TO ANY CONTENT, IMAGE, COMPUTER SYSTEM OR DATA THAT MAY RESULT FROM USING THE SERVICE. - - 6. EXCLUSION OF DAMAGES. TO THE FULLEST EXTENT ALLOWED BY LAW, VIVOX SHALL NOT BE LIABLE FOR ANY INDIRECT OR CONSEQUENTIAL DAMAGES, INCLUDING INCIDENTAL, SPECIAL, EXEMPLARY AND PUNITIVE DAMAGES, RESULTING FROM THE USE OR PROVISION OF THE SERVICE, EVEN IF THE POSSIBILITY OF SUCH DAMAGES IS KNOWN. Certain states prohibit the limitation of liability in certain cases, so the above may not apply to the user in all instances. - - 7. ENFORCEMENT OF THIS POLICY: Vivox does not routinely monitors the activity of Service accounts for violation of this Policy. Vivox reserves the right at any time to monitor usage, transmissions, and content from time to time to operate the Service; to identify violations of this Policy; and/or to protect the network, the Service and/or other users. If the Service is used in a way that Vivox, in their sole discretion, believe violate this Policy, it may take any responsive actions they deem appropriate, including, but are not limited to, the immediate suspension or termination of all or any portion of the Service. Vivox will have no liability for any of these responsive actions. These actions are not exclusive remedies and Vivox may take any other legal or technical action deemed appropriate. The user expressly authorizes Vivox to cooperate with (i) law enforcement authorities in the investigation of suspected legal violations, and (ii) any system administrators at other Internet service providers or other network or computing facilities in order to enforce this Policy. This cooperation may include making available personally identifiable information about users to law enforcement or system administrators. The failure to enforce this Policy, for whatever reason or for no reason, shall not be construed as a waiver of any right to do so at any time. The user agrees that if any portion of this Policy is held invalid or unenforceable, such portion will be construed consistent with applicable law as nearly as possible, and the remaining portions will remain in full force and effect. The user agrees to indemnify, defend and hold harmless Vivox and its affiliates, suppliers, providers, and agents against all claims and expenses (including reasonable attorney fees) resulting from users engaging in any of the prohibited activities listed in this Policy or resulting from users violating the Policy or any other posted policy related to the Service. The foregoing user indemnification will survive any termination of the user's agreements with Vivox . - - 8. ARBITRATION. Except for the right of a party to seek equitable relief, any disputes arising under or related to this Agreement ("Dispute"), excluding any Dispute relating to the validity or infringement of any intellectual property right, will be resolved by negotiation, mediation and, if necessary, arbitration, as follows. The party raising such Dispute will promptly advise the other party in writing describing in reasonable detail the nature of such Dispute ("Notice of Dispute"). The parties will negotiate in good faith to resolve the Dispute, but if they have not done so within thirty (30) days, the parties will submit the Dispute to a mutually agreed mediation organization. If the parties are unable to resolve the Dispute within sixty (60) days after delivery of the Notice of Dispute, then the Dispute will be resolved by a single arbitrator in a final and binding arbitration under the then current procedural rules of the American Arbitration Association. All proceedings will be conducted in the English language in Boston, Massachusetts. The arbitrator will have no power to modify the terms or conditions of this Agreement, or to award punitive damages. Any award rendered in such arbitration may be enforced by either party in any Court of competent jurisdiction. - - 9. GENERAL TERMS. This Agreement is governed by the laws of the Commonwealth of Massachusetts. No agency, partnership, joint venture, employment or franchise relationship is intended or created by this Agreement. This AUP constitute the entire agreement between the parties concerning the use of the Service. If any provision of this Agreement is found to be unenforceable, it shall be deemed modified to the least extent needed to make the provision enforceable; the remaining terms of this Agreement shall remain in full force and effect. Vivox reserves the right to disclose any information about any user as required by a court order or as recommended by counsel in the context of any action by any government entity or other third party. - - 10. CHANGES TO THIS POLICY. Vivox may revise its Acceptable Use Policy from time to time without prior notice. Any changes will be presented in the latest version at the Vivox web site. All revised copies of the Policy are effective immediately upon a user's first use of the Service after the change has been posted. \ No newline at end of file diff --git a/indra/newview/installers/darwin/firestormos-nightly-dmg/background.png b/indra/newview/installers/darwin/firestormos-nightly-dmg/background.png index 0e134a3c5b..5e90b18d4e 100755 Binary files a/indra/newview/installers/darwin/firestormos-nightly-dmg/background.png and b/indra/newview/installers/darwin/firestormos-nightly-dmg/background.png differ diff --git a/indra/newview/installers/darwin/firestormos-private-dmg/LGPL-license.txt b/indra/newview/installers/darwin/firestormos-private-dmg/LGPL-license.txt deleted file mode 100644 index 4362b49151..0000000000 --- a/indra/newview/installers/darwin/firestormos-private-dmg/LGPL-license.txt +++ /dev/null @@ -1,502 +0,0 @@ - GNU LESSER GENERAL PUBLIC LICENSE - Version 2.1, February 1999 - - Copyright (C) 1991, 1999 Free Software Foundation, Inc. - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - -[This is the first released version of the Lesser GPL. It also counts - as the successor of the GNU Library Public License, version 2, hence - the version number 2.1.] - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -Licenses are intended to guarantee your freedom to share and change -free software--to make sure the software is free for all its users. - - This license, the Lesser General Public License, applies to some -specially designated software packages--typically libraries--of the -Free Software Foundation and other authors who decide to use it. You -can use it too, but we suggest you first think carefully about whether -this license or the ordinary General Public License is the better -strategy to use in any particular case, based on the explanations below. - - When we speak of free software, we are referring to freedom of use, -not price. Our General Public Licenses are designed to make sure that -you have the freedom to distribute copies of free software (and charge -for this service if you wish); that you receive source code or can get -it if you want it; that you can change the software and use pieces of -it in new free programs; and that you are informed that you can do -these things. - - To protect your rights, we need to make restrictions that forbid -distributors to deny you these rights or to ask you to surrender these -rights. These restrictions translate to certain responsibilities for -you if you distribute copies of the library or if you modify it. - - For example, if you distribute copies of the library, whether gratis -or for a fee, you must give the recipients all the rights that we gave -you. You must make sure that they, too, receive or can get the source -code. If you link other code with the library, you must provide -complete object files to the recipients, so that they can relink them -with the library after making changes to the library and recompiling -it. And you must show them these terms so they know their rights. - - We protect your rights with a two-step method: (1) we copyright the -library, and (2) we offer you this license, which gives you legal -permission to copy, distribute and/or modify the library. - - To protect each distributor, we want to make it very clear that -there is no warranty for the free library. Also, if the library is -modified by someone else and passed on, the recipients should know -that what they have is not the original version, so that the original -author's reputation will not be affected by problems that might be -introduced by others. - - Finally, software patents pose a constant threat to the existence of -any free program. We wish to make sure that a company cannot -effectively restrict the users of a free program by obtaining a -restrictive license from a patent holder. Therefore, we insist that -any patent license obtained for a version of the library must be -consistent with the full freedom of use specified in this license. - - Most GNU software, including some libraries, is covered by the -ordinary GNU General Public License. This license, the GNU Lesser -General Public License, applies to certain designated libraries, and -is quite different from the ordinary General Public License. We use -this license for certain libraries in order to permit linking those -libraries into non-free programs. - - When a program is linked with a library, whether statically or using -a shared library, the combination of the two is legally speaking a -combined work, a derivative of the original library. The ordinary -General Public License therefore permits such linking only if the -entire combination fits its criteria of freedom. The Lesser General -Public License permits more lax criteria for linking other code with -the library. - - We call this license the "Lesser" General Public License because it -does Less to protect the user's freedom than the ordinary General -Public License. It also provides other free software developers Less -of an advantage over competing non-free programs. These disadvantages -are the reason we use the ordinary General Public License for many -libraries. However, the Lesser license provides advantages in certain -special circumstances. - - For example, on rare occasions, there may be a special need to -encourage the widest possible use of a certain library, so that it becomes -a de-facto standard. To achieve this, non-free programs must be -allowed to use the library. A more frequent case is that a free -library does the same job as widely used non-free libraries. In this -case, there is little to gain by limiting the free library to free -software only, so we use the Lesser General Public License. - - In other cases, permission to use a particular library in non-free -programs enables a greater number of people to use a large body of -free software. For example, permission to use the GNU C Library in -non-free programs enables many more people to use the whole GNU -operating system, as well as its variant, the GNU/Linux operating -system. - - Although the Lesser General Public License is Less protective of the -users' freedom, it does ensure that the user of a program that is -linked with the Library has the freedom and the wherewithal to run -that program using a modified version of the Library. - - The precise terms and conditions for copying, distribution and -modification follow. Pay close attention to the difference between a -"work based on the library" and a "work that uses the library". The -former contains code derived from the library, whereas the latter must -be combined with the library in order to run. - - GNU LESSER GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License Agreement applies to any software library or other -program which contains a notice placed by the copyright holder or -other authorized party saying it may be distributed under the terms of -this Lesser General Public License (also called "this License"). -Each licensee is addressed as "you". - - A "library" means a collection of software functions and/or data -prepared so as to be conveniently linked with application programs -(which use some of those functions and data) to form executables. - - The "Library", below, refers to any such software library or work -which has been distributed under these terms. A "work based on the -Library" means either the Library or any derivative work under -copyright law: that is to say, a work containing the Library or a -portion of it, either verbatim or with modifications and/or translated -straightforwardly into another language. (Hereinafter, translation is -included without limitation in the term "modification".) - - "Source code" for a work means the preferred form of the work for -making modifications to it. For a library, complete source code means -all the source code for all modules it contains, plus any associated -interface definition files, plus the scripts used to control compilation -and installation of the library. - - Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running a program using the Library is not restricted, and output from -such a program is covered only if its contents constitute a work based -on the Library (independent of the use of the Library in a tool for -writing it). Whether that is true depends on what the Library does -and what the program that uses the Library does. - - 1. You may copy and distribute verbatim copies of the Library's -complete source code as you receive it, in any medium, provided that -you conspicuously and appropriately publish on each copy an -appropriate copyright notice and disclaimer of warranty; keep intact -all the notices that refer to this License and to the absence of any -warranty; and distribute a copy of this License along with the -Library. - - You may charge a fee for the physical act of transferring a copy, -and you may at your option offer warranty protection in exchange for a -fee. - - 2. You may modify your copy or copies of the Library or any portion -of it, thus forming a work based on the Library, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) The modified work must itself be a software library. - - b) You must cause the files modified to carry prominent notices - stating that you changed the files and the date of any change. - - c) You must cause the whole of the work to be licensed at no - charge to all third parties under the terms of this License. - - d) If a facility in the modified Library refers to a function or a - table of data to be supplied by an application program that uses - the facility, other than as an argument passed when the facility - is invoked, then you must make a good faith effort to ensure that, - in the event an application does not supply such function or - table, the facility still operates, and performs whatever part of - its purpose remains meaningful. - - (For example, a function in a library to compute square roots has - a purpose that is entirely well-defined independent of the - application. Therefore, Subsection 2d requires that any - application-supplied function or table used by this function must - be optional: if the application does not supply it, the square - root function must still compute square roots.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Library, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Library, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote -it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Library. - -In addition, mere aggregation of another work not based on the Library -with the Library (or with a work based on the Library) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may opt to apply the terms of the ordinary GNU General Public -License instead of this License to a given copy of the Library. To do -this, you must alter all the notices that refer to this License, so -that they refer to the ordinary GNU General Public License, version 2, -instead of to this License. (If a newer version than version 2 of the -ordinary GNU General Public License has appeared, then you can specify -that version instead if you wish.) Do not make any other change in -these notices. - - Once this change is made in a given copy, it is irreversible for -that copy, so the ordinary GNU General Public License applies to all -subsequent copies and derivative works made from that copy. - - This option is useful when you wish to copy part of the code of -the Library into a program that is not a library. - - 4. You may copy and distribute the Library (or a portion or -derivative of it, under Section 2) in object code or executable form -under the terms of Sections 1 and 2 above provided that you accompany -it with the complete corresponding machine-readable source code, which -must be distributed under the terms of Sections 1 and 2 above on a -medium customarily used for software interchange. - - If distribution of object code is made by offering access to copy -from a designated place, then offering equivalent access to copy the -source code from the same place satisfies the requirement to -distribute the source code, even though third parties are not -compelled to copy the source along with the object code. - - 5. A program that contains no derivative of any portion of the -Library, but is designed to work with the Library by being compiled or -linked with it, is called a "work that uses the Library". Such a -work, in isolation, is not a derivative work of the Library, and -therefore falls outside the scope of this License. - - However, linking a "work that uses the Library" with the Library -creates an executable that is a derivative of the Library (because it -contains portions of the Library), rather than a "work that uses the -library". The executable is therefore covered by this License. -Section 6 states terms for distribution of such executables. - - When a "work that uses the Library" uses material from a header file -that is part of the Library, the object code for the work may be a -derivative work of the Library even though the source code is not. -Whether this is true is especially significant if the work can be -linked without the Library, or if the work is itself a library. The -threshold for this to be true is not precisely defined by law. - - If such an object file uses only numerical parameters, data -structure layouts and accessors, and small macros and small inline -functions (ten lines or less in length), then the use of the object -file is unrestricted, regardless of whether it is legally a derivative -work. (Executables containing this object code plus portions of the -Library will still fall under Section 6.) - - Otherwise, if the work is a derivative of the Library, you may -distribute the object code for the work under the terms of Section 6. -Any executables containing that work also fall under Section 6, -whether or not they are linked directly with the Library itself. - - 6. As an exception to the Sections above, you may also combine or -link a "work that uses the Library" with the Library to produce a -work containing portions of the Library, and distribute that work -under terms of your choice, provided that the terms permit -modification of the work for the customer's own use and reverse -engineering for debugging such modifications. - - You must give prominent notice with each copy of the work that the -Library is used in it and that the Library and its use are covered by -this License. You must supply a copy of this License. If the work -during execution displays copyright notices, you must include the -copyright notice for the Library among them, as well as a reference -directing the user to the copy of this License. Also, you must do one -of these things: - - a) Accompany the work with the complete corresponding - machine-readable source code for the Library including whatever - changes were used in the work (which must be distributed under - Sections 1 and 2 above); and, if the work is an executable linked - with the Library, with the complete machine-readable "work that - uses the Library", as object code and/or source code, so that the - user can modify the Library and then relink to produce a modified - executable containing the modified Library. (It is understood - that the user who changes the contents of definitions files in the - Library will not necessarily be able to recompile the application - to use the modified definitions.) - - b) Use a suitable shared library mechanism for linking with the - Library. A suitable mechanism is one that (1) uses at run time a - copy of the library already present on the user's computer system, - rather than copying library functions into the executable, and (2) - will operate properly with a modified version of the library, if - the user installs one, as long as the modified version is - interface-compatible with the version that the work was made with. - - c) Accompany the work with a written offer, valid for at - least three years, to give the same user the materials - specified in Subsection 6a, above, for a charge no more - than the cost of performing this distribution. - - d) If distribution of the work is made by offering access to copy - from a designated place, offer equivalent access to copy the above - specified materials from the same place. - - e) Verify that the user has already received a copy of these - materials or that you have already sent this user a copy. - - For an executable, the required form of the "work that uses the -Library" must include any data and utility programs needed for -reproducing the executable from it. However, as a special exception, -the materials to be distributed need not include anything that is -normally distributed (in either source or binary form) with the major -components (compiler, kernel, and so on) of the operating system on -which the executable runs, unless that component itself accompanies -the executable. - - It may happen that this requirement contradicts the license -restrictions of other proprietary libraries that do not normally -accompany the operating system. Such a contradiction means you cannot -use both them and the Library together in an executable that you -distribute. - - 7. You may place library facilities that are a work based on the -Library side-by-side in a single library together with other library -facilities not covered by this License, and distribute such a combined -library, provided that the separate distribution of the work based on -the Library and of the other library facilities is otherwise -permitted, and provided that you do these two things: - - a) Accompany the combined library with a copy of the same work - based on the Library, uncombined with any other library - facilities. This must be distributed under the terms of the - Sections above. - - b) Give prominent notice with the combined library of the fact - that part of it is a work based on the Library, and explaining - where to find the accompanying uncombined form of the same work. - - 8. You may not copy, modify, sublicense, link with, or distribute -the Library except as expressly provided under this License. Any -attempt otherwise to copy, modify, sublicense, link with, or -distribute the Library is void, and will automatically terminate your -rights under this License. However, parties who have received copies, -or rights, from you under this License will not have their licenses -terminated so long as such parties remain in full compliance. - - 9. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Library or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Library (or any work based on the -Library), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Library or works based on it. - - 10. Each time you redistribute the Library (or any work based on the -Library), the recipient automatically receives a license from the -original licensor to copy, distribute, link with or modify the Library -subject to these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties with -this License. - - 11. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Library at all. For example, if a patent -license would not permit royalty-free redistribution of the Library by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Library. - -If any portion of this section is held invalid or unenforceable under any -particular circumstance, the balance of the section is intended to apply, -and the section as a whole is intended to apply in other circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 12. If the distribution and/or use of the Library is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Library under this License may add -an explicit geographical distribution limitation excluding those countries, -so that distribution is permitted only in or among countries not thus -excluded. In such case, this License incorporates the limitation as if -written in the body of this License. - - 13. The Free Software Foundation may publish revised and/or new -versions of the Lesser General Public License from time to time. -Such new versions will be similar in spirit to the present version, -but may differ in detail to address new problems or concerns. - -Each version is given a distinguishing version number. If the Library -specifies a version number of this License which applies to it and -"any later version", you have the option of following the terms and -conditions either of that version or of any later version published by -the Free Software Foundation. If the Library does not specify a -license version number, you may choose any version ever published by -the Free Software Foundation. - - 14. If you wish to incorporate parts of the Library into other free -programs whose distribution conditions are incompatible with these, -write to the author to ask for permission. For software which is -copyrighted by the Free Software Foundation, write to the Free -Software Foundation; we sometimes make exceptions for this. Our -decision will be guided by the two goals of preserving the free status -of all derivatives of our free software and of promoting the sharing -and reuse of software generally. - - NO WARRANTY - - 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO -WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. -EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR -OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY -KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE -LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME -THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN -WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY -AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU -FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR -CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE -LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING -RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A -FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF -SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH -DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Libraries - - If you develop a new library, and you want it to be of the greatest -possible use to the public, we recommend making it free software that -everyone can redistribute and change. You can do so by permitting -redistribution under these terms (or, alternatively, under the terms of the -ordinary General Public License). - - To apply these terms, attach the following notices to the library. It is -safest to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least the -"copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -Also add information on how to contact you by electronic and paper mail. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the library, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the - library `Frob' (a library for tweaking knobs) written by James Random Hacker. - - , 1 April 1990 - Ty Coon, President of Vice - -That's all there is to it! diff --git a/indra/newview/installers/darwin/firestormos-private-dmg/VivoxAUP.txt b/indra/newview/installers/darwin/firestormos-private-dmg/VivoxAUP.txt deleted file mode 100644 index 6413f8b16a..0000000000 --- a/indra/newview/installers/darwin/firestormos-private-dmg/VivoxAUP.txt +++ /dev/null @@ -1,23 +0,0 @@ -Acceptable Use Policy (AUP) - - 1. BACKGROUND: Users of the online voice services provided by Vivox, Inc. ("Vivox") (the "Service"), through the act of utilizing the Service, agree to adhere to this Acceptable Use Policy (the "Policy"). Vivox reserves the right to immediately terminate a user's access to the Service if the user engages in any of the activities prohibited by this Policy or uses the Service contrary to this Policy. Each user is responsible for all activities conducted under its account. The user is also responsible for adhering to any policy set forth by any other service provider accessed through the Service; Vivox, and its suppliers and providers, assume no responsibility or liability for a user's failure to comply with the Policy. The user acknowledges that Vivox may have access to information about or provided by the user, including diagnostic information sent automatically after a problem or error, and agrees to such access and use. - - 2. PROHIBITED USES AND ACTIVITIES: Users shall not provide inaccurate or misleading information to Vivox or use the Service to: (i) access any other person's computer or computer system, software, or data without their knowledge and consent; or breach the security of another user; or attempt to circumvent the user authentication or security of any host, network, system, or account, which includes, but is not limited to, accessing data not intended for the user, logging into or making use of a server or account the user is not expressly authorized to access, or probing the security of other hosts, networks, or accounts; or use automated means (such as robots and spiders) to obtain information from Vivox's website or, though it, from other websites; (ii) interfere with computer networking or telecommunications service to any user, host or network, including, without limitation, denial of service attacks, flooding of a network, overloading a service, improper seizing and abuse of operator privileges and attempts to "crash" a host; (iii) violate the rules, regulations, or policies applicable to any network, server, computer database, or service that accessed by the user; (iv) transmit, re-transmit, or store any content or to engage in any activity that infringes the intellectual property rights or privacy rights of Vivox or any individual, group or entity, including but not limited to any rights protected by any copyright, patent, trademark, trade secret, trade dress, right of privacy, right of publicity, moral rights or other intellectual property right now known or later recognized by statute, judicial decision or regulation; (v) host, post, transmit, or re-transmit any content or material that is threatening, harassing, obscene, indecent, pornographic, hateful, malicious, racist, defamatory, libelous, treasonous, excessively violent or promotes the use of violence, or provides instruction, information or assistance in causing or carrying out violence against any government, organization, group or individual, or provides guidance, information or assistance with respect to causing damage or security breaches to or Vivox's network or to the network of any other service provider; (vi) commit an act that constitutes a criminal offense, gives rise to civil liability, or otherwise violates any applicable local, state, federal or international law, or (vii) encourage conduct that would constitute a criminal offense, give rise to civil liability, or otherwise violate any applicable local, state, federal or international law. - - 3. SECURITY: In all cases, the user is solely responsible for the security of any device or application it chooses to connect to the Service, including any data stored on or communications passed. - - 4. TRADEMARKS AND COPYRIGHTS. "Vivox," "Powered by Vivox" and similar marks are the property of Vivox. All other names, graphics, logos, marks and trade names used in connection with this Service, are the property of their owners and suppliers and may not be used without permission for any purpose. The copyright in the Vivox website and Service and all related materials are owned by Vivox or its suppliers unless otherwise stated. - - 5. DISCLAIMER OF WARRANTIES. THE SERVICE IS PROVIDED "AS IS" AND "WITH ALL FAULTS," AND PROVIDER AND VIVOX HEREBY DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION (I) WARRANTIES OF MERCHANTIBILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT, AND (II) ANY WARRANTIES CONCERNING THE SECURITY, RELIABILITY OR PERFORMANCE OF THE SERVICE. Certain states prohibit the disclaimer of warranties in certain cases, so the above may not apply to all users in all instances. - - THE DOWNLOADING OR SUBMISSION OF ANY MATERIALS IS DONE AT THE USER'S OWN RISK, AND THE USER IS SOLELY RESPONSIBLE FOR ANY LOSS OR DAMAGE TO ANY CONTENT, IMAGE, COMPUTER SYSTEM OR DATA THAT MAY RESULT FROM USING THE SERVICE. - - 6. EXCLUSION OF DAMAGES. TO THE FULLEST EXTENT ALLOWED BY LAW, VIVOX SHALL NOT BE LIABLE FOR ANY INDIRECT OR CONSEQUENTIAL DAMAGES, INCLUDING INCIDENTAL, SPECIAL, EXEMPLARY AND PUNITIVE DAMAGES, RESULTING FROM THE USE OR PROVISION OF THE SERVICE, EVEN IF THE POSSIBILITY OF SUCH DAMAGES IS KNOWN. Certain states prohibit the limitation of liability in certain cases, so the above may not apply to the user in all instances. - - 7. ENFORCEMENT OF THIS POLICY: Vivox does not routinely monitors the activity of Service accounts for violation of this Policy. Vivox reserves the right at any time to monitor usage, transmissions, and content from time to time to operate the Service; to identify violations of this Policy; and/or to protect the network, the Service and/or other users. If the Service is used in a way that Vivox, in their sole discretion, believe violate this Policy, it may take any responsive actions they deem appropriate, including, but are not limited to, the immediate suspension or termination of all or any portion of the Service. Vivox will have no liability for any of these responsive actions. These actions are not exclusive remedies and Vivox may take any other legal or technical action deemed appropriate. The user expressly authorizes Vivox to cooperate with (i) law enforcement authorities in the investigation of suspected legal violations, and (ii) any system administrators at other Internet service providers or other network or computing facilities in order to enforce this Policy. This cooperation may include making available personally identifiable information about users to law enforcement or system administrators. The failure to enforce this Policy, for whatever reason or for no reason, shall not be construed as a waiver of any right to do so at any time. The user agrees that if any portion of this Policy is held invalid or unenforceable, such portion will be construed consistent with applicable law as nearly as possible, and the remaining portions will remain in full force and effect. The user agrees to indemnify, defend and hold harmless Vivox and its affiliates, suppliers, providers, and agents against all claims and expenses (including reasonable attorney fees) resulting from users engaging in any of the prohibited activities listed in this Policy or resulting from users violating the Policy or any other posted policy related to the Service. The foregoing user indemnification will survive any termination of the user's agreements with Vivox . - - 8. ARBITRATION. Except for the right of a party to seek equitable relief, any disputes arising under or related to this Agreement ("Dispute"), excluding any Dispute relating to the validity or infringement of any intellectual property right, will be resolved by negotiation, mediation and, if necessary, arbitration, as follows. The party raising such Dispute will promptly advise the other party in writing describing in reasonable detail the nature of such Dispute ("Notice of Dispute"). The parties will negotiate in good faith to resolve the Dispute, but if they have not done so within thirty (30) days, the parties will submit the Dispute to a mutually agreed mediation organization. If the parties are unable to resolve the Dispute within sixty (60) days after delivery of the Notice of Dispute, then the Dispute will be resolved by a single arbitrator in a final and binding arbitration under the then current procedural rules of the American Arbitration Association. All proceedings will be conducted in the English language in Boston, Massachusetts. The arbitrator will have no power to modify the terms or conditions of this Agreement, or to award punitive damages. Any award rendered in such arbitration may be enforced by either party in any Court of competent jurisdiction. - - 9. GENERAL TERMS. This Agreement is governed by the laws of the Commonwealth of Massachusetts. No agency, partnership, joint venture, employment or franchise relationship is intended or created by this Agreement. This AUP constitute the entire agreement between the parties concerning the use of the Service. If any provision of this Agreement is found to be unenforceable, it shall be deemed modified to the least extent needed to make the provision enforceable; the remaining terms of this Agreement shall remain in full force and effect. Vivox reserves the right to disclose any information about any user as required by a court order or as recommended by counsel in the context of any action by any government entity or other third party. - - 10. CHANGES TO THIS POLICY. Vivox may revise its Acceptable Use Policy from time to time without prior notice. Any changes will be presented in the latest version at the Vivox web site. All revised copies of the Policy are effective immediately upon a user's first use of the Service after the change has been posted. \ No newline at end of file diff --git a/indra/newview/installers/darwin/firestormos-private-dmg/background.png b/indra/newview/installers/darwin/firestormos-private-dmg/background.png index 060c54c18a..5e90b18d4e 100755 Binary files a/indra/newview/installers/darwin/firestormos-private-dmg/background.png and b/indra/newview/installers/darwin/firestormos-private-dmg/background.png differ diff --git a/indra/newview/installers/darwin/firestormos-release-dmg/LGPL-license.txt b/indra/newview/installers/darwin/firestormos-release-dmg/LGPL-license.txt deleted file mode 100644 index 4362b49151..0000000000 --- a/indra/newview/installers/darwin/firestormos-release-dmg/LGPL-license.txt +++ /dev/null @@ -1,502 +0,0 @@ - GNU LESSER GENERAL PUBLIC LICENSE - Version 2.1, February 1999 - - Copyright (C) 1991, 1999 Free Software Foundation, Inc. - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - -[This is the first released version of the Lesser GPL. It also counts - as the successor of the GNU Library Public License, version 2, hence - the version number 2.1.] - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -Licenses are intended to guarantee your freedom to share and change -free software--to make sure the software is free for all its users. - - This license, the Lesser General Public License, applies to some -specially designated software packages--typically libraries--of the -Free Software Foundation and other authors who decide to use it. You -can use it too, but we suggest you first think carefully about whether -this license or the ordinary General Public License is the better -strategy to use in any particular case, based on the explanations below. - - When we speak of free software, we are referring to freedom of use, -not price. Our General Public Licenses are designed to make sure that -you have the freedom to distribute copies of free software (and charge -for this service if you wish); that you receive source code or can get -it if you want it; that you can change the software and use pieces of -it in new free programs; and that you are informed that you can do -these things. - - To protect your rights, we need to make restrictions that forbid -distributors to deny you these rights or to ask you to surrender these -rights. These restrictions translate to certain responsibilities for -you if you distribute copies of the library or if you modify it. - - For example, if you distribute copies of the library, whether gratis -or for a fee, you must give the recipients all the rights that we gave -you. You must make sure that they, too, receive or can get the source -code. If you link other code with the library, you must provide -complete object files to the recipients, so that they can relink them -with the library after making changes to the library and recompiling -it. And you must show them these terms so they know their rights. - - We protect your rights with a two-step method: (1) we copyright the -library, and (2) we offer you this license, which gives you legal -permission to copy, distribute and/or modify the library. - - To protect each distributor, we want to make it very clear that -there is no warranty for the free library. Also, if the library is -modified by someone else and passed on, the recipients should know -that what they have is not the original version, so that the original -author's reputation will not be affected by problems that might be -introduced by others. - - Finally, software patents pose a constant threat to the existence of -any free program. We wish to make sure that a company cannot -effectively restrict the users of a free program by obtaining a -restrictive license from a patent holder. Therefore, we insist that -any patent license obtained for a version of the library must be -consistent with the full freedom of use specified in this license. - - Most GNU software, including some libraries, is covered by the -ordinary GNU General Public License. This license, the GNU Lesser -General Public License, applies to certain designated libraries, and -is quite different from the ordinary General Public License. We use -this license for certain libraries in order to permit linking those -libraries into non-free programs. - - When a program is linked with a library, whether statically or using -a shared library, the combination of the two is legally speaking a -combined work, a derivative of the original library. The ordinary -General Public License therefore permits such linking only if the -entire combination fits its criteria of freedom. The Lesser General -Public License permits more lax criteria for linking other code with -the library. - - We call this license the "Lesser" General Public License because it -does Less to protect the user's freedom than the ordinary General -Public License. It also provides other free software developers Less -of an advantage over competing non-free programs. These disadvantages -are the reason we use the ordinary General Public License for many -libraries. However, the Lesser license provides advantages in certain -special circumstances. - - For example, on rare occasions, there may be a special need to -encourage the widest possible use of a certain library, so that it becomes -a de-facto standard. To achieve this, non-free programs must be -allowed to use the library. A more frequent case is that a free -library does the same job as widely used non-free libraries. In this -case, there is little to gain by limiting the free library to free -software only, so we use the Lesser General Public License. - - In other cases, permission to use a particular library in non-free -programs enables a greater number of people to use a large body of -free software. For example, permission to use the GNU C Library in -non-free programs enables many more people to use the whole GNU -operating system, as well as its variant, the GNU/Linux operating -system. - - Although the Lesser General Public License is Less protective of the -users' freedom, it does ensure that the user of a program that is -linked with the Library has the freedom and the wherewithal to run -that program using a modified version of the Library. - - The precise terms and conditions for copying, distribution and -modification follow. Pay close attention to the difference between a -"work based on the library" and a "work that uses the library". The -former contains code derived from the library, whereas the latter must -be combined with the library in order to run. - - GNU LESSER GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License Agreement applies to any software library or other -program which contains a notice placed by the copyright holder or -other authorized party saying it may be distributed under the terms of -this Lesser General Public License (also called "this License"). -Each licensee is addressed as "you". - - A "library" means a collection of software functions and/or data -prepared so as to be conveniently linked with application programs -(which use some of those functions and data) to form executables. - - The "Library", below, refers to any such software library or work -which has been distributed under these terms. A "work based on the -Library" means either the Library or any derivative work under -copyright law: that is to say, a work containing the Library or a -portion of it, either verbatim or with modifications and/or translated -straightforwardly into another language. (Hereinafter, translation is -included without limitation in the term "modification".) - - "Source code" for a work means the preferred form of the work for -making modifications to it. For a library, complete source code means -all the source code for all modules it contains, plus any associated -interface definition files, plus the scripts used to control compilation -and installation of the library. - - Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running a program using the Library is not restricted, and output from -such a program is covered only if its contents constitute a work based -on the Library (independent of the use of the Library in a tool for -writing it). Whether that is true depends on what the Library does -and what the program that uses the Library does. - - 1. You may copy and distribute verbatim copies of the Library's -complete source code as you receive it, in any medium, provided that -you conspicuously and appropriately publish on each copy an -appropriate copyright notice and disclaimer of warranty; keep intact -all the notices that refer to this License and to the absence of any -warranty; and distribute a copy of this License along with the -Library. - - You may charge a fee for the physical act of transferring a copy, -and you may at your option offer warranty protection in exchange for a -fee. - - 2. You may modify your copy or copies of the Library or any portion -of it, thus forming a work based on the Library, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) The modified work must itself be a software library. - - b) You must cause the files modified to carry prominent notices - stating that you changed the files and the date of any change. - - c) You must cause the whole of the work to be licensed at no - charge to all third parties under the terms of this License. - - d) If a facility in the modified Library refers to a function or a - table of data to be supplied by an application program that uses - the facility, other than as an argument passed when the facility - is invoked, then you must make a good faith effort to ensure that, - in the event an application does not supply such function or - table, the facility still operates, and performs whatever part of - its purpose remains meaningful. - - (For example, a function in a library to compute square roots has - a purpose that is entirely well-defined independent of the - application. Therefore, Subsection 2d requires that any - application-supplied function or table used by this function must - be optional: if the application does not supply it, the square - root function must still compute square roots.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Library, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Library, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote -it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Library. - -In addition, mere aggregation of another work not based on the Library -with the Library (or with a work based on the Library) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may opt to apply the terms of the ordinary GNU General Public -License instead of this License to a given copy of the Library. To do -this, you must alter all the notices that refer to this License, so -that they refer to the ordinary GNU General Public License, version 2, -instead of to this License. (If a newer version than version 2 of the -ordinary GNU General Public License has appeared, then you can specify -that version instead if you wish.) Do not make any other change in -these notices. - - Once this change is made in a given copy, it is irreversible for -that copy, so the ordinary GNU General Public License applies to all -subsequent copies and derivative works made from that copy. - - This option is useful when you wish to copy part of the code of -the Library into a program that is not a library. - - 4. You may copy and distribute the Library (or a portion or -derivative of it, under Section 2) in object code or executable form -under the terms of Sections 1 and 2 above provided that you accompany -it with the complete corresponding machine-readable source code, which -must be distributed under the terms of Sections 1 and 2 above on a -medium customarily used for software interchange. - - If distribution of object code is made by offering access to copy -from a designated place, then offering equivalent access to copy the -source code from the same place satisfies the requirement to -distribute the source code, even though third parties are not -compelled to copy the source along with the object code. - - 5. A program that contains no derivative of any portion of the -Library, but is designed to work with the Library by being compiled or -linked with it, is called a "work that uses the Library". Such a -work, in isolation, is not a derivative work of the Library, and -therefore falls outside the scope of this License. - - However, linking a "work that uses the Library" with the Library -creates an executable that is a derivative of the Library (because it -contains portions of the Library), rather than a "work that uses the -library". The executable is therefore covered by this License. -Section 6 states terms for distribution of such executables. - - When a "work that uses the Library" uses material from a header file -that is part of the Library, the object code for the work may be a -derivative work of the Library even though the source code is not. -Whether this is true is especially significant if the work can be -linked without the Library, or if the work is itself a library. The -threshold for this to be true is not precisely defined by law. - - If such an object file uses only numerical parameters, data -structure layouts and accessors, and small macros and small inline -functions (ten lines or less in length), then the use of the object -file is unrestricted, regardless of whether it is legally a derivative -work. (Executables containing this object code plus portions of the -Library will still fall under Section 6.) - - Otherwise, if the work is a derivative of the Library, you may -distribute the object code for the work under the terms of Section 6. -Any executables containing that work also fall under Section 6, -whether or not they are linked directly with the Library itself. - - 6. As an exception to the Sections above, you may also combine or -link a "work that uses the Library" with the Library to produce a -work containing portions of the Library, and distribute that work -under terms of your choice, provided that the terms permit -modification of the work for the customer's own use and reverse -engineering for debugging such modifications. - - You must give prominent notice with each copy of the work that the -Library is used in it and that the Library and its use are covered by -this License. You must supply a copy of this License. If the work -during execution displays copyright notices, you must include the -copyright notice for the Library among them, as well as a reference -directing the user to the copy of this License. Also, you must do one -of these things: - - a) Accompany the work with the complete corresponding - machine-readable source code for the Library including whatever - changes were used in the work (which must be distributed under - Sections 1 and 2 above); and, if the work is an executable linked - with the Library, with the complete machine-readable "work that - uses the Library", as object code and/or source code, so that the - user can modify the Library and then relink to produce a modified - executable containing the modified Library. (It is understood - that the user who changes the contents of definitions files in the - Library will not necessarily be able to recompile the application - to use the modified definitions.) - - b) Use a suitable shared library mechanism for linking with the - Library. A suitable mechanism is one that (1) uses at run time a - copy of the library already present on the user's computer system, - rather than copying library functions into the executable, and (2) - will operate properly with a modified version of the library, if - the user installs one, as long as the modified version is - interface-compatible with the version that the work was made with. - - c) Accompany the work with a written offer, valid for at - least three years, to give the same user the materials - specified in Subsection 6a, above, for a charge no more - than the cost of performing this distribution. - - d) If distribution of the work is made by offering access to copy - from a designated place, offer equivalent access to copy the above - specified materials from the same place. - - e) Verify that the user has already received a copy of these - materials or that you have already sent this user a copy. - - For an executable, the required form of the "work that uses the -Library" must include any data and utility programs needed for -reproducing the executable from it. However, as a special exception, -the materials to be distributed need not include anything that is -normally distributed (in either source or binary form) with the major -components (compiler, kernel, and so on) of the operating system on -which the executable runs, unless that component itself accompanies -the executable. - - It may happen that this requirement contradicts the license -restrictions of other proprietary libraries that do not normally -accompany the operating system. Such a contradiction means you cannot -use both them and the Library together in an executable that you -distribute. - - 7. You may place library facilities that are a work based on the -Library side-by-side in a single library together with other library -facilities not covered by this License, and distribute such a combined -library, provided that the separate distribution of the work based on -the Library and of the other library facilities is otherwise -permitted, and provided that you do these two things: - - a) Accompany the combined library with a copy of the same work - based on the Library, uncombined with any other library - facilities. This must be distributed under the terms of the - Sections above. - - b) Give prominent notice with the combined library of the fact - that part of it is a work based on the Library, and explaining - where to find the accompanying uncombined form of the same work. - - 8. You may not copy, modify, sublicense, link with, or distribute -the Library except as expressly provided under this License. Any -attempt otherwise to copy, modify, sublicense, link with, or -distribute the Library is void, and will automatically terminate your -rights under this License. However, parties who have received copies, -or rights, from you under this License will not have their licenses -terminated so long as such parties remain in full compliance. - - 9. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Library or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Library (or any work based on the -Library), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Library or works based on it. - - 10. Each time you redistribute the Library (or any work based on the -Library), the recipient automatically receives a license from the -original licensor to copy, distribute, link with or modify the Library -subject to these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties with -this License. - - 11. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Library at all. For example, if a patent -license would not permit royalty-free redistribution of the Library by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Library. - -If any portion of this section is held invalid or unenforceable under any -particular circumstance, the balance of the section is intended to apply, -and the section as a whole is intended to apply in other circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 12. If the distribution and/or use of the Library is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Library under this License may add -an explicit geographical distribution limitation excluding those countries, -so that distribution is permitted only in or among countries not thus -excluded. In such case, this License incorporates the limitation as if -written in the body of this License. - - 13. The Free Software Foundation may publish revised and/or new -versions of the Lesser General Public License from time to time. -Such new versions will be similar in spirit to the present version, -but may differ in detail to address new problems or concerns. - -Each version is given a distinguishing version number. If the Library -specifies a version number of this License which applies to it and -"any later version", you have the option of following the terms and -conditions either of that version or of any later version published by -the Free Software Foundation. If the Library does not specify a -license version number, you may choose any version ever published by -the Free Software Foundation. - - 14. If you wish to incorporate parts of the Library into other free -programs whose distribution conditions are incompatible with these, -write to the author to ask for permission. For software which is -copyrighted by the Free Software Foundation, write to the Free -Software Foundation; we sometimes make exceptions for this. Our -decision will be guided by the two goals of preserving the free status -of all derivatives of our free software and of promoting the sharing -and reuse of software generally. - - NO WARRANTY - - 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO -WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. -EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR -OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY -KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE -LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME -THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN -WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY -AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU -FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR -CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE -LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING -RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A -FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF -SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH -DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Libraries - - If you develop a new library, and you want it to be of the greatest -possible use to the public, we recommend making it free software that -everyone can redistribute and change. You can do so by permitting -redistribution under these terms (or, alternatively, under the terms of the -ordinary General Public License). - - To apply these terms, attach the following notices to the library. It is -safest to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least the -"copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -Also add information on how to contact you by electronic and paper mail. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the library, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the - library `Frob' (a library for tweaking knobs) written by James Random Hacker. - - , 1 April 1990 - Ty Coon, President of Vice - -That's all there is to it! diff --git a/indra/newview/installers/darwin/firestormos-release-dmg/VivoxAUP.txt b/indra/newview/installers/darwin/firestormos-release-dmg/VivoxAUP.txt deleted file mode 100644 index 6413f8b16a..0000000000 --- a/indra/newview/installers/darwin/firestormos-release-dmg/VivoxAUP.txt +++ /dev/null @@ -1,23 +0,0 @@ -Acceptable Use Policy (AUP) - - 1. BACKGROUND: Users of the online voice services provided by Vivox, Inc. ("Vivox") (the "Service"), through the act of utilizing the Service, agree to adhere to this Acceptable Use Policy (the "Policy"). Vivox reserves the right to immediately terminate a user's access to the Service if the user engages in any of the activities prohibited by this Policy or uses the Service contrary to this Policy. Each user is responsible for all activities conducted under its account. The user is also responsible for adhering to any policy set forth by any other service provider accessed through the Service; Vivox, and its suppliers and providers, assume no responsibility or liability for a user's failure to comply with the Policy. The user acknowledges that Vivox may have access to information about or provided by the user, including diagnostic information sent automatically after a problem or error, and agrees to such access and use. - - 2. PROHIBITED USES AND ACTIVITIES: Users shall not provide inaccurate or misleading information to Vivox or use the Service to: (i) access any other person's computer or computer system, software, or data without their knowledge and consent; or breach the security of another user; or attempt to circumvent the user authentication or security of any host, network, system, or account, which includes, but is not limited to, accessing data not intended for the user, logging into or making use of a server or account the user is not expressly authorized to access, or probing the security of other hosts, networks, or accounts; or use automated means (such as robots and spiders) to obtain information from Vivox's website or, though it, from other websites; (ii) interfere with computer networking or telecommunications service to any user, host or network, including, without limitation, denial of service attacks, flooding of a network, overloading a service, improper seizing and abuse of operator privileges and attempts to "crash" a host; (iii) violate the rules, regulations, or policies applicable to any network, server, computer database, or service that accessed by the user; (iv) transmit, re-transmit, or store any content or to engage in any activity that infringes the intellectual property rights or privacy rights of Vivox or any individual, group or entity, including but not limited to any rights protected by any copyright, patent, trademark, trade secret, trade dress, right of privacy, right of publicity, moral rights or other intellectual property right now known or later recognized by statute, judicial decision or regulation; (v) host, post, transmit, or re-transmit any content or material that is threatening, harassing, obscene, indecent, pornographic, hateful, malicious, racist, defamatory, libelous, treasonous, excessively violent or promotes the use of violence, or provides instruction, information or assistance in causing or carrying out violence against any government, organization, group or individual, or provides guidance, information or assistance with respect to causing damage or security breaches to or Vivox's network or to the network of any other service provider; (vi) commit an act that constitutes a criminal offense, gives rise to civil liability, or otherwise violates any applicable local, state, federal or international law, or (vii) encourage conduct that would constitute a criminal offense, give rise to civil liability, or otherwise violate any applicable local, state, federal or international law. - - 3. SECURITY: In all cases, the user is solely responsible for the security of any device or application it chooses to connect to the Service, including any data stored on or communications passed. - - 4. TRADEMARKS AND COPYRIGHTS. "Vivox," "Powered by Vivox" and similar marks are the property of Vivox. All other names, graphics, logos, marks and trade names used in connection with this Service, are the property of their owners and suppliers and may not be used without permission for any purpose. The copyright in the Vivox website and Service and all related materials are owned by Vivox or its suppliers unless otherwise stated. - - 5. DISCLAIMER OF WARRANTIES. THE SERVICE IS PROVIDED "AS IS" AND "WITH ALL FAULTS," AND PROVIDER AND VIVOX HEREBY DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION (I) WARRANTIES OF MERCHANTIBILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT, AND (II) ANY WARRANTIES CONCERNING THE SECURITY, RELIABILITY OR PERFORMANCE OF THE SERVICE. Certain states prohibit the disclaimer of warranties in certain cases, so the above may not apply to all users in all instances. - - THE DOWNLOADING OR SUBMISSION OF ANY MATERIALS IS DONE AT THE USER'S OWN RISK, AND THE USER IS SOLELY RESPONSIBLE FOR ANY LOSS OR DAMAGE TO ANY CONTENT, IMAGE, COMPUTER SYSTEM OR DATA THAT MAY RESULT FROM USING THE SERVICE. - - 6. EXCLUSION OF DAMAGES. TO THE FULLEST EXTENT ALLOWED BY LAW, VIVOX SHALL NOT BE LIABLE FOR ANY INDIRECT OR CONSEQUENTIAL DAMAGES, INCLUDING INCIDENTAL, SPECIAL, EXEMPLARY AND PUNITIVE DAMAGES, RESULTING FROM THE USE OR PROVISION OF THE SERVICE, EVEN IF THE POSSIBILITY OF SUCH DAMAGES IS KNOWN. Certain states prohibit the limitation of liability in certain cases, so the above may not apply to the user in all instances. - - 7. ENFORCEMENT OF THIS POLICY: Vivox does not routinely monitors the activity of Service accounts for violation of this Policy. Vivox reserves the right at any time to monitor usage, transmissions, and content from time to time to operate the Service; to identify violations of this Policy; and/or to protect the network, the Service and/or other users. If the Service is used in a way that Vivox, in their sole discretion, believe violate this Policy, it may take any responsive actions they deem appropriate, including, but are not limited to, the immediate suspension or termination of all or any portion of the Service. Vivox will have no liability for any of these responsive actions. These actions are not exclusive remedies and Vivox may take any other legal or technical action deemed appropriate. The user expressly authorizes Vivox to cooperate with (i) law enforcement authorities in the investigation of suspected legal violations, and (ii) any system administrators at other Internet service providers or other network or computing facilities in order to enforce this Policy. This cooperation may include making available personally identifiable information about users to law enforcement or system administrators. The failure to enforce this Policy, for whatever reason or for no reason, shall not be construed as a waiver of any right to do so at any time. The user agrees that if any portion of this Policy is held invalid or unenforceable, such portion will be construed consistent with applicable law as nearly as possible, and the remaining portions will remain in full force and effect. The user agrees to indemnify, defend and hold harmless Vivox and its affiliates, suppliers, providers, and agents against all claims and expenses (including reasonable attorney fees) resulting from users engaging in any of the prohibited activities listed in this Policy or resulting from users violating the Policy or any other posted policy related to the Service. The foregoing user indemnification will survive any termination of the user's agreements with Vivox . - - 8. ARBITRATION. Except for the right of a party to seek equitable relief, any disputes arising under or related to this Agreement ("Dispute"), excluding any Dispute relating to the validity or infringement of any intellectual property right, will be resolved by negotiation, mediation and, if necessary, arbitration, as follows. The party raising such Dispute will promptly advise the other party in writing describing in reasonable detail the nature of such Dispute ("Notice of Dispute"). The parties will negotiate in good faith to resolve the Dispute, but if they have not done so within thirty (30) days, the parties will submit the Dispute to a mutually agreed mediation organization. If the parties are unable to resolve the Dispute within sixty (60) days after delivery of the Notice of Dispute, then the Dispute will be resolved by a single arbitrator in a final and binding arbitration under the then current procedural rules of the American Arbitration Association. All proceedings will be conducted in the English language in Boston, Massachusetts. The arbitrator will have no power to modify the terms or conditions of this Agreement, or to award punitive damages. Any award rendered in such arbitration may be enforced by either party in any Court of competent jurisdiction. - - 9. GENERAL TERMS. This Agreement is governed by the laws of the Commonwealth of Massachusetts. No agency, partnership, joint venture, employment or franchise relationship is intended or created by this Agreement. This AUP constitute the entire agreement between the parties concerning the use of the Service. If any provision of this Agreement is found to be unenforceable, it shall be deemed modified to the least extent needed to make the provision enforceable; the remaining terms of this Agreement shall remain in full force and effect. Vivox reserves the right to disclose any information about any user as required by a court order or as recommended by counsel in the context of any action by any government entity or other third party. - - 10. CHANGES TO THIS POLICY. Vivox may revise its Acceptable Use Policy from time to time without prior notice. Any changes will be presented in the latest version at the Vivox web site. All revised copies of the Policy are effective immediately upon a user's first use of the Service after the change has been posted. \ No newline at end of file diff --git a/indra/newview/installers/darwin/firestormos-release-dmg/background.png b/indra/newview/installers/darwin/firestormos-release-dmg/background.png index cbc32141dd..5e90b18d4e 100755 Binary files a/indra/newview/installers/darwin/firestormos-release-dmg/background.png and b/indra/newview/installers/darwin/firestormos-release-dmg/background.png differ diff --git a/indra/newview/installers/darwin/installer-dmg.applescript b/indra/newview/installers/darwin/installer-dmg.applescript index 5e29a4147c..56330fb814 100644 --- a/indra/newview/installers/darwin/installer-dmg.applescript +++ b/indra/newview/installers/darwin/installer-dmg.applescript @@ -8,11 +8,11 @@ on run (volumeName) tell disk (volumeName as string) open - set theXOrigin to 400 - set theYOrigin to 100 - set theWidth to 500 - set theHeight to 600 - set iconSize to 100 + set theXOrigin to 200 + set theYOrigin to 200 + set theWidth to 340 + set theHeight to 240 + set iconSize to 55 set theBottomRightX to (theXOrigin + theWidth) set theBottomRightY to (theYOrigin + theHeight) @@ -28,15 +28,9 @@ on run (volumeName) set file_list to every file repeat with i in file_list if the name of i is "Applications" then - set the position of i to {345, 200} + set the position of i to {200, 90} else if the name of i ends with ".app" then - set the position of i to {145, 200} - else if the name of i is "LGPL License.txt" then - set the position of i to {145, 400} - set the extension hidden of i to true - else if the name of i is "Vivox Acceptable Use Policy.txt" then - set the position of i to {345, 400} - set the extension hidden of i to true + set the position of i to {50, 90} end if end repeat -- This close-open hack is nessesary to save positions on 10.6 Snow Leopard diff --git a/indra/newview/installers/windows/installer_template.nsi b/indra/newview/installers/windows/installer_template.nsi index 14e09d4773..82bd7c12fd 100644 --- a/indra/newview/installers/windows/installer_template.nsi +++ b/indra/newview/installers/windows/installer_template.nsi @@ -762,9 +762,17 @@ Push $2 Delete "$2\AppData\Roaming\Firestorm\typed_locations.txt" # Delete files in \Users\\AppData\Local\Firestorm ${If} ${ISOPENSIM} == "0" - RMDir /r "$2\AppData\Local\Firestorm" #Delete the Havok cache folder + ${If} ${IS64BIT} == "0" + RMDir /r "$2\AppData\Local\Firestorm" #Delete the Havok cache folder + ${Else} + RMDir /r "$2\AppData\Local\Firestorm_x64" #Delete the OpenSim cache folder + ${EndIf} ${Else} - RMDir /r "$2\AppData\Local\FirestormOS" #Delete the OpenSim cache folder + ${If} ${IS64BIT} == "0" + RMDir /r "$2\AppData\Local\FirestormOS" #Delete the Havok cache folder + ${Else} + RMDir /r "$2\AppData\Local\FirestormOS_x64" #Delete the OpenSim cache folder + ${EndIf} ${EndIf} CONTINUE: diff --git a/indra/newview/licenses-linux.txt b/indra/newview/licenses-linux.txt index b43c402e64..e53ba94a36 100644 --- a/indra/newview/licenses-linux.txt +++ b/indra/newview/licenses-linux.txt @@ -638,7 +638,7 @@ Vivox SDK License RSA Data Security, Inc. MD5 Message-Digest Algorithm -Audio coding: Polycom¨ Siren14TM (ITU-T Rec. G.722.1 Annex C) +Audio coding: Polycom(R) Siren14TM (ITU-T Rec. G.722.1 Annex C) Open Source Software Licensing Each open source software component utilized by this product is subject to its own copyright and licensing terms, as listed below. diff --git a/indra/newview/licenses-mac.txt b/indra/newview/licenses-mac.txt index af80bff5d9..d0747ccd03 100644 --- a/indra/newview/licenses-mac.txt +++ b/indra/newview/licenses-mac.txt @@ -522,7 +522,7 @@ Vivox SDK License RSA Data Security, Inc. MD5 Message-Digest Algorithm -Audio coding: Polycom¨ Siren14TM (ITU-T Rec. G.722.1 Annex C) +Audio coding: Polycom(R) Siren14TM (ITU-T Rec. G.722.1 Annex C) Open Source Software Licensing Each open source software component utilized by this product is subject to its own copyright and licensing terms, as listed below. diff --git a/indra/newview/licenses-win32.txt b/indra/newview/licenses-win32.txt index 8736626907..98edd35bea 100644 --- a/indra/newview/licenses-win32.txt +++ b/indra/newview/licenses-win32.txt @@ -4,7 +4,7 @@ Logitech License End-User License Agreement for Logitech LCD SDK -This End-User License Agreement for Logitech LCD SDK ( “Agreement”) is a legal agreement between you, either an individual or legal entity (“You” or “you”) and Logitech Inc. (“Logitech”) for use of the Logitech LCD software development kit, which includes computer software and related media and documentation (hereinafter “LCD SDK”). By using this LCD SDK, you are agreeing to be bound by the terms and conditions of this Agreement. If you do not agree to the terms and conditions of this Agreement, promptly return the LCD SDK and other items that are part of this product in their original package with your sales receipt to your point of purchase for a full refund, or if you have downloaded this software from a Logitech web site, then you must stop using the software and destroy any copies of the software in your possession or control. +This End-User License Agreement for Logitech LCD SDK ( "Agreement") is a legal agreement between you, either an individual or legal entity ("You" or "you") and Logitech Inc. ("Logitech") for use of the Logitech LCD software development kit, which includes computer software and related media and documentation (hereinafter "LCD SDK"). By using this LCD SDK, you are agreeing to be bound by the terms and conditions of this Agreement. If you do not agree to the terms and conditions of this Agreement, promptly return the LCD SDK and other items that are part of this product in their original package with your sales receipt to your point of purchase for a full refund, or if you have downloaded this software from a Logitech web site, then you must stop using the software and destroy any copies of the software in your possession or control. 1 Grant of License and Restrictions. This Agreement grants You the following rights provided that You comply with all terms and conditions of this Agreement. @@ -14,7 +14,7 @@ This Agreement grants You the following rights provided that You comply with all (d) In the event Logitech, in its sole discretion, elects to provide copies of the LCD SDK to more than one individual employed by You (if You are not a single individual), each such individual shall be entitled to exercise the rights granted in this Agreement and shall be bound by the terms and conditions herein. 2 Updates. -Logitech is not obligated to provide technical support or updates to You for the LCD SDK provided to You pursuant to this Agreement. However, Logitech may, in its sole discretion, provide further pre-release versions, technical support, updates and/or supplements (“Updates”) to You, in which case such Updates shall be deemed to be included in the “LCD SDK” and shall be governed by this Agreement, unless other terms of use are provided in writing by Logitech with such Updates. +Logitech is not obligated to provide technical support or updates to You for the LCD SDK provided to You pursuant to this Agreement. However, Logitech may, in its sole discretion, provide further pre-release versions, technical support, updates and/or supplements ("Updates") to You, in which case such Updates shall be deemed to be included in the "LCD SDK" and shall be governed by this Agreement, unless other terms of use are provided in writing by Logitech with such Updates. 3 Intellectual Property Rights. The LCD SDK is licensed, not sold, to You for use only under the terms and conditions of this Agreement. Logitech and its suppliers retain title to the LCD SDK and all intellectual property rights therein. The LCD SDK is protected by intellectual property laws and international treaties, including U.S. copyright law and international copyright treaties. All rights not expressly granted by Logitech are reserved. @@ -23,7 +23,7 @@ The LCD SDK is licensed, not sold, to You for use only under the terms and condi TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW, LOGITECH AND ITS SUPPLIERS PROVIDE THE LCD SDK AND OTHER LOGITECH PRODUCTS AND SERVICES (IF ANY) AS IS AND WITHOUT WARRANTY OF ANY KIND. LOGITECH AND ITS SUPPLIERS EXPRESSLY DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD-PARTY RIGHTS WITH RESPECT TO THE LCD SDK AND ANY WARRANTIES OF NON-INTERFERENCE OR ACCURACY OF INFORMATIONAL CONTENT. NO LOGITECH DEALER, AGENT, OR EMPLOYEE IS AUTHORIZED TO MAKE ANY MODIFICATION, EXTENSION, OR ADDITION TO THIS WARRANTY. Some jurisdictions do not allow limitations on how long an implied warranty lasts, so the above limitation may not apply to you. 5 Limitation of Liability. -IN NO EVENT WILL LOGITECH OR ITS SUPPLIERS BE LIABLE FOR ANY COSTS OF PROCUREMENT OF SUBSTITUTE PRODUCTS OR SERVICES, LOST PROFITS, LOSS OF INFORMATION OR DATA, OR ANY OTHER SPECIAL, INDIRECT, CONSEQUENTIAL, OR INCIDENTAL DAMAGES ARISING IN ANY WAY OUT OF THE SALE OF, USE OF, OR INABILITY TO USE THE LCD SDK OR ANY LOGITECH PRODUCT OR SERVICE, EVEN IF LOGITECH HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. IN NO CASE SHALL LOGITECH'S AND ITS SUPPLIERS’ TOTAL LIABILITY EXCEED THE ACTUAL MONEY PAID FOR THE LOGITECH PRODUCT OR SERVICE GIVING RISE TO THE LIABILITY. Some jurisdictions do not allow the exclusion or limitation of incidental or consequential damages, so the above limitation or exclusion may not apply to you. The above limitations will not apply in case of personal injury where and to the extent that applicable law requires such liability. +IN NO EVENT WILL LOGITECH OR ITS SUPPLIERS BE LIABLE FOR ANY COSTS OF PROCUREMENT OF SUBSTITUTE PRODUCTS OR SERVICES, LOST PROFITS, LOSS OF INFORMATION OR DATA, OR ANY OTHER SPECIAL, INDIRECT, CONSEQUENTIAL, OR INCIDENTAL DAMAGES ARISING IN ANY WAY OUT OF THE SALE OF, USE OF, OR INABILITY TO USE THE LCD SDK OR ANY LOGITECH PRODUCT OR SERVICE, EVEN IF LOGITECH HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. IN NO CASE SHALL LOGITECH'S AND ITS SUPPLIERS' TOTAL LIABILITY EXCEED THE ACTUAL MONEY PAID FOR THE LOGITECH PRODUCT OR SERVICE GIVING RISE TO THE LIABILITY. Some jurisdictions do not allow the exclusion or limitation of incidental or consequential damages, so the above limitation or exclusion may not apply to you. The above limitations will not apply in case of personal injury where and to the extent that applicable law requires such liability. 6 U.S. Government Rights. Use, duplication, or disclosure of the software contained in the LCD SDK by the U.S. Government is subject to restrictions set forth in this Agreement and as provided in DFARS 227.7202-1(a) and 227.7202-3(a) (1995), DFARS 252.227-7013(c)(1)(ii) (OCT 1988) FAR 12.212(a) (1995), FAR 52.227-19, or FAR 52.227-14 (ALT III), as applicable. Logitech Inc. 6505 Kaiser Drive, Fremont, CA 94555. @@ -564,7 +564,7 @@ Vivox SDK License RSA Data Security, Inc. MD5 Message-Digest Algorithm -Audio coding: Polycom¨ Siren14TM (ITU-T Rec. G.722.1 Annex C) +Audio coding: Polycom(R) Siren14TM (ITU-T Rec. G.722.1 Annex C) Open Source Software Licensing Each open source software component utilized by this product is subject to its own copyright and licensing terms, as listed below. diff --git a/indra/newview/llagent.cpp b/indra/newview/llagent.cpp index 990edf51d1..007b957777 100644 --- a/indra/newview/llagent.cpp +++ b/indra/newview/llagent.cpp @@ -3471,10 +3471,7 @@ bool LLAgent::requestGetCapability(const std::string &capName, httpCallback_t cb { std::string url; - // FIRE-21323: Crashfix - //url = getRegion()->getCapability(capName); - url = getRegion() ? getRegion()->getCapability(capName) : ""; - // + url = getRegionCapability(capName); if (url.empty()) { @@ -5458,11 +5455,22 @@ void LLAgent::stopCurrentAnimations(bool force_keep_script_perms /*= false*/) { std::vector anim_ids; + // assume we need to restore the default standing animation + bool restore_stand_animation = true; + for ( LLVOAvatar::AnimIterator anim_it = gAgentAvatarp->mPlayingAnimations.begin(); anim_it != gAgentAvatarp->mPlayingAnimations.end(); anim_it++) { + // don't restore stand animation when ground sitting because it is not needed + // and an AO would not play a standing animation on top of the ground sit + if (anim_it->first == ANIM_AGENT_SIT_GROUND_CONSTRAINED) + { + restore_stand_animation = false; + } + // + if ((anim_it->first == ANIM_AGENT_DO_NOT_DISTURB)|| (anim_it->first == ANIM_AGENT_SIT_GROUND_CONSTRAINED)) { @@ -5502,7 +5510,14 @@ void LLAgent::stopCurrentAnimations(bool force_keep_script_perms /*= false*/) // re-assert at least the default standing animation, because // viewers get confused by avs with no associated anims. - sendAnimationRequest(ANIM_AGENT_STAND, ANIM_REQUEST_START); + + // Only restore stand animation when the avatar was not sitting on ground + // sendAnimationRequest(ANIM_AGENT_STAND, ANIM_REQUEST_START); + if (restore_stand_animation) + { + sendAnimationRequest(ANIM_AGENT_STAND, ANIM_REQUEST_START); + } + // // Run Prio 0 default bento pose in the background to fix splayed hands, open mouths, etc. if (gSavedSettings.getBOOL("FSPlayDefaultBentoAnimation")) @@ -5660,27 +5675,31 @@ void LLAgent::requestAgentUserInfoCoro(std::string capurl) return; } - bool im_via_email; - bool is_verified_email; std::string email; std::string dir_visibility; - im_via_email = result["im_via_email"].asBoolean(); - is_verified_email = result["is_verified"].asBoolean(); + // Keep this for OpenSim + bool im_via_email = false; + if (!LLGridManager::instance().isInSecondLife()) + { + im_via_email = result["im_via_email"].asBoolean(); + } + // email = result["email"].asString(); dir_visibility = result["directory_visibility"].asString(); // TODO: This should probably be changed. I'm not entirely comfortable // having LLAgent interact directly with the UI in this way. - // Show email address in preferences (FIRE-1071) - //LLFloaterPreference::updateUserInfo(dir_visibility, im_via_email, is_verified_email); - LLFloaterPreference::updateUserInfo(dir_visibility, im_via_email, is_verified_email, email); + // Show email address in preferences (FIRE-1071) and keep IM to email setting for OpenSim + //LLFloaterPreference::updateUserInfo(dir_visibility); + LLFloaterPreference::updateUserInfo(dir_visibility, im_via_email, email); // LLFloaterSnapshot::setAgentEmail(email); } -void LLAgent::sendAgentUpdateUserInfo(bool im_via_email, const std::string& directory_visibility) -{ +// Keep this for OpenSim +//void LLAgent::sendAgentUpdateUserInfo(const std::string& directory_visibility) +void LLAgent::sendAgentUpdateUserInfo(bool im_via_email, const std::string& directory_visibility){ std::string cap; if (getID().isNull()) @@ -5692,15 +5711,21 @@ void LLAgent::sendAgentUpdateUserInfo(bool im_via_email, const std::string& dire if (!cap.empty()) { LLCoros::instance().launch("updateAgentUserInfoCoro", + // Keep this for OpenSim + //boost::bind(&LLAgent::updateAgentUserInfoCoro, this, cap, directory_visibility)); boost::bind(&LLAgent::updateAgentUserInfoCoro, this, cap, im_via_email, directory_visibility)); } else { + // Keep this for OpenSim + //sendAgentUpdateUserInfoMessage(directory_visibility); sendAgentUpdateUserInfoMessage(im_via_email, directory_visibility); } } +// Keep this for OpenSim +//void LLAgent::updateAgentUserInfoCoro(std::string capurl, std::string directory_visibility) void LLAgent::updateAgentUserInfoCoro(std::string capurl, bool im_via_email, std::string directory_visibility) { LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); @@ -5712,8 +5737,11 @@ void LLAgent::updateAgentUserInfoCoro(std::string capurl, bool im_via_email, std httpOpts->setFollowRedirects(true); LLSD body(LLSDMap - ("dir_visibility", LLSD::String(directory_visibility)) - ("im_via_email", LLSD::Boolean(im_via_email))); + ("dir_visibility", LLSD::String(directory_visibility))); + + // Keep this for OpenSim + if (!LLGridManager::instance().isInSecondLife()) + body.insert("im_via_email", LLSD::Boolean(im_via_email)); LLSD result = httpAdapter->postAndSuspend(httpRequest, capurl, body, httpOpts, httpHeaders); @@ -5741,6 +5769,8 @@ void LLAgent::sendAgentUserInfoRequestMessage() sendReliableMessage(); } +// Keep this for OpenSim +//void LLAgent::sendAgentUpdateUserInfoMessage(const std::string& directory_visibility) void LLAgent::sendAgentUpdateUserInfoMessage(bool im_via_email, const std::string& directory_visibility) { gMessageSystem->newMessageFast(_PREHASH_UpdateUserInfo); @@ -5748,7 +5778,10 @@ void LLAgent::sendAgentUpdateUserInfoMessage(bool im_via_email, const std::strin gMessageSystem->addUUIDFast(_PREHASH_AgentID, getID()); gMessageSystem->addUUIDFast(_PREHASH_SessionID, getSessionID()); gMessageSystem->nextBlockFast(_PREHASH_UserData); - gMessageSystem->addBOOLFast(_PREHASH_IMViaEMail, im_via_email); + // Keep this for OpenSim + if (!LLGridManager::instance().isInSecondLife()) + gMessageSystem->addBOOLFast(_PREHASH_IMViaEMail, im_via_email); + // gMessageSystem->addString("DirectoryVisibility", directory_visibility); gAgent.sendReliableMessage(); diff --git a/indra/newview/llagent.h b/indra/newview/llagent.h index 839fb68eaa..27c73e32dc 100644 --- a/indra/newview/llagent.h +++ b/indra/newview/llagent.h @@ -1036,6 +1036,8 @@ public: void sendAgentUserInfoRequest(); // IM to Email and Online visibility + // Keep this for OpenSim + //void sendAgentUpdateUserInfo(const std::string& directory_visibility); void sendAgentUpdateUserInfo(bool im_to_email, const std::string& directory_visibility); // [Legacy Bake] void dumpSentAppearance(const std::string& dump_prefix); @@ -1044,9 +1046,13 @@ public: private: void requestAgentUserInfoCoro(std::string capurl); + // Keep this for OpenSim + //void updateAgentUserInfoCoro(std::string capurl, std::string directory_visibility); void updateAgentUserInfoCoro(std::string capurl, bool im_via_email, std::string directory_visibility); // DEPRECATED: may be removed when User Info cap propagates void sendAgentUserInfoRequestMessage(); + // Keep this for OpenSim + //void sendAgentUpdateUserInfoMessage(const std::string& directory_visibility); void sendAgentUpdateUserInfoMessage(bool im_via_email, const std::string& directory_visibility); //-------------------------------------------------------------------- diff --git a/indra/newview/llagentwearables.cpp b/indra/newview/llagentwearables.cpp index f09198699d..c4e3593e7f 100644 --- a/indra/newview/llagentwearables.cpp +++ b/indra/newview/llagentwearables.cpp @@ -1179,13 +1179,14 @@ void LLAgentWearables::setWearableOutfit(const LLInventoryItem::item_array_t& it } // updating inventory + LLWearableType* wearable_type_inst = LLWearableType::getInstance(); // TODO: Removed check for ensuring that teens don't remove undershirt and underwear. Handle later // note: shirt is the first non-body part wearable item. Update if wearable order changes. // This loop should remove all clothing, but not any body parts for (S32 j = 0; j < (S32)LLWearableType::WT_COUNT; j++) { - if (LLWearableType::getAssetType((LLWearableType::EType)j) == LLAssetType::AT_CLOTHING) + if (wearable_type_inst->getAssetType((LLWearableType::EType)j) == LLAssetType::AT_CLOTHING) { removeWearable((LLWearableType::EType)j, true, 0); } @@ -1205,7 +1206,7 @@ void LLAgentWearables::setWearableOutfit(const LLInventoryItem::item_array_t& it new_wearable->setName(new_item->getName()); new_wearable->setItemID(new_item->getUUID()); - if (LLWearableType::getAssetType(type) == LLAssetType::AT_BODYPART) + if (wearable_type_inst->getAssetType(type) == LLAssetType::AT_BODYPART) { // exactly one wearable per body part setWearable(type,0,new_wearable); @@ -1304,7 +1305,7 @@ void LLAgentWearables::setWearableOutfit(const LLInventoryItem::item_array_t& it // if ((old_wearable->getAssetID() == new_wearable->getAssetID()) && // (old_item_id == new_item->getUUID())) // { -// LL_DEBUGS() << "No change to wearable asset and item: " << LLWearableType::getTypeName(type) << LL_ENDL; +// LL_DEBUGS() << "No change to wearable asset and item: " << LLWearableType::getInstance()->getTypeName(type) << LL_ENDL; // return; // } // @@ -1767,7 +1768,7 @@ void LLAgentWearables::editWearable(const LLUUID& item_id) return; } - const BOOL disable_camera_switch = LLWearableType::getDisableCameraSwitch(wearable->getType()); + const BOOL disable_camera_switch = LLWearableType::getInstance()->getDisableCameraSwitch(wearable->getType()); LLPanel* panel = LLFloaterSidePanelContainer::getPanel("appearance"); LLSidepanelAppearance::editWearable(wearable, panel, disable_camera_switch); } @@ -1905,11 +1906,11 @@ void LLAgentWearables::sendAgentWearablesUpdate() } else { - //LL_INFOS() << "Not wearing wearable type " << LLWearableType::getTypeName((LLWearableType::EType)i) << LL_ENDL; + //LL_INFOS() << "Not wearing wearable type " << LLWearableType::getInstance()->getTypeName((LLWearableType::EType)i) << LL_ENDL; gMessageSystem->addUUIDFast(_PREHASH_ItemID, LLUUID::null); } - LL_DEBUGS() << " " << LLWearableType::getTypeLabel((LLWearableType::EType)type) << ": " << (wearable ? wearable->getAssetID() : LLUUID::null) << LL_ENDL; + LL_DEBUGS() << " " << LLWearableType::getInstance()->getTypeLabel((LLWearableType::EType)type) << ": " << (wearable ? wearable->getAssetID() : LLUUID::null) << LL_ENDL; } gAgent.sendReliableMessage(); } @@ -2007,7 +2008,7 @@ void LLAgentWearables::processAgentInitialWearablesUpdate(LLMessageSystem* mesgs } else { - LLAssetType::EType asset_type = LLWearableType::getAssetType(type); + LLAssetType::EType asset_type = LLWearableType::getInstance()->getAssetType(type); if (asset_type == LLAssetType::AT_NONE) { continue; @@ -2020,7 +2021,7 @@ void LLAgentWearables::processAgentInitialWearablesUpdate(LLMessageSystem* mesgs outfit->add(wearable_data); } - LL_DEBUGS() << " " << LLWearableType::getTypeLabel(type) << LL_ENDL; + LL_DEBUGS() << " " << LLWearableType::getInstance()->getTypeLabel(type) << LL_ENDL; } // Get the complete information on the items in the inventory and set up an observer @@ -2048,7 +2049,7 @@ void LLAgentWearables::recoverMissingWearable(const LLWearableType::EType type, { // Try to recover by replacing missing wearable with a new one. LLNotificationsUtil::add("ReplacedMissingWearable"); - LL_DEBUGS() << "Wearable " << LLWearableType::getTypeLabel(type) << " could not be downloaded. Replaced inventory item with default wearable." << LL_ENDL; + LL_DEBUGS() << "Wearable " << LLWearableType::getInstance()->getTypeLabel(type) << " could not be downloaded. Replaced inventory item with default wearable." << LL_ENDL; LLViewerWearable* new_wearable = LLWearableList::instance().createNewWearable(type, gAgentAvatarp); setWearable(type,index,new_wearable); diff --git a/indra/newview/llappcorehttp.cpp b/indra/newview/llappcorehttp.cpp index 407115480c..551e480e7e 100644 --- a/indra/newview/llappcorehttp.cpp +++ b/indra/newview/llappcorehttp.cpp @@ -282,20 +282,13 @@ void LLAppCoreHttp::init() << LL_ENDL; } - // Signal for global pipelining preference from settings + // Global pipelining setting static const std::string http_pipelining("HttpPipelining"); if (gSavedSettings.controlExists(http_pipelining)) { - LLPointer cntrl_ptr = gSavedSettings.getControl(http_pipelining); - if (cntrl_ptr.isNull()) - { - LL_WARNS("Init") << "Unable to set signal on global setting '" << http_pipelining - << "'" << LL_ENDL; - } - else - { - mPipelinedSignal = cntrl_ptr->getCommitSignal()->connect(boost::bind(&setting_changed)); - } + // Default to true (in ctor) if absent. + mPipelined = gSavedSettings.getBOOL(http_pipelining); + LL_INFOS("Init") << "HTTP Pipelining " << (mPipelined ? "enabled" : "disabled") << "!" << LL_ENDL; } // Register signals for settings and state changes @@ -409,21 +402,6 @@ void LLAppCoreHttp::refreshSettings(bool initial) { LLCore::HttpStatus status; - // Global pipelining setting - bool pipeline_changed(false); - static const std::string http_pipelining("HttpPipelining"); - if (gSavedSettings.controlExists(http_pipelining)) - { - // Default to true (in ctor) if absent. - bool pipelined(gSavedSettings.getBOOL(http_pipelining)); - if (pipelined != mPipelined) - { - mPipelined = pipelined; - pipeline_changed = true; - } - LL_INFOS("Init") << "HTTP Pipelining " << (mPipelined ? "enabled" : "disabled") << "!" << LL_ENDL; - } - for (int i(0); i < LL_ARRAY_SIZE(init_data); ++i) { const EAppPolicy app_policy(static_cast(i)); @@ -452,7 +430,7 @@ void LLAppCoreHttp::refreshSettings(bool initial) // Init- or run-time settings. Must use the queued request API. // Pipelining changes - if (initial || pipeline_changed) + if (initial) { const bool to_pipeline(mPipelined && init_data[i].mPipelined); if (to_pipeline != mHttpClasses[app_policy].mPipelined) @@ -495,7 +473,7 @@ void LLAppCoreHttp::refreshSettings(bool initial) } } - if (initial || setting != mHttpClasses[app_policy].mConnLimit || pipeline_changed) + if (initial || setting != mHttpClasses[app_policy].mConnLimit) { // Set it and report. Strategies depend on pipelining: // diff --git a/indra/newview/llappdelegate-objc.mm b/indra/newview/llappdelegate-objc.mm index 40357123a2..aa801d6ae6 100644 --- a/indra/newview/llappdelegate-objc.mm +++ b/indra/newview/llappdelegate-objc.mm @@ -304,6 +304,12 @@ struct AttachmentInfo //}; std::vector info{}; + //secondLogPath = metadata.secondLogFilePathname; + //if(!secondLogPath.empty()) + //{ + // info.push_back(AttachmentInfo(secondLogPath, "text/xml")); + //} + // We "happen to know" that info[0].basename is "SecondLife.old" -- due to // the fact that BugsplatMac only notices a crash during the viewer run // following the crash. @@ -342,6 +348,12 @@ struct AttachmentInfo - (void)bugsplatStartupManagerDidFinishSendingCrashReport:(BugsplatStartupManager *)bugsplatStartupManager { infos("Sent crash report to BugSplat"); + + if(!secondLogPath.empty()) + { + boost::filesystem::remove(secondLogPath); + } + clearDumpLogsDir(); } - (void)bugsplatStartupManager:(BugsplatStartupManager *)bugsplatStartupManager didFailWithError:(NSError *)error diff --git a/indra/newview/llappearancemgr.cpp b/indra/newview/llappearancemgr.cpp index 14035289fe..1c4a43860d 100644 --- a/indra/newview/llappearancemgr.cpp +++ b/indra/newview/llappearancemgr.cpp @@ -977,7 +977,7 @@ void recovered_item_link_cb(const LLUUID& item_id, LLWearableType::EType type, L // runway skip here? } - LL_INFOS() << "HP " << holder->index() << " recovered item link for type " << type << LL_ENDL; + LL_INFOS("Avatar") << "HP " << holder->index() << " recovered item link for type " << type << LL_ENDL; holder->eraseTypeToLink(type); // Add wearable to FoundData for actual wearing LLViewerInventoryItem *item = gInventory.getItem(item_id); @@ -1046,8 +1046,8 @@ void LLWearableHoldingPattern::recoverMissingWearable(LLWearableType::EType type // Try to recover by replacing missing wearable with a new one. LLNotificationsUtil::add("ReplacedMissingWearable"); - LL_DEBUGS() << "Wearable " << LLWearableType::getTypeLabel(type) - << " could not be downloaded. Replaced inventory item with default wearable." << LL_ENDL; + LL_DEBUGS("Avatar") << "Wearable of type '" << LLWearableType::getInstance()->getTypeName(type) + << "' could not be downloaded. Replaced inventory item with default wearable." << LL_ENDL; LLViewerWearable* wearable = LLWearableList::instance().createNewWearable(type, gAgentAvatarp); // Add a new one in the lost and found folder. @@ -2162,7 +2162,7 @@ void LLAppearanceMgr::filterWearableItems( continue; // S32 start_index = llmax(0,size-max_per_type); // [SL:KB] - Patch: Appearance-Misc | Checked: 2010-05-11 (Catznip-2.0) - S32 start_index = llmax(0, size - ((LLWearableType::getAllowMultiwear((LLWearableType::EType)i)) ? max_per_type : 1)); + S32 start_index = llmax(0, size - ((LLWearableType::getInstance()->getAllowMultiwear((LLWearableType::EType)i)) ? max_per_type : 1)); // [/SL:KB[ for (S32 j = start_index; j Tracy profiler support +#include "fsperfstats.h" // performance stats support #if LL_LINUX && LL_GTK #include "glib.h" @@ -675,13 +676,13 @@ static void settings_to_globals() static void settings_modify() { -// LLRenderTarget::sUseFBO = gSavedSettings.getBOOL("RenderDeferred"); -// [RLVa:KB] - @setsphere - LLRenderTarget::sUseFBO = gSavedSettings.getBOOL("RenderDeferred") || (gSavedSettings.getBOOL("WindLightUseAtmosShaders") && LLPipeline::sUseDepthTexture); -// [/RLVa:KB] LLPipeline::sRenderTransparentWater = gSavedSettings.getBOOL("RenderTransparentWater"); LLPipeline::sRenderBump = gSavedSettings.getBOOL("RenderObjectBump"); - LLPipeline::sRenderDeferred = LLPipeline::sRenderTransparentWater && LLPipeline::sRenderBump && gSavedSettings.getBOOL("RenderDeferred"); + LLPipeline::sRenderDeferred = LLPipeline::sRenderTransparentWater && LLPipeline::sRenderBump && gSavedSettings.getBOOL("RenderDeferred"); +// LLRenderTarget::sUseFBO = LLPipeline::sRenderDeferred && gSavedSettings.getBOOL("RenderAvatarVP"); +// [RLVa:KB] - @setsphere + LLRenderTarget::sUseFBO = (LLPipeline::sRenderDeferred && gSavedSettings.getBOOL("RenderAvatarVP")) || (gSavedSettings.getBOOL("WindLightUseAtmosShaders") && LLPipeline::sUseDepthTexture); +// [/RLVa:KB] LLVOSurfacePatch::sLODFactor = gSavedSettings.getF32("RenderTerrainLODFactor"); LLVOSurfacePatch::sLODFactor *= LLVOSurfacePatch::sLODFactor; //square lod factor to get exponential range of [1,4] gDebugGL = gSavedSettings.getBOOL("RenderDebugGL") || gDebugSession; @@ -737,7 +738,7 @@ LLAppViewer* LLAppViewer::sInstance = NULL; LLTextureCache* LLAppViewer::sTextureCache = NULL; LLImageDecodeThread* LLAppViewer::sImageDecodeThread = NULL; LLTextureFetch* LLAppViewer::sTextureFetch = NULL; -FSPurgeDiskCacheThread* LLAppViewer::sPurgeDiskCacheThread = NULL; // Regular disk cache cleanup +LLPurgeDiskCacheThread* LLAppViewer::sPurgeDiskCacheThread = NULL; std::string getRuntime() { @@ -800,8 +801,6 @@ LLAppViewer::LLAppViewer() gLoggedInTime.stop(); - initLoggingAndGetLastDuration(); - processMarkerFiles(); // // OK to write stuff to logs now, we've now crash reported if necessary @@ -822,7 +821,7 @@ LLAppViewer::LLAppViewer() std::string logdir = gDirUtilp->getExpandedFilename(LL_PATH_DUMP, ""); # endif // ! LL_BUGSPLAT mDumpPath = logdir; - setMiniDumpDir(logdir); + setDebugFileNames(logdir); } @@ -858,14 +857,10 @@ bool LLAppViewer::init() // Start of the application // - // Move further down after translation system has been initialized - //// initialize LLWearableType translation bridge. - //// Memory will be cleaned up in ::cleanupClass() - //LLWearableType::initParamSingleton(new LLUITranslationBridge()); - + // Move further down after translation system has been initialized //LLTranslationBridge::ptr_t trans = std::make_shared(); //LLSettingsType::initClass(trans); - // + // // initialize SSE options LLVector4a::initClass(); @@ -968,6 +963,7 @@ bool LLAppViewer::init() // init_default_trans_args(); + // inits from settings.xml and from strings.xml if (!initConfiguration()) return false; @@ -1041,10 +1037,9 @@ bool LLAppViewer::init() // Moved down here translation system has been initialized // initialize LLWearableType translation bridge. - // Memory will be cleaned up in ::cleanupClass() - LLWearableType::initParamSingleton(new LLUITranslationBridge()); - + // Will immediately use LLTranslationBridge to init LLWearableDictionary LLTranslationBridge::ptr_t trans = std::make_shared(); + LLWearableType::initParamSingleton(trans); LLSettingsType::initParamSingleton(trans); // @@ -1300,19 +1295,27 @@ bool LLAppViewer::init() if (count > 0 && v1 <= 10) { LL_INFOS("AppInit") << "Detected obsolete intel driver: " << driver << LL_ENDL; - LLUIString details = LLNotifications::instance().getGlobalString("UnsupportedIntelDriver"); - std::string gpu_name = ll_safe_string((const char *)glGetString(GL_RENDERER)); - details.setArg("[VERSION]", driver); - details.setArg("[GPUNAME]", gpu_name); - S32 button = OSMessageBox(details.getString(), - LLStringUtil::null, - OSMB_YESNO); - if (OSBTN_YES == button && gViewerWindow) + + if (!gViewerWindow->getInitAlert().empty() // graphic initialization crashed on last run + || LLVersionInfo::getInstance()->getChannelAndVersion() != gLastRunVersion // viewer was updated + || mNumSessions % 20 == 0 //periodically remind user to update driver + ) { - std::string url = LLWeb::escapeURL(LLTrans::getString("IntelDriverPage")); - if (gViewerWindow->getWindow()) + LLUIString details = LLNotifications::instance().getGlobalString("UnsupportedIntelDriver"); + std::string gpu_name = ll_safe_string((const char *)glGetString(GL_RENDERER)); + LL_INFOS("AppInit") << "Notifying user about obsolete intel driver for " << gpu_name << LL_ENDL; + details.setArg("[VERSION]", driver); + details.setArg("[GPUNAME]", gpu_name); + S32 button = OSMessageBox(details.getString(), + LLStringUtil::null, + OSMB_YESNO); + if (OSBTN_YES == button && gViewerWindow) { - gViewerWindow->getWindow()->spawnWebBrowser(url, false); + std::string url = LLWeb::escapeURL(LLTrans::getString("IntelDriverPage")); + if (gViewerWindow->getWindow()) + { + gViewerWindow->getWindow()->spawnWebBrowser(url, false); + } } } } @@ -1374,9 +1377,9 @@ bool LLAppViewer::init() gGLActive = FALSE; // Disable updater -//#if LL_RELEASE_FOR_DOWNLOAD -// if (!gSavedSettings.getBOOL("CmdLineSkipUpdater")) -// { +//#if LL_RELEASE_FOR_DOWNLOAD +// if (!gSavedSettings.getBOOL("CmdLineSkipUpdater")) +// { // LLProcess::Params updater; // updater.desc = "updater process"; // // Because it's the updater, it MUST persist beyond the lifespan of the @@ -1540,6 +1543,13 @@ bool LLAppViewer::init() // Load User's bindings loadKeyBindings(); +#if LL_WINDOWS + if (!mSecondInstance) + { + gDirUtilp->deleteDirAndContents(gDirUtilp->getDumpLogsDirPath()); + } +#endif + return true; } @@ -1570,6 +1580,7 @@ void LLAppViewer::initMaxHeapSize() } static LLTrace::BlockTimerStatHandle FTM_MESSAGES("System Messages"); +static LLTrace::BlockTimerStatHandle FTM_MESSAGES2("System Messages2"); static LLTrace::BlockTimerStatHandle FTM_SLEEP("Sleep"); static LLTrace::BlockTimerStatHandle FTM_YIELD("Yield"); @@ -1631,6 +1642,10 @@ bool LLAppViewer::frame() bool LLAppViewer::doFrame() { +// Perfstats collection Frame boundary +{ + FSPerfStats::RecordSceneTime T (FSPerfStats::StatType_t::RENDER_FRAME); + LLEventPump& mainloop(LLEventPumps::instance().obtain("mainloop")); LLSD newFrame; // telemetry enabling. @@ -1665,6 +1680,7 @@ bool LLAppViewer::doFrame() nd::etw::logFrame(); // Write the start of each frame. Even if our Provider (Firestorm) would be enabled, this has only light impact. Does nothing on OSX and Linux. LL_RECORD_BLOCK_TIME(FTM_FRAME); + {FSPerfStats::RecordSceneTime T (FSPerfStats::StatType_t::RENDER_IDLE); // perf stats LLTrace::BlockTimer::processTimes(); LLTrace::get_frame_recording().nextPeriod(); LLTrace::BlockTimer::logStats(); @@ -1673,8 +1689,9 @@ bool LLAppViewer::doFrame() //clear call stack records LL_CLEAR_CALLSTACKS(); - + } // perf stats { + {FSPerfStats::RecordSceneTime T (FSPerfStats::StatType_t::RENDER_IDLE); // ensure we have the entire top scope of frame covered // MaxFPS Viewer-Chui merge error // Check if we need to restore rendering masks. if (restore_rendering_masks) @@ -1712,7 +1729,7 @@ bool LLAppViewer::doFrame() if (gViewerWindow) { - LL_RECORD_BLOCK_TIME(FTM_MESSAGES); + LL_RECORD_BLOCK_TIME(FTM_MESSAGES2); if (!restoreErrorTrap()) { LL_WARNS() << " Someone took over my signal/exception handler (post messagehandling)!" << LL_ENDL; @@ -1735,8 +1752,11 @@ bool LLAppViewer::doFrame() // canonical per-frame event mainloop.post(newFrame); // give listeners a chance to run + { + FSZoneN("Main:Coro"); llcoro::suspend(); - + } + }// ensure we have the entire top scope of frame covered if (!LLApp::isExiting()) { pingMainloopTimeout("Main:JoystickKeyboard"); @@ -1752,6 +1772,8 @@ bool LLAppViewer::doFrame() && (gHeadlessClient || !gViewerWindow->getShowProgress()) && !gFocusMgr.focusLocked()) { + FSPerfStats::RecordSceneTime T (FSPerfStats::StatType_t::RENDER_IDLE); + FSZoneN("Main:JoystickKeyboard"); joystick->scanJoystick(); gKeyboard->scanKeyboard(); gViewerInput.scanMouse(); @@ -1767,6 +1789,8 @@ bool LLAppViewer::doFrame() // Update state based on messages, user input, object idle. { + FSPerfStats::RecordSceneTime T (FSPerfStats::StatType_t::RENDER_IDLE); + pauseMainloopTimeout(); // *TODO: Remove. Messages shouldn't be stalling for 20+ seconds! LL_RECORD_BLOCK_TIME(FTM_IDLE); @@ -1777,8 +1801,15 @@ bool LLAppViewer::doFrame() if (gDoDisconnect && (LLStartUp::getStartupState() == STATE_STARTED)) { + FSZoneN("Shutdown:SaveSnapshot"); pauseMainloopTimeout(); saveFinalSnapshot(); + + if (LLVoiceClient::instanceExists()) + { + LLVoiceClient::getInstance()->terminate(); + } + disconnectViewer(); resumeMainloopTimeout(); } @@ -1787,6 +1818,7 @@ bool LLAppViewer::doFrame() // *TODO: Should we run display() even during gHeadlessClient? DK 2011-02-18 if (!LLApp::isExiting() && !gHeadlessClient && gViewerWindow) { + FSZoneN("Main:Display"); pingMainloopTimeout("Main:Display"); gGLActive = TRUE; @@ -1810,8 +1842,12 @@ bool LLAppViewer::doFrame() // pingMainloopTimeout("Main:Snapshot"); + { + FSPerfStats::RecordSceneTime T (FSPerfStats::StatType_t::RENDER_IDLE); + FSZoneN("Main:Snapshot"); LLFloaterSnapshot::update(); // take snapshots LLFloaterOutfitSnapshot::update(); + } gGLActive = FALSE; } } @@ -1845,6 +1881,7 @@ bool LLAppViewer::doFrame() // of equal priority on Windows if (milliseconds_to_sleep > 0) { + FSPerfStats::RecordSceneTime T ( FSPerfStats::StatType_t::RENDER_SLEEP ); ms_sleep(milliseconds_to_sleep); // also pause worker threads during this wait period LLAppViewer::getTextureCache()->pause(); @@ -1922,6 +1959,7 @@ bool LLAppViewer::doFrame() if (fsLimitFramerate && LLStartUp::getStartupState() == STATE_STARTED && !gTeleportDisplay && !logoutRequestSent() && max_fps > F_APPROXIMATELY_ZERO) { // Sleep a while to limit frame rate. + FSPerfStats::RecordSceneTime T ( FSPerfStats::StatType_t::RENDER_FPSLIMIT ); F32 min_frame_time = 1.f / (F32)max_fps; S32 milliseconds_to_sleep = llclamp((S32)((min_frame_time - frameTimer.getElapsedTimeF64()) * 1000.f), 0, 1000); if (milliseconds_to_sleep > 0) @@ -1961,7 +1999,8 @@ bool LLAppViewer::doFrame() } FSFrameMark; // Tracy support delineate Frame LLPROFILE_UPDATE(); - + } + FSPerfStats::StatsRecorder::endFrame(); return ! LLApp::isRunning(); } @@ -2379,7 +2418,9 @@ bool LLAppViewer::cleanup() if (LLConversationLog::instanceExists()) { LLConversationLog::instance().cache(); - } + } + + clearSecHandler(); if (mPurgeCacheOnExit) { @@ -2437,7 +2478,7 @@ bool LLAppViewer::cleanup() sTextureFetch->shutdown(); sTextureCache->shutdown(); sImageDecodeThread->shutdown(); - sPurgeDiskCacheThread->shutdown(); // Regular disk cache cleanup + sPurgeDiskCacheThread->shutdown(); sTextureFetch->shutDownTextureCacheThread() ; sTextureFetch->shutDownImageDecodeThread() ; @@ -2460,10 +2501,8 @@ bool LLAppViewer::cleanup() sImageDecodeThread = NULL; delete mFastTimerLogThread; mFastTimerLogThread = NULL; - // Regular disk cache cleanup delete sPurgeDiskCacheThread; sPurgeDiskCacheThread = NULL; - // if (LLFastTimerView::sAnalyzePerformance) { @@ -2566,7 +2605,7 @@ bool LLAppViewer::initThreads() sImageDecodeThread, enable_threads && true, app_metrics_qa_mode); - LLAppViewer::sPurgeDiskCacheThread = new FSPurgeDiskCacheThread(); // Regular disk cache cleanup + LLAppViewer::sPurgeDiskCacheThread = new LLPurgeDiskCacheThread(); if (LLTrace::BlockTimer::sLog || LLTrace::BlockTimer::sMetricLog) { @@ -2634,78 +2673,90 @@ void errorCallback(LLError::ELevel level, const std::string &error_string) void LLAppViewer::initLoggingAndGetLastDuration() { - // - // Set up logging defaults for the viewer - // - LLError::initForApplication( gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, "") + // + // Set up logging defaults for the viewer + // + LLError::initForApplication( gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, "") ,gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "") ); - LLError::addGenericRecorder(&errorCallback); - //LLError::setTimeFunction(getRuntime); + LLError::addGenericRecorder(&errorCallback); + //LLError::setTimeFunction(getRuntime); - // Remove old CEF log file (defined in dullahan.h) - LLFile::remove(gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "cef_log.txt")); - // Remove the last ".old" log file. - std::string old_log_file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, - APP_NAME + ".old"); - LLFile::remove(old_log_file); + if (mSecondInstance) + { + LLFile::mkdir(gDirUtilp->getDumpLogsDirPath()); + + LLUUID uid; + uid.generate(); + LLError::logToFile(gDirUtilp->getDumpLogsDirPath(uid.asString() + ".log")); + } + else + { + // Remove old CEF log file (defined in dullahan.h) + LLFile::remove(gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "cef_log.txt")); - // Get name of the log file - std::string log_file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, - APP_NAME + ".log"); - /* - * Before touching any log files, compute the duration of the last run - * by comparing the ctime of the previous start marker file with the ctime - * of the last log file. - */ - std::string start_marker_file_name = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, START_MARKER_FILE_NAME); - llstat start_marker_stat; - llstat log_file_stat; - std::ostringstream duration_log_stream; // can't log yet, so save any message for when we can below - int start_stat_result = LLFile::stat(start_marker_file_name, &start_marker_stat); - int log_stat_result = LLFile::stat(log_file, &log_file_stat); - if ( 0 == start_stat_result && 0 == log_stat_result ) - { - int elapsed_seconds = log_file_stat.st_ctime - start_marker_stat.st_ctime; - // only report a last run time if the last viewer was the same version - // because this stat will be counted against this version - if ( markerIsSameVersion(start_marker_file_name) ) - { - gLastExecDuration = elapsed_seconds; - } - else - { - duration_log_stream << "start marker from some other version; duration is not reported"; - gLastExecDuration = -1; - } - } - else - { - // at least one of the LLFile::stat calls failed, so we can't compute the run time - duration_log_stream << "duration stat failure; start: "<< start_stat_result << " log: " << log_stat_result; - gLastExecDuration = -1; // unknown - } - std::string duration_log_msg(duration_log_stream.str()); + // Remove the last ".old" log file. + std::string old_log_file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, + APP_NAME + ".log"); + LLFile::remove(old_log_file); - // Create a new start marker file for comparison with log file time for the next run - LLAPRFile start_marker_file ; - start_marker_file.open(start_marker_file_name, LL_APR_WB); - if (start_marker_file.getFileHandle()) - { - recordMarkerVersion(start_marker_file); - start_marker_file.close(); - } + // Get name of the log file + std::string log_file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, + APP_NAME + ".log"); + /* + * Before touching any log files, compute the duration of the last run + * by comparing the ctime of the previous start marker file with the ctime + * of the last log file. + */ + std::string start_marker_file_name = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, START_MARKER_FILE_NAME); + llstat start_marker_stat; + llstat log_file_stat; + std::ostringstream duration_log_stream; // can't log yet, so save any message for when we can below + int start_stat_result = LLFile::stat(start_marker_file_name, &start_marker_stat); + int log_stat_result = LLFile::stat(log_file, &log_file_stat); + if (0 == start_stat_result && 0 == log_stat_result) + { + int elapsed_seconds = log_file_stat.st_ctime - start_marker_stat.st_ctime; + // only report a last run time if the last viewer was the same version + // because this stat will be counted against this version + if (markerIsSameVersion(start_marker_file_name)) + { + gLastExecDuration = elapsed_seconds; + } + else + { + duration_log_stream << "start marker from some other version; duration is not reported"; + gLastExecDuration = -1; + } + } + else + { + // at least one of the LLFile::stat calls failed, so we can't compute the run time + duration_log_stream << "duration stat failure; start: " << start_stat_result << " log: " << log_stat_result; + gLastExecDuration = -1; // unknown + } + std::string duration_log_msg(duration_log_stream.str()); - // Rename current log file to ".old" - LLFile::rename(log_file, old_log_file); + // Create a new start marker file for comparison with log file time for the next run + LLAPRFile start_marker_file; + start_marker_file.open(start_marker_file_name, LL_APR_WB); + if (start_marker_file.getFileHandle()) + { + recordMarkerVersion(start_marker_file); + start_marker_file.close(); + } - // Set the log file to SecondLife.log - LLError::logToFile(log_file); - if (!duration_log_msg.empty()) - { - LL_WARNS("MarkerFile") << duration_log_msg << LL_ENDL; - } + // Rename current log file to ".old" + LLFile::rename(log_file, old_log_file); + + // Set the log file to SecondLife.log + LLError::logToFile(log_file); + if (!duration_log_msg.empty()) + { + LL_WARNS("MarkerFile") << duration_log_msg << LL_ENDL; + } + } } bool LLAppViewer::loadSettingsFromDirectory(const std::string& location_key, @@ -3659,6 +3710,15 @@ bool LLAppViewer::initWindow() void LLAppViewer::writeDebugInfo(bool isStatic) { +#if LL_WINDOWS && LL_BUGSPLAT + // bugsplat does not create dump folder and debug logs are written directly + // to logs folder, so it conflicts with main instance + if (mSecondInstance) + { + return; + } +#endif + //Try to do the minimum when writing data during a crash. std::string* debug_filename; debug_filename = ( isStatic @@ -4161,7 +4221,7 @@ void LLAppViewer::writeSystemInfo() gDebugInfo["Dynamic"] = LLSD::emptyMap(); // we don't want this (otherwise set filename to Firestorm.old/log -// #if LL_WINDOWS +// #if LL_WINDOWS && !LL_BUGSPLAT // gDebugInfo["SLLog"] = gDirUtilp->getExpandedFilename(LL_PATH_DUMP,"SecondLife.log"); // #else // //Not ideal but sufficient for good reporting. @@ -4530,6 +4590,7 @@ void LLAppViewer::processMarkerFiles() // - Other Crash (SecondLife.error_marker present) // These checks should also remove these files for the last 2 cases if they currently exist + std::ostringstream marker_log_stream; bool marker_is_same_version = true; // first, look for the marker created at startup and deleted on a clean exit mMarkerFileName = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,MARKER_FILE_NAME); @@ -4540,7 +4601,7 @@ void LLAppViewer::processMarkerFiles() marker_is_same_version = markerIsSameVersion(mMarkerFileName); // now test to see if this file is locked by a running process (try to open for write) - LL_DEBUGS("MarkerFile") << "Checking exec marker file for lock..." << LL_ENDL; + marker_log_stream << "Checking exec marker file for lock..."; mMarkerFile.open(mMarkerFileName, LL_APR_WB); // Remove LLVolatileAPRPool/apr_file_t and use FILE* instead //apr_file_t* fMarker = mMarkerFile.getFileHandle() ; @@ -4548,7 +4609,7 @@ void LLAppViewer::processMarkerFiles() // if (!fMarker) { - LL_INFOS("MarkerFile") << "Exec marker file open failed - assume it is locked." << LL_ENDL; + marker_log_stream << "Exec marker file open failed - assume it is locked."; mSecondInstance = true; // lock means that instance is running. } else @@ -4556,7 +4617,7 @@ void LLAppViewer::processMarkerFiles() // We were able to open it, now try to lock it ourselves... if (apr_file_lock(fMarker, APR_FLOCK_NONBLOCK | APR_FLOCK_EXCLUSIVE) != APR_SUCCESS) { - LL_WARNS_ONCE("MarkerFile") << "Locking exec marker failed." << LL_ENDL; + marker_log_stream << "Locking exec marker failed."; mSecondInstance = true; // lost a race? be conservative mMarkerFile.close(); // Cannot lock the file and take ownership. Don't keep it open } @@ -4564,9 +4625,13 @@ void LLAppViewer::processMarkerFiles() { // No other instances; we've locked this file now, so record our version; delete on quit. recordMarkerVersion(mMarkerFile); - LL_DEBUGS("MarkerFile") << "Exec marker file existed but was not locked; rewritten." << LL_ENDL; + marker_log_stream << "Exec marker file existed but was not locked; rewritten."; } } + initLoggingAndGetLastDuration(); + + std::string marker_log_msg(marker_log_stream.str()); + LL_INFOS("MarkerFile") << marker_log_msg << LL_ENDL; if (mSecondInstance) { @@ -4585,6 +4650,7 @@ void LLAppViewer::processMarkerFiles() } else // marker did not exist... last exec (if any) did not freeze { + initLoggingAndGetLastDuration(); // Create the marker file for this execution & lock it; it will be deleted on a clean exit apr_status_t s; s = mMarkerFile.open(mMarkerFileName, LL_APR_WB, TRUE); @@ -4710,8 +4776,18 @@ void LLAppViewer::removeDumpDir() { //Call this routine only on clean exit. Crash reporter will clean up //its locking table for us. - std::string dump_dir = gDirUtilp->getExpandedFilename(LL_PATH_DUMP, ""); - gDirUtilp->deleteDirAndContents(dump_dir); + if (gDirUtilp->dumpDirExists()) // Check if dump dir was created this run + { + std::string dump_dir = gDirUtilp->getExpandedFilename(LL_PATH_DUMP, ""); + gDirUtilp->deleteDirAndContents(dump_dir); + } + + if (mSecondInstance && !isError()) + { + std::string log_filename = LLError::logFileName(); + LLError::logToFile(""); + LLFile::remove(log_filename); + } } void LLAppViewer::forceQuit() @@ -4927,8 +5003,11 @@ void LLAppViewer::migrateCacheDirectory() //static U32 LLAppViewer::getTextureCacheVersion() { - //viewer texture cache version, change if the texture cache format changes. - const U32 TEXTURE_CACHE_VERSION = 8; + // Viewer texture cache version, change if the texture cache format changes. + // 2021-03-10 Bumping up by one to help obviate texture cache issues with + // Simple Cache Viewer - see SL-14985 for more information + //const U32 TEXTURE_CACHE_VERSION = 8; + const U32 TEXTURE_CACHE_VERSION = 9; return TEXTURE_CACHE_VERSION ; } @@ -4961,8 +5040,6 @@ bool LLAppViewer::initCache() //const unsigned int disk_cache_mb = cache_total_size_mb * disk_cache_percent / 100; const unsigned int disk_cache_mb = gSavedSettings.getU32("FSDiskCacheSize"); // - // Fix integer overflow - //const unsigned int disk_cache_bytes = disk_cache_mb * 1024 * 1024; const uintmax_t disk_cache_bytes = disk_cache_mb * 1024ULL * 1024ULL; const bool enable_cache_debug_info = gSavedSettings.getBOOL("EnableDiskCacheDebugInfo"); @@ -5056,7 +5133,6 @@ bool LLAppViewer::initCache() LLDiskCache::getInstance()->purge(); } } - // Regular disk cache cleanup LLAppViewer::getPurgeDiskCacheThread()->start(); // FIRE-13066 @@ -5771,6 +5847,7 @@ void LLAppViewer::idle() if (!(logoutRequestSent() && hasSavedFinalSnapshot())) { + FSPerfStats::tunedAvatars=0; // reset the number of avatars that have been tweaked. gObjectList.update(gAgent); } } diff --git a/indra/newview/llappviewer.h b/indra/newview/llappviewer.h index e42a11d3e4..a32f7a743f 100644 --- a/indra/newview/llappviewer.h +++ b/indra/newview/llappviewer.h @@ -58,8 +58,8 @@ class LLImageDecodeThread; class LLTextureFetch; class LLWatchdogTimeout; class LLViewerJoystick; +class LLPurgeDiskCacheThread; class LLViewerRegion; -class FSPurgeDiskCacheThread; // Regular disk cache cleanup extern LLTrace::BlockTimerStatHandle FTM_FRAME; @@ -111,7 +111,6 @@ public: virtual bool restoreErrorTrap() = 0; // Require platform specific override to reset error handling mechanism. // return false if the error trap needed restoration. - virtual void initCrashReporting(bool reportFreeze = false) = 0; // What to do with crash report? static void handleViewerCrash(); // Hey! The viewer crashed. Do this, soon. void checkForCrash(); @@ -119,7 +118,7 @@ public: static LLTextureCache* getTextureCache() { return sTextureCache; } static LLImageDecodeThread* getImageDecodeThread() { return sImageDecodeThread; } static LLTextureFetch* getTextureFetch() { return sTextureFetch; } - static FSPurgeDiskCacheThread* getPurgeDiskCacheThread() { return sPurgeDiskCacheThread; } // Regular disk cache cleanup + static LLPurgeDiskCacheThread* getPurgeDiskCacheThread() { return sPurgeDiskCacheThread; } static U32 getTextureCacheVersion() ; static U32 getObjectCacheVersion() ; @@ -307,7 +306,7 @@ private: static LLTextureCache* sTextureCache; static LLImageDecodeThread* sImageDecodeThread; static LLTextureFetch* sTextureFetch; - static FSPurgeDiskCacheThread* sPurgeDiskCacheThread; // Regular disk cache cleanup + static LLPurgeDiskCacheThread* sPurgeDiskCacheThread; S32 mNumSessions; diff --git a/indra/newview/llappviewermacosx-for-objc.h b/indra/newview/llappviewermacosx-for-objc.h index 79c3efff91..94bfa2491b 100644 --- a/indra/newview/llappviewermacosx-for-objc.h +++ b/indra/newview/llappviewermacosx-for-objc.h @@ -31,6 +31,7 @@ bool pumpMainLoop(); void handleQuit(); void cleanupViewer(); void infos(const std::string& message); +void clearDumpLogsDir(); // This struct is malleable; it only serves as a way to convey a number of // fields from llappviewermacosx.cpp's CrashMetadata_instance() function to the @@ -47,6 +48,7 @@ struct CrashMetadata std::string agentFullname; std::string regionName; std::string fatalMessage; + std::string secondLogFilePathname; }; CrashMetadata& CrashMetadata_instance(); diff --git a/indra/newview/llappviewermacosx.cpp b/indra/newview/llappviewermacosx.cpp index 42946e4415..cb5cac6f2d 100644 --- a/indra/newview/llappviewermacosx.cpp +++ b/indra/newview/llappviewermacosx.cpp @@ -57,6 +57,7 @@ #include #include "lldir.h" +#include "lldiriterator.h" #include #include // for systemwide mute class LLMediaCtrl; // for LLURLDispatcher @@ -136,6 +137,14 @@ void cleanupViewer() gViewerAppPtr = NULL; } +void clearDumpLogsDir() +{ + if (!LLAppViewer::instance()->isSecondInstance()) + { + gDirUtilp->deleteDirAndContents(gDirUtilp->getDumpLogsDirPath()); + } +} + // The BugsplatMac API is structured as a number of different method // overrides, each returning a different piece of metadata. But since we // obtain such metadata by opening and parsing a file, it seems ridiculous to @@ -190,6 +199,24 @@ CrashMetadataSingleton::CrashMetadataSingleton() LLStringUtil::replaceChar(agentFullname, '_', ' '); regionName = get_metadata(info, "CurrentRegion"); fatalMessage = get_metadata(info, "FatalMessage"); + + if (gDirUtilp->fileExists(gDirUtilp->getDumpLogsDirPath())) + { + LLDirIterator file_iter(gDirUtilp->getDumpLogsDirPath(), "*.log"); + std::string file_name; + bool found = true; + while(found) + { + if((found = file_iter.next(file_name))) + { + std::string log_filename = gDirUtilp->getDumpLogsDirPath(file_name); + if(LLError::logFileName() != log_filename) + { + secondLogFilePathname = log_filename; + } + } + } + } } } @@ -222,14 +249,7 @@ LLAppViewerMacOSX::~LLAppViewerMacOSX() bool LLAppViewerMacOSX::init() { - bool success = LLAppViewer::init(); - - if (success) - { - LLAppViewer* pApp = LLAppViewer::instance(); - pApp->initCrashReporting(); - } - return success; + return LLAppViewer::init(); } // MacOSX may add and addition command line arguement for the process serial number. @@ -347,28 +367,6 @@ bool LLAppViewerMacOSX::restoreErrorTrap() return reset_count == 0; } -void LLAppViewerMacOSX::initCrashReporting(bool reportFreeze) -{ -#if defined LL_BUGSPLAT - LL_DEBUGS("InitOSX", "Bugsplat") << "using BugSplat crash logger" << LL_ENDL; -#elif LL_SEND_CRASH_REPORTS - LL_DEBUGS("InitOSX") << "Initializing legacy crash logger" << LL_ENDL; - std::string command_str = "mac-crash-logger.app"; - - std::stringstream pid_str; - pid_str << LLApp::getPid(); - std::string logdir = gDirUtilp->getExpandedFilename(LL_PATH_DUMP, ""); - std::string appname = gDirUtilp->getExecutableFilename(); - std::string str[] = { "-pid", pid_str.str(), "-dumpdir", logdir, "-procname", appname.c_str() }; - std::vector< std::string > args( str, str + ( sizeof ( str ) / sizeof ( std::string ) ) ); - LL_WARNS() << "about to launch mac-crash-logger" << pid_str.str() - << " " << logdir << " " << appname << LL_ENDL; - launchApplication(&command_str, &args); -#else - LL_DEBUGS("InitOSX") << "No crash logger enabled" << LL_ENDL; -#endif // ! LL_BUGSPLAT -} - std::string LLAppViewerMacOSX::generateSerialNumber() { char serial_md5[MD5HEX_STR_SIZE]; // Flawfinder: ignore diff --git a/indra/newview/llappviewermacosx.h b/indra/newview/llappviewermacosx.h index d5a80864be..b0e325a955 100644 --- a/indra/newview/llappviewermacosx.h +++ b/indra/newview/llappviewermacosx.h @@ -44,7 +44,6 @@ public: protected: virtual bool restoreErrorTrap(); - virtual void initCrashReporting(bool reportFreeze); std::string generateSerialNumber(); virtual bool initParseCommandLine(LLCommandLineParser& clp); diff --git a/indra/newview/llappviewerwin32.cpp b/indra/newview/llappviewerwin32.cpp index 9092edb115..26ebd19f99 100644 --- a/indra/newview/llappviewerwin32.cpp +++ b/indra/newview/llappviewerwin32.cpp @@ -141,24 +141,23 @@ namespace ::CopyFileW(FS::LogfileIn.c_str(), FS::LogfileOut.c_str(), FALSE); // - // send the main viewer log file - // widen to wstring, convert to __wchar_t, then pass c_str() - - // We don't send log files - // sBugSplatSender->sendAdditionalFile( - // WCSTR(gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "SecondLife.log"))); - // + // second instance does not have own log files + if (!LLAppViewer::instance()->isSecondInstance()) + { + // We don't send log files + // sBugSplatSender->sendAdditionalFile( + // WCSTR(LLError::logFileName())); + // + + sBugSplatSender->sendAdditionalFile( + WCSTR(*LLAppViewer::instance()->getStaticDebugFile())); + } // sBugSplatSender->sendAdditionalFile( // WCSTR(gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, "settings.xml"))); - if (gCrashSettings.getBOOL("CrashSubmitSettings")) sBugSplatSender->sendAdditionalFile( WCSTR(gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, "settings.xml"))); - - sBugSplatSender->sendAdditionalFile( - WCSTR(*LLAppViewer::instance()->getStaticDebugFile())); - // We don't have an email address for any user. Hijack this // metadata field for the platform identifier. // sBugSplatSender->setDefaultUserEmail( @@ -774,9 +773,6 @@ bool LLAppViewerWin32::init() #if ! defined(LL_BUGSPLAT) #pragma message("Building without BugSplat") - LLAppViewer* pApp = LLAppViewer::instance(); - pApp->initCrashReporting(); - #else // LL_BUGSPLAT #pragma message("Building with BugSplat") // Pre BugSplat dance, make sure settings are valid, query crash behavior and then set up Bugsplat accordingly" @@ -1065,57 +1061,6 @@ bool LLAppViewerWin32::restoreErrorTrap() return true; // we don't check for handler collisions on windows, so just say they're ok } -void LLAppViewerWin32::initCrashReporting(bool reportFreeze) -{ - if (isSecondInstance()) return; //BUG-5707 do not start another crash reporter for second instance. - - const char* logger_name = "win_crash_logger.exe"; - std::string exe_path = gDirUtilp->getExecutableDir(); - exe_path += gDirUtilp->getDirDelimiter(); - exe_path += logger_name; - - std::string logdir = gDirUtilp->getExpandedFilename(LL_PATH_DUMP, ""); - std::string appname = gDirUtilp->getExecutableFilename(); - - S32 slen = logdir.length() -1; - S32 end = slen; - while (logdir.at(end) == '/' || logdir.at(end) == '\\') end--; - - if (slen !=end) - { - logdir = logdir.substr(0,end+1); - } - //std::string arg_str = "\"" + exe_path + "\" -dumpdir \"" + logdir + "\" -procname \"" + appname + "\" -pid " + stringize(LLApp::getPid()); - //_spawnl(_P_NOWAIT, exe_path.c_str(), arg_str.c_str(), NULL); - std::string arg_str = "\"" + exe_path + "\" -dumpdir \"" + logdir + "\" -procname \"" + appname + "\" -pid " + stringize(LLApp::getPid()); - - STARTUPINFO startInfo={sizeof(startInfo)}; - PROCESS_INFORMATION processInfo; - - std::wstring exe_wstr; - exe_wstr = utf8str_to_utf16str(exe_path); - - std::wstring arg_wstr; - arg_wstr = utf8str_to_utf16str(arg_str); - - LL_INFOS("CrashReport") << "Creating crash reporter process " << exe_path << " with params: " << arg_str << LL_ENDL; - if(CreateProcess(exe_wstr.c_str(), - &arg_wstr[0], // Application arguments - 0, - 0, - FALSE, - CREATE_DEFAULT_ERROR_MODE, - 0, - 0, // Working directory - &startInfo, - &processInfo) == FALSE) - // Could not start application -> call 'GetLastError()' - { - LL_WARNS("CrashReport") << "CreateProcess failed " << GetLastError() << LL_ENDL; - return; - } -} - //virtual bool LLAppViewerWin32::sendURLToOtherInstance(const std::string& url) { diff --git a/indra/newview/llappviewerwin32.h b/indra/newview/llappviewerwin32.h index ca271af7a0..f9fe43b215 100644 --- a/indra/newview/llappviewerwin32.h +++ b/indra/newview/llappviewerwin32.h @@ -51,9 +51,8 @@ protected: bool initHardwareTest() override; // Win32 uses DX9 to test hardware. bool initParseCommandLine(LLCommandLineParser& clp) override; - bool beingDebugged() override; - bool restoreErrorTrap() override; - void initCrashReporting(bool reportFreeze) override; + virtual bool beingDebugged(); + virtual bool restoreErrorTrap(); bool sendURLToOtherInstance(const std::string& url) override; diff --git a/indra/newview/llavatarrendernotifier.cpp b/indra/newview/llavatarrendernotifier.cpp index b608646abd..697f8f8459 100644 --- a/indra/newview/llavatarrendernotifier.cpp +++ b/indra/newview/llavatarrendernotifier.cpp @@ -244,6 +244,12 @@ void LLAvatarRenderNotifier::updateNotificationAgent(U32 agentComplexity) // save the value for use in following messages mLatestAgentComplexity = agentComplexity; + static LLCachedControl show_my_complexity_changes(gSavedSettings, "ShowMyComplexityChanges", 20); + if (!show_my_complexity_changes) + { + return; + } + if (!isAgentAvatarValid() || !gAgentWearables.areWearablesLoaded()) { // data not ready, nothing to show. @@ -291,7 +297,8 @@ static const char* e_hud_messages[] = }; LLHUDRenderNotifier::LLHUDRenderNotifier() : -mReportedHUDWarning(WARN_NONE) +mReportedHUDWarning(WARN_NONE), +mHUDsCount(0) { } @@ -307,6 +314,15 @@ void LLHUDRenderNotifier::updateNotificationHUD(hud_complexity_list_t complexity return; } + mHUDComplexityList = complexity; + mHUDsCount = mHUDComplexityList.size(); + + static LLCachedControl show_my_complexity_changes(gSavedSettings, "ShowMyComplexityChanges", 20); + if (!show_my_complexity_changes) + { + return; + } + // TODO: // Find a way to show message with list of issues, but without making it too large // and intrusive. diff --git a/indra/newview/llavatarrendernotifier.h b/indra/newview/llavatarrendernotifier.h index ec17b3d9e6..658d696458 100644 --- a/indra/newview/llavatarrendernotifier.h +++ b/indra/newview/llavatarrendernotifier.h @@ -30,6 +30,9 @@ #define LL_llavatarrendernotifier_H #include "llnotificationptr.h" +#include "llviewerobject.h" +#include "llhudobject.h" + class LLViewerRegion; @@ -63,6 +66,25 @@ struct LLHUDComplexity typedef std::list hud_complexity_list_t; +struct LLObjectComplexity +{ + LLObjectComplexity() + { + reset(); + } + void reset() + { + objectId = LLUUID::null; + objectName = ""; + objectCost = 0; + } + LLUUID objectId; + std::string objectName; + U32 objectCost; +}; + +typedef std::list object_complexity_list_t; + // Class to notify user about drastic changes in agent's render weights or if other agents // reported that user's agent is too 'heavy' for their settings class LLAvatarRenderNotifier : public LLSingleton @@ -77,6 +99,9 @@ public: void updateNotificationState(); void updateNotificationAgent(U32 agentComplexity); + void setObjectComplexityList(object_complexity_list_t object_list) { mObjectComplexityList = object_list; } + object_complexity_list_t getObjectComplexityList() { return mObjectComplexityList; } + private: LLNotificationPtr mNotificationPtr; @@ -109,6 +134,8 @@ private: // Used to detect changes in voavatar's rezzed status. // If value decreases - there were changes in outfit. S32 mLastOutfitRezStatus; + + object_complexity_list_t mObjectComplexityList; }; // Class to notify user about heavy set of HUD @@ -121,6 +148,9 @@ public: void updateNotificationHUD(hud_complexity_list_t complexity); bool isNotificationVisible(); + hud_complexity_list_t getHUDComplexityList() { return mHUDComplexityList; } + S32 getHUDsCount() { return mHUDsCount; } + private: enum EWarnLevel { @@ -141,6 +171,8 @@ private: EWarnLevel mReportedHUDWarning; LLHUDComplexity mLatestHUDComplexity; LLFrameTimer mHUDPopUpDelayTimer; + hud_complexity_list_t mHUDComplexityList; + S32 mHUDsCount; }; #endif /* ! defined(LL_llavatarrendernotifier_H) */ diff --git a/indra/newview/llcofwearables.cpp b/indra/newview/llcofwearables.cpp index 39f7f9ebd8..0778a0a569 100644 --- a/indra/newview/llcofwearables.cpp +++ b/indra/newview/llcofwearables.cpp @@ -75,7 +75,7 @@ protected: } // Set proper label for the "Create new " menu item. - std::string new_label = LLTrans::getString("create_new_" + LLWearableType::getTypeName(w_type)); + std::string new_label = LLTrans::getString("create_new_" + LLWearableType::getInstance()->getTypeName(w_type)); menu_item->setLabel(new_label); } diff --git a/indra/newview/llcontrolavatar.cpp b/indra/newview/llcontrolavatar.cpp index 8cd0332be9..6cdd30e698 100644 --- a/indra/newview/llcontrolavatar.cpp +++ b/indra/newview/llcontrolavatar.cpp @@ -80,6 +80,7 @@ void LLControlAvatar::initInstance() const LLVOAvatar *LLControlAvatar::getAttachedAvatar() const { + FSZone; if (mRootVolp && mRootVolp->isAttachment()) { return mRootVolp->getAvatarAncestor(); @@ -89,6 +90,7 @@ const LLVOAvatar *LLControlAvatar::getAttachedAvatar() const LLVOAvatar *LLControlAvatar::getAttachedAvatar() { + FSZone; if (mRootVolp && mRootVolp->isAttachment()) { return mRootVolp->getAvatarAncestor(); diff --git a/indra/newview/lldrawpool.cpp b/indra/newview/lldrawpool.cpp index d583a692f9..2ebd699b15 100644 --- a/indra/newview/lldrawpool.cpp +++ b/indra/newview/lldrawpool.cpp @@ -50,6 +50,7 @@ #include "lldrawpoolwlsky.h" #include "llglslshader.h" #include "llglcommonfunc.h" +#include "fsperfstats.h" // performance stats support S32 LLDrawPool::sNumDrawPools = 0; @@ -388,10 +389,21 @@ void LLRenderPass::renderGroup(LLSpatialGroup* group, U32 type, U32 mask, BOOL t { LLSpatialGroup::drawmap_elem_t& draw_info = group->mDrawMap[type]; + std::unique_ptr ratPtr{}; // Perf stats for (LLSpatialGroup::drawmap_elem_t::iterator k = draw_info.begin(); k != draw_info.end(); ++k) { LLDrawInfo *pparams = *k; if (pparams) { + // Capture render times + if(pparams->mFace) + { + LLViewerObject* vobj = pparams->mFace->getViewerObject(); + if(vobj->isAttachment()) + { + trackAttachments( vobj, pparams->mFace->isState(LLFace::RIGGED),&ratPtr); + } + } + // pushBatch(*pparams, mask, texture); } } @@ -404,11 +416,22 @@ void LLRenderPass::renderTexture(U32 type, U32 mask, BOOL batch_textures) void LLRenderPass::pushBatches(U32 type, U32 mask, BOOL texture, BOOL batch_textures) { + std::unique_ptr ratPtr{}; for (LLCullResult::drawinfo_iterator i = gPipeline.beginRenderMap(type); i != gPipeline.endRenderMap(type); ++i) { LLDrawInfo* pparams = *i; if (pparams) { + // Capture render times + if(pparams->mFace) + { + LLViewerObject* vobj = pparams->mFace->getViewerObject(); + if(vobj->isAttachment()) + { + trackAttachments( vobj, pparams->mFace->isState(LLFace::RIGGED),&ratPtr); + } + } + // pushBatch(*pparams, mask, texture, batch_textures); } } @@ -416,11 +439,22 @@ void LLRenderPass::pushBatches(U32 type, U32 mask, BOOL texture, BOOL batch_text void LLRenderPass::pushMaskBatches(U32 type, U32 mask, BOOL texture, BOOL batch_textures) { + std::unique_ptr ratPtr{}; for (LLCullResult::drawinfo_iterator i = gPipeline.beginRenderMap(type); i != gPipeline.endRenderMap(type); ++i) { LLDrawInfo* pparams = *i; if (pparams) { + // Capture render times + if((*pparams).mFace) + { + LLViewerObject* vobj = (*pparams).mFace->getViewerObject(); + if(vobj->isAttachment()) + { + trackAttachments( vobj, (*pparams).mFace->isState(LLFace::RIGGED),&ratPtr); + } + } + // if (LLGLSLShader::sCurBoundShaderPtr) { LLGLSLShader::sCurBoundShaderPtr->setMinimumAlpha(pparams->mAlphaMaskCutoff); diff --git a/indra/newview/lldrawpoolalpha.cpp b/indra/newview/lldrawpoolalpha.cpp index 87bf2cb098..c6ec168cc2 100644 --- a/indra/newview/lldrawpoolalpha.cpp +++ b/indra/newview/lldrawpoolalpha.cpp @@ -48,6 +48,7 @@ #include "lldrawpoolwater.h" #include "llspatialpartition.h" #include "llglcommonfunc.h" +#include "fsperfstats.h" // performance stats support BOOL LLDrawPoolAlpha::sShowDebugAlpha = FALSE; @@ -341,6 +342,7 @@ void LLDrawPoolAlpha::render(S32 pass) void LLDrawPoolAlpha::renderAlphaHighlight(U32 mask) { + FSZone; for (LLCullResult::sg_iterator i = gPipeline.beginAlphaGroups(); i != gPipeline.endAlphaGroups(); ++i) { LLSpatialGroup* group = *i; @@ -349,9 +351,20 @@ void LLDrawPoolAlpha::renderAlphaHighlight(U32 mask) { LLSpatialGroup::drawmap_elem_t& draw_info = group->mDrawMap[LLRenderPass::PASS_ALPHA]; + std::unique_ptr ratPtr{}; // Render time Stats collection for (LLSpatialGroup::drawmap_elem_t::iterator k = draw_info.begin(); k != draw_info.end(); ++k) { LLDrawInfo& params = **k; + // Capture render times + if(params.mFace) + { + LLViewerObject* vobj = (LLViewerObject *)params.mFace->getViewerObject(); + if(vobj->isAttachment()) + { + trackAttachments( vobj, params.mFace->isState(LLFace::RIGGED), &ratPtr ); + } + } + // if (params.mParticle) { @@ -477,6 +490,7 @@ void LLDrawPoolAlpha::RestoreTexSetup(bool tex_setup) void LLDrawPoolAlpha::renderSimples(U32 mask, std::vector& simples) { + FSZone; gPipeline.enableLightsDynamic(); simple_shader->bind(); simple_shader->bindTexture(LLShaderMgr::BUMP_MAP, LLViewerFetchedTexture::sFlatNormalImagep); @@ -485,8 +499,17 @@ void LLDrawPoolAlpha::renderSimples(U32 mask, std::vector& simples) simple_shader->uniform1f(LLShaderMgr::ENVIRONMENT_INTENSITY, 0.0f); simple_shader->uniform1f(LLShaderMgr::EMISSIVE_BRIGHTNESS, 0.0f); bool use_shaders = gPipeline.canUseVertexShaders(); + std::unique_ptr ratPtr{};// Render time Stats collection for (LLDrawInfo* draw : simples) { + // Capture render times + FSZoneN("Simples"); + auto vobj = draw->mFace?draw->mFace->getViewerObject():nullptr; + if(vobj && vobj->isAttachment()) + { + trackAttachments( vobj, draw->mFace->isState(LLFace::RIGGED), &ratPtr ); + } + // bool tex_setup = TexSetup(draw, use_shaders, false, simple_shader); LLGLEnableFunc stencil_test(GL_STENCIL_TEST, draw->mSelected, &LLGLCommonFunc::selected_stencil_test); gGL.blendFunc((LLRender::eBlendFactor) draw->mBlendFuncSrc, (LLRender::eBlendFactor) draw->mBlendFuncDst, mAlphaSFactor, mAlphaDFactor); @@ -503,8 +526,17 @@ void LLDrawPoolAlpha::renderFullbrights(U32 mask, std::vector& full fullbright_shader->bind(); fullbright_shader->uniform1f(LLShaderMgr::EMISSIVE_BRIGHTNESS, 1.0f); bool use_shaders = gPipeline.canUseVertexShaders(); + std::unique_ptr ratPtr{}; // Render time Stats collection for (LLDrawInfo* draw : fullbrights) { + // Capture render times + FSZoneN("Fullbrights"); + auto vobj = draw->mFace?draw->mFace->getViewerObject():nullptr; + if(vobj && vobj->isAttachment()) + { + trackAttachments( vobj, draw->mFace->isState(LLFace::RIGGED), &ratPtr ); + } + // bool tex_setup = TexSetup(draw, use_shaders, false, fullbright_shader); LLGLEnableFunc stencil_test(GL_STENCIL_TEST, draw->mSelected, &LLGLCommonFunc::selected_stencil_test); @@ -518,13 +550,24 @@ void LLDrawPoolAlpha::renderFullbrights(U32 mask, std::vector& full void LLDrawPoolAlpha::renderMaterials(U32 mask, std::vector& materials) { + FSZone;// Tracy markup LLGLSLShader::bindNoShader(); current_shader = NULL; gPipeline.enableLightsDynamic(); bool use_shaders = gPipeline.canUseVertexShaders(); + std::unique_ptr ratPtr{}; // Render time Stats collection for (LLDrawInfo* draw : materials) { + // Capture render times + FSZoneN("Materials"); + auto vobj = draw->mFace?draw->mFace->getViewerObject():nullptr; + if(vobj && vobj->isAttachment()) + { + trackAttachments( vobj, draw->mFace->isState(LLFace::RIGGED), &ratPtr ); + } + // + U32 mask = draw->mShaderMask; llassert(mask < LLMaterial::SHADER_COUNT); @@ -605,8 +648,18 @@ void LLDrawPoolAlpha::renderEmissives(U32 mask, std::vector& emissi // don't touch color, add to alpha (glow) gGL.blendFunc(LLRender::BF_ZERO, LLRender::BF_ONE, LLRender::BF_ONE, LLRender::BF_ONE); bool use_shaders = gPipeline.canUseVertexShaders(); + std::unique_ptr ratPtr{}; // Render time Stats collection for (LLDrawInfo* draw : emissives) { + // Capture render times + FSZoneN("Emissives"); + auto vobj = draw->mFace?draw->mFace->getViewerObject():nullptr; + if(vobj && vobj->isAttachment()) + { + trackAttachments( vobj, draw->mFace->isState(LLFace::RIGGED), &ratPtr ); + } + // + bool tex_setup = TexSetup(draw, use_shaders, false, emissive_shader); drawEmissive(mask, draw); RestoreTexSetup(tex_setup); @@ -664,6 +717,7 @@ void LLDrawPoolAlpha::renderAlpha(U32 mask, S32 pass) LLSpatialGroup::drawmap_elem_t& draw_info = group->mDrawMap[LLRenderPass::PASS_ALPHA]; + std::unique_ptr ratPtr{}; // Render time Stats collection for (LLSpatialGroup::drawmap_elem_t::iterator k = draw_info.begin(); k != draw_info.end(); ++k) { LLDrawInfo& params = **k; @@ -679,6 +733,18 @@ void LLDrawPoolAlpha::renderAlpha(U32 mask, S32 pass) continue; } + // Capture render times + if(params.mFace) + { + LLViewerObject* vobj = (LLViewerObject *)params.mFace->getViewerObject(); + + if(vobj->isAttachment()) + { + trackAttachments( vobj, params.mFace->isState(LLFace::RIGGED), &ratPtr ); + } + } + // + // Fix for bug - NORSPEC-271 // If the face is more than 90% transparent, then don't update the Depth buffer for Dof // We don't want the nearly invisible objects to cause of DoF effects @@ -858,7 +924,9 @@ void LLDrawPoolAlpha::renderAlpha(U32 mask, S32 pass) gGL.matrixMode(LLRender::MM_MODELVIEW); } } - + // performance stats + ratPtr.reset(); // force the final batch to terminate to avoid double counting on the subsidiary batches for FB and Emmissives + // if (batch_fullbrights) { light_enabled = false; diff --git a/indra/newview/lldrawpoolavatar.cpp b/indra/newview/lldrawpoolavatar.cpp index 80d45d6fb3..31d4c3c94e 100644 --- a/indra/newview/lldrawpoolavatar.cpp +++ b/indra/newview/lldrawpoolavatar.cpp @@ -59,6 +59,8 @@ // void drawBoxOutline(const LLVector3& pos,const LLVector3& size); // llspatialpartition.cpp // #include "llnetmap.h" +#include "fsperfstats.h" // performance stats support + static U32 sDataMask = LLDrawPoolAvatar::VERTEX_DATA_MASK; static U32 sBufferUsage = GL_STREAM_DRAW_ARB; @@ -579,13 +581,16 @@ void LLDrawPoolAvatar::renderShadow(S32 pass) { return; } + FSPerfStats::RecordAvatarTime T(avatarp->getID(), FSPerfStats::StatType_t::RENDER_SHADOWS); + LLVOAvatar::AvatarOverallAppearance oa = avatarp->getOverallAppearance(); BOOL impostor = !LLPipeline::sImpostorRender && avatarp->isImpostor(); // plain old impostors are passing through the shadow pipeline // if (oa == LLVOAvatar::AOA_INVISIBLE || // (impostor && oa == LLVOAvatar::AOA_JELLYDOLL)) // Note: Impostors should not cast shadows, also all JDs are impostor nowadays so we do not need the extra check at all. - if (impostor || (oa == LLVOAvatar::AOA_INVISIBLE) ) + // also no shadows if the shadows are causing this avatar to breach the limit. + if ( avatarp->isTooSlowWithShadows() || impostor || (oa == LLVOAvatar::AOA_INVISIBLE) ) // { // No shadows for jellydolled or invisible avs. @@ -1462,6 +1467,7 @@ void LLDrawPoolAvatar::renderAvatars(LLVOAvatar* single_avatar, S32 pass) if (pass == -1) { + FSZoneN("pass -1"); for (S32 i = 1; i < getNumPasses(); i++) { //skip foot shadows prerender(); @@ -1478,7 +1484,7 @@ void LLDrawPoolAvatar::renderAvatars(LLVOAvatar* single_avatar, S32 pass) return; } - LLVOAvatar *avatarp = NULL; + LLVOAvatar *avatarp { nullptr }; if (single_avatar) { @@ -1486,6 +1492,7 @@ void LLDrawPoolAvatar::renderAvatars(LLVOAvatar* single_avatar, S32 pass) } else { + FSZoneN("Find avatarp"); // Tracy markup const LLFace *facep = mDrawFace[0]; if (!facep->getDrawable()) { @@ -1498,11 +1505,16 @@ void LLDrawPoolAvatar::renderAvatars(LLVOAvatar* single_avatar, S32 pass) { return; } + FSPerfStats::RecordAvatarTime T(avatarp->getID(), FSPerfStats::StatType_t::RENDER_GEOMETRY); // Add avatar hitbox debug + { + FSZoneN("cached control renderhitboxes"); static LLCachedControl render_hitbox(gSavedSettings, "DebugRenderHitboxes", false); + if (render_hitbox && pass == 2) { + FSZoneN("render_hitbox"); LLGLSLShader* current_shader_program = NULL; // load the debug output shader @@ -1581,10 +1593,14 @@ void LLDrawPoolAvatar::renderAvatars(LLVOAvatar* single_avatar, S32 pass) } } } - // - + }// +// rendertime Tracy annotations +{ + FSZoneN("check fully_loaded"); +// if (!single_avatar && !avatarp->isFullyLoaded() ) { + FSZoneN("avatar not loaded"); if (pass==0 && (!gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_PARTICLES) || LLViewerPartSim::getMaxPartCount() <= 0)) { // debug code to draw a sphere in place of avatar @@ -1607,9 +1623,14 @@ void LLDrawPoolAvatar::renderAvatars(LLVOAvatar* single_avatar, S32 pass) // don't render please return; } +}// rendertime Tracy annotations BOOL impostor = !LLPipeline::sImpostorRender && avatarp->isImpostor() && !single_avatar; +// rendertime Tracy annotations +{ + FSZoneN("check appearance"); +// if (( /*avatarp->isInMuteList() // Partially undo MAINT-5700: Draw imposter for muted avatars ||*/ impostor || (LLVOAvatar::AOA_NORMAL != avatarp->getOverallAppearance() && !avatarp->needsImpostorUpdate()) ) && pass != 0) @@ -1617,6 +1638,7 @@ void LLDrawPoolAvatar::renderAvatars(LLVOAvatar* single_avatar, S32 pass) { //don't draw anything but the impostor for impostored avatars return; } +}// rendertime Tracy annotations if (pass == 0 && !impostor && LLPipeline::sUnderWaterRender) { //don't draw foot shadows under water @@ -1624,7 +1646,7 @@ void LLDrawPoolAvatar::renderAvatars(LLVOAvatar* single_avatar, S32 pass) } LLVOAvatar *attached_av = avatarp->getAttachedAvatar(); - if (attached_av && LLVOAvatar::AOA_NORMAL != attached_av->getOverallAppearance()) + if (attached_av && (LLVOAvatar::AOA_NORMAL != attached_av->getOverallAppearance() || !gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_AVATAR))) { // Animesh attachment of a jellydolled or invisible parent - don't show return; @@ -1632,6 +1654,7 @@ void LLDrawPoolAvatar::renderAvatars(LLVOAvatar* single_avatar, S32 pass) if (pass == 0) { + FSZoneN("pass 0"); if (!LLPipeline::sReflectionRender) { LLVOAvatar::sNumVisibleAvatars++; @@ -1640,6 +1663,7 @@ void LLDrawPoolAvatar::renderAvatars(LLVOAvatar* single_avatar, S32 pass) // if (impostor || (LLVOAvatar::AV_DO_NOT_RENDER == avatarp->getVisualMuteSettings() && !avatarp->needsImpostorUpdate())) if (impostor || (LLVOAvatar::AOA_NORMAL != avatarp->getOverallAppearance() && !avatarp->needsImpostorUpdate())) { + FSZoneN("render impostor"); if (LLPipeline::sRenderDeferred && !LLPipeline::sReflectionRender && avatarp->mImpostor.isComplete()) { // FIRE-9179: Crash fix @@ -1665,6 +1689,7 @@ void LLDrawPoolAvatar::renderAvatars(LLVOAvatar* single_avatar, S32 pass) if (pass == 1) { + FSZoneN("render rigid meshes (eyeballs)"); // render rigid meshes (eyeballs) first avatarp->renderRigid(); return; @@ -1672,12 +1697,15 @@ void LLDrawPoolAvatar::renderAvatars(LLVOAvatar* single_avatar, S32 pass) if (pass == 3) { + FSZoneN("pass 3"); if (is_deferred_render) { + FSZoneN("deferred rigged simple"); renderDeferredRiggedSimple(avatarp); } else { + FSZoneN("non-deferred rigged"); renderRiggedSimple(avatarp); if (LLPipeline::sRenderDeferred) @@ -1701,12 +1729,15 @@ void LLDrawPoolAvatar::renderAvatars(LLVOAvatar* single_avatar, S32 pass) if (pass == 4) { + FSZoneN("pass 4"); if (is_deferred_render) { + FSZoneN("deferred rigged bump"); renderDeferredRiggedBump(avatarp); } else { + FSZoneN("non-deferred fullbright"); renderRiggedFullbright(avatarp); } @@ -1715,6 +1746,7 @@ void LLDrawPoolAvatar::renderAvatars(LLVOAvatar* single_avatar, S32 pass) if (is_deferred_render && pass >= 5 && pass <= 21) { + FSZoneN("deferred passes 5-21"); S32 p = pass-5; if (p != 1 && @@ -1722,6 +1754,7 @@ void LLDrawPoolAvatar::renderAvatars(LLVOAvatar* single_avatar, S32 pass) p != 9 && p != 13) { + FSZoneN("deferred rigged material"); renderDeferredRiggedMaterial(avatarp, p); } return; @@ -1732,6 +1765,7 @@ void LLDrawPoolAvatar::renderAvatars(LLVOAvatar* single_avatar, S32 pass) if (pass == 5) { + FSZoneN("rigged shiny"); renderRiggedShinySimple(avatarp); return; @@ -1739,6 +1773,7 @@ void LLDrawPoolAvatar::renderAvatars(LLVOAvatar* single_avatar, S32 pass) if (pass == 6) { + FSZoneN("rigged FB shiny"); renderRiggedFullbrightShiny(avatarp); return; } @@ -1747,10 +1782,12 @@ void LLDrawPoolAvatar::renderAvatars(LLVOAvatar* single_avatar, S32 pass) { if (pass == 7) { + FSZoneN("pass 7 rigged Alpha"); renderRiggedAlpha(avatarp); if (LLPipeline::sRenderDeferred && !is_post_deferred_render) { //render transparent materials under water + FSZoneN("rigged Alpha Blend"); LLGLEnable blend(GL_BLEND); gGL.setColorMask(true, true); @@ -1771,6 +1808,7 @@ void LLDrawPoolAvatar::renderAvatars(LLVOAvatar* single_avatar, S32 pass) if (pass == 8) { + FSZoneN("pass 8 rigged FB Alpha"); renderRiggedFullbrightAlpha(avatarp); return; } @@ -1787,6 +1825,7 @@ void LLDrawPoolAvatar::renderAvatars(LLVOAvatar* single_avatar, S32 pass) } { + FSZoneN("post deferred rigged Alpha"); LLGLEnable blend(GL_BLEND); renderDeferredRiggedMaterial(avatarp, p); } @@ -1794,6 +1833,7 @@ void LLDrawPoolAvatar::renderAvatars(LLVOAvatar* single_avatar, S32 pass) } else if (pass == 9) { + FSZoneN("pass 9 - rigged glow"); renderRiggedGlow(avatarp); return; } @@ -1801,6 +1841,7 @@ void LLDrawPoolAvatar::renderAvatars(LLVOAvatar* single_avatar, S32 pass) if (pass == 13) { + FSZoneN("pass 13 - rigged glow"); renderRiggedGlow(avatarp); return; @@ -1808,6 +1849,7 @@ void LLDrawPoolAvatar::renderAvatars(LLVOAvatar* single_avatar, S32 pass) if ((sShaderLevel >= SHADER_LEVEL_CLOTH)) { + FSZoneN("shader level > CLOTH"); LLMatrix4 rot_mat; LLViewerCamera::getInstance()->getMatrixToLocal(rot_mat); LLMatrix4 cfr(OGL_TO_CFR_ROTATION); @@ -1833,6 +1875,7 @@ void LLDrawPoolAvatar::renderAvatars(LLVOAvatar* single_avatar, S32 pass) if( !single_avatar || (avatarp == single_avatar) ) { + FSZoneN("renderSkinned"); avatarp->renderSkinned(); } } @@ -2228,6 +2271,7 @@ void LLDrawPoolAvatar::renderRigged(LLVOAvatar* avatar, U32 type, bool glow) stop_glerror(); + std::unique_ptr ratPtr{};// Perf stats capture for (U32 i = 0; i < mRiggedFace[type].size(); ++i) { LLFace* face = mRiggedFace[type][i]; @@ -2250,7 +2294,14 @@ void LLDrawPoolAvatar::renderRigged(LLVOAvatar* avatar, U32 type, bool glow) { continue; } - + + // Capture render times + if(vobj->isAttachment()) + { + trackAttachments( vobj, true, &ratPtr); + } + // + LLVolume* volume = vobj->getVolume(); S32 te = face->getTEOffset(); @@ -2545,12 +2596,17 @@ static LLTrace::BlockTimerStatHandle FTM_RIGGED_VBO("Rigged VBO"); void LLDrawPoolAvatar::updateRiggedVertexBuffers(LLVOAvatar* avatar) { LL_RECORD_BLOCK_TIME(FTM_RIGGED_VBO); - + // render stats collection + if(!avatar)return; // in theory this never happens...right + FSPerfStats::RecordAvatarTime T( avatar->getID(), ( (LLPipeline::sShadowRender)?FSPerfStats::StatType_t::RENDER_SHADOWS : FSPerfStats::StatType_t::RENDER_GEOMETRY ) ); + // //update rigged vertex buffers for (U32 type = 0; type < NUM_RIGGED_PASSES; ++type) { + std::unique_ptr ratPtr{}; for (U32 i = 0; i < mRiggedFace[type].size(); ++i) { + FSZoneN("updateRiggedVBO"); LLFace* face = mRiggedFace[type][i]; LLDrawable* drawable = face->getDrawable(); if (!drawable) @@ -2564,7 +2620,12 @@ void LLDrawPoolAvatar::updateRiggedVertexBuffers(LLVOAvatar* avatar) { continue; } - + // Capture render times + if(vobj->isAttachment()) + { + trackAttachments( vobj, true, &ratPtr ); + } + // LLVolume* volume = vobj->getVolume(); S32 te = face->getTEOffset(); diff --git a/indra/newview/lldrawpoolbump.cpp b/indra/newview/lldrawpoolbump.cpp index c7cb6567b5..d49c0d95d3 100644 --- a/indra/newview/lldrawpoolbump.cpp +++ b/indra/newview/lldrawpoolbump.cpp @@ -47,6 +47,7 @@ #include "pipeline.h" #include "llspatialpartition.h" #include "llviewershadermgr.h" +#include "fsperfstats.h" // performance stats support //#include "llimagebmp.h" //#include "../tools/imdebug/imdebug.h" @@ -640,13 +641,22 @@ void LLDrawPoolBump::endFullbrightShiny() } void LLDrawPoolBump::renderGroup(LLSpatialGroup* group, U32 type, U32 mask, BOOL texture = TRUE) -{ +{ + FSZone; LLSpatialGroup::drawmap_elem_t& draw_info = group->mDrawMap[type]; + std::unique_ptr ratPtr{}; // render time capture for (LLSpatialGroup::drawmap_elem_t::iterator k = draw_info.begin(); k != draw_info.end(); ++k) { LLDrawInfo& params = **k; + // Capture render times + LLViewerObject* vobj = (LLViewerObject *)params.mFace->getViewerObject(); + if( vobj && vobj->isAttachment() ) + { + trackAttachments( vobj, params.mFace->isState(LLFace::RIGGED), &ratPtr ); + } + // applyModelMatrix(params); if (params.mGroup) @@ -888,10 +898,21 @@ void LLDrawPoolBump::renderDeferred(S32 pass) U32 mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0 | LLVertexBuffer::MAP_TANGENT | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_COLOR; + std::unique_ptr ratPtr{}; // render time capture for (LLCullResult::drawinfo_iterator i = begin; i != end; ++i) { LLDrawInfo& params = **i; - + // Capture render times + if(params.mFace) + { + LLViewerObject* vobj = (LLViewerObject *)params.mFace->getViewerObject(); + + if(vobj && vobj->isAttachment()) + { + trackAttachments( vobj, params.mFace->isState(LLFace::RIGGED), &ratPtr ); + } + } + // gDeferredBumpProgram.setMinimumAlpha(params.mAlphaMaskCutoff); LLDrawPoolBump::bindBumpMap(params, bump_channel); pushBatch(params, mask, TRUE); @@ -1499,9 +1520,21 @@ void LLDrawPoolBump::renderBump(U32 type, U32 mask) LLCullResult::drawinfo_iterator begin = gPipeline.beginRenderMap(type); LLCullResult::drawinfo_iterator end = gPipeline.endRenderMap(type); + std::unique_ptr ratPtr{}; // render time capture for (LLCullResult::drawinfo_iterator i = begin; i != end; ++i) { LLDrawInfo& params = **i; + // Capture render times + if(params.mFace) + { + LLViewerObject* vobj = (LLViewerObject *)params.mFace->getViewerObject(); + + if( vobj && vobj->isAttachment() ) + { + trackAttachments( vobj, params.mFace->isState(LLFace::RIGGED), &ratPtr ); + } + } + // if (LLDrawPoolBump::bindBumpMap(params)) { @@ -1512,6 +1545,7 @@ void LLDrawPoolBump::renderBump(U32 type, U32 mask) void LLDrawPoolBump::pushBatch(LLDrawInfo& params, U32 mask, BOOL texture, BOOL batch_textures) { + FSZone; applyModelMatrix(params); bool tex_setup = false; diff --git a/indra/newview/lldrawpoolmaterials.cpp b/indra/newview/lldrawpoolmaterials.cpp index 05b0c1f1a9..34dbc350b9 100644 --- a/indra/newview/lldrawpoolmaterials.cpp +++ b/indra/newview/lldrawpoolmaterials.cpp @@ -31,6 +31,7 @@ #include "llviewershadermgr.h" #include "pipeline.h" #include "llglcommonfunc.h" +#include "fsperfstats.h" // performance stats support S32 diffuse_channel = -1; @@ -135,10 +136,23 @@ void LLDrawPoolMaterials::renderDeferred(S32 pass) LLCullResult::drawinfo_iterator begin = gPipeline.beginRenderMap(type); LLCullResult::drawinfo_iterator end = gPipeline.endRenderMap(type); + std::unique_ptr ratPtr{}; // render time capture for (LLCullResult::drawinfo_iterator i = begin; i != end; ++i) { LLDrawInfo& params = **i; - + + // Capture render times + if(params.mFace) + { + LLViewerObject* vobj = (LLViewerObject *)params.mFace->getViewerObject(); + + if( vobj && vobj->isAttachment() ) + { + trackAttachments( vobj, params.mFace->isState(LLFace::RIGGED), &ratPtr ); + } + } + // + mShader->uniform4f(LLShaderMgr::SPECULAR_COLOR, params.mSpecColor.mV[0], params.mSpecColor.mV[1], params.mSpecColor.mV[2], params.mSpecColor.mV[3]); mShader->uniform1f(LLShaderMgr::ENVIRONMENT_INTENSITY, params.mEnvIntensity); diff --git a/indra/newview/lldrawpoolsimple.cpp b/indra/newview/lldrawpoolsimple.cpp index f211cf6e27..05ac2fad6a 100644 --- a/indra/newview/lldrawpoolsimple.cpp +++ b/indra/newview/lldrawpoolsimple.cpp @@ -36,6 +36,7 @@ #include "llspatialpartition.h" #include "llviewershadermgr.h" #include "llrender.h" +#include "fsperfstats.h" static LLGLSLShader* simple_shader = NULL; static LLGLSLShader* fullbright_shader = NULL; @@ -224,7 +225,7 @@ void LLDrawPoolSimple::render(S32 pass) LLGLDisable blend(GL_BLEND); { //render simple - LL_RECORD_BLOCK_TIME(FTM_RENDER_SIMPLE); + LL_RECORD_BLOCK_TIME(FTM_RENDER_SIMPLE); gPipeline.enableLightsDynamic(); if (mShaderLevel > 0) diff --git a/indra/newview/lldynamictexture.cpp b/indra/newview/lldynamictexture.cpp index 86c598f70a..8761524e89 100644 --- a/indra/newview/lldynamictexture.cpp +++ b/indra/newview/lldynamictexture.cpp @@ -228,12 +228,15 @@ BOOL LLViewerDynamicTexture::updateAllInstances() BOOL ret = FALSE ; for( S32 order = 0; order < ORDER_COUNT; order++ ) { + FSZone; for (instance_list_t::iterator iter = LLViewerDynamicTexture::sInstances[order].begin(); iter != LLViewerDynamicTexture::sInstances[order].end(); ++iter) { + FSZone; LLViewerDynamicTexture *dynamicTexture = *iter; if (dynamicTexture->needsRender()) - { + { + FSZoneN("needsRender"); glClear(GL_DEPTH_BUFFER_BIT); gDepthDirty = TRUE; @@ -241,13 +244,19 @@ BOOL LLViewerDynamicTexture::updateAllInstances() dynamicTexture->setBoundTarget(use_fbo ? &gPipeline.mBake : nullptr); dynamicTexture->preRender(); // Must be called outside of startRender() result = FALSE; + { + FSZoneN("DynTexture->render"); if (dynamicTexture->render()) { ret = TRUE ; result = TRUE; sNumRenders++; } + } + { + FSZoneN("flush"); gGL.flush(); + } LLVertexBuffer::unbind(); dynamicTexture->setBoundTarget(nullptr); dynamicTexture->postRender(result); diff --git a/indra/newview/llenvironment.cpp b/indra/newview/llenvironment.cpp index 991fb813bb..c9f37fa924 100644 --- a/indra/newview/llenvironment.cpp +++ b/indra/newview/llenvironment.cpp @@ -2209,7 +2209,15 @@ void LLEnvironment::coroUpdateEnvironment(S32 parcel_id, S32 track_no, UpdateInf LL_WARNS("ENVIRONMENT") << "Couldn't update Windlight settings for " << ((parcel_id == INVALID_PARCEL_ID) ? ("region!") : ("parcel!")) << LL_ENDL; notify = LLSD::emptyMap(); - notify["FAIL_REASON"] = result["message"].asString(); + std::string reason = result["message"].asString(); + if (reason.empty()) + { + notify["FAIL_REASON"] = status.toString(); + } + else + { + notify["FAIL_REASON"] = reason; + } } else if (LLApp::isExiting()) { @@ -2275,7 +2283,15 @@ void LLEnvironment::coroResetEnvironment(S32 parcel_id, S32 track_no, environmen LL_WARNS("ENVIRONMENT") << "Couldn't reset Windlight settings in " << ((parcel_id == INVALID_PARCEL_ID) ? ("region!") : ("parcel!")) << LL_ENDL; notify = LLSD::emptyMap(); - notify["FAIL_REASON"] = result["message"].asString(); + std::string reason = result["message"].asString(); + if (reason.empty()) + { + notify["FAIL_REASON"] = status.toString(); + } + else + { + notify["FAIL_REASON"] = reason; + } } else if (LLApp::isExiting()) { diff --git a/indra/newview/lleventpoll.cpp b/indra/newview/lleventpoll.cpp index bb2aa7d248..d5f15c9f6c 100644 --- a/indra/newview/lleventpoll.cpp +++ b/indra/newview/lleventpoll.cpp @@ -50,7 +50,7 @@ namespace LLEventPolling namespace Details { - class LLEventPollImpl: public boost::enable_shared_from_this + class LLEventPollImpl: public std::enable_shared_from_this { public: LLEventPollImpl(const LLHost &sender); @@ -320,7 +320,7 @@ namespace Details LLEventPoll::LLEventPoll(const std::string& poll_url, const LLHost& sender): mImpl() { - mImpl = boost::make_shared(sender); + mImpl = std::make_shared(sender); mImpl->start(poll_url); } diff --git a/indra/newview/lleventpoll.h b/indra/newview/lleventpoll.h index 65766dbb2a..d6da04b281 100644 --- a/indra/newview/lleventpoll.h +++ b/indra/newview/lleventpoll.h @@ -51,7 +51,7 @@ public: private: - boost::shared_ptr mImpl; + std::shared_ptr mImpl; }; diff --git a/indra/newview/llface.cpp b/indra/newview/llface.cpp index 316951c316..c28fbfc369 100644 --- a/indra/newview/llface.cpp +++ b/indra/newview/llface.cpp @@ -59,6 +59,7 @@ // [RLVa:KB] - Checked: RLVa-2.0.0 #include "rlvhandler.h" // [/RLVa:KB] +#include "fsperfstats.h" // performance stats support #if LL_LINUX // Work-around spurious used before init warning on Vector4a @@ -642,6 +643,13 @@ void renderFace(LLDrawable* drawable, LLFace *face) LLVOVolume* vobj = drawable->getVOVolume(); if (vobj) { + // Placeholder - This function emits drawcalls but is only used in one place and not useful for stats. + // TODO(Beq) if we need this consider moving it to llSelectMgr loop instead to reduce overhead. + // std::unique_ptr ratPtr{}; + // if(vobj->isAttachment()) + // { + // trackAttachments(vobj, LLPipeline::sShadowRender, &ratPtr); + // } LLVolume* volume = NULL; if (drawable->isState(LLDrawable::RIGGED)) @@ -1240,6 +1248,11 @@ bool LLFace::canRenderAsMask() { return false; } + + // shortcircuit fully alpha faces + if(getViewerObject()->isHUDAttachment()){return false;}; + if(te->getAlpha() == 0.0f && (te->getGlow() == 0.f)){FSZoneN("beqshortcircuit invisible");return true;} + // LLMaterial* mat = te->getMaterialParams(); if (mat && mat->getDiffuseAlphaMode() == LLMaterial::DIFFUSE_ALPHA_MODE_BLEND) diff --git a/indra/newview/llfavoritesbar.cpp b/indra/newview/llfavoritesbar.cpp index 4a3f7192aa..c9d29e1a76 100644 --- a/indra/newview/llfavoritesbar.cpp +++ b/indra/newview/llfavoritesbar.cpp @@ -829,8 +829,12 @@ void LLFavoritesBarCtrl::changed(U32 mask) //virtual void LLFavoritesBarCtrl::reshape(S32 width, S32 height, BOOL called_from_parent) { + S32 delta_width = width - getRect().getWidth(); + S32 delta_height = height - getRect().getHeight(); + + bool force_update = delta_width || delta_height || sForceReshape; LLUICtrl::reshape(width, height, called_from_parent); - updateButtons(); + updateButtons(force_update); } void LLFavoritesBarCtrl::draw() @@ -893,8 +897,13 @@ const LLButton::Params& LLFavoritesBarCtrl::getButtonParams() return button_params; } -void LLFavoritesBarCtrl::updateButtons() +void LLFavoritesBarCtrl::updateButtons(bool force_update) { + if (LLApp::isExiting()) + { + return; + } + mItems.clear(); if (!collectFavoriteItems(mItems)) @@ -925,31 +934,29 @@ void LLFavoritesBarCtrl::updateButtons() const child_list_t* childs = getChildList(); child_list_const_iter_t child_it = childs->begin(); int first_changed_item_index = 0; - // Allow V3 and FS style favorites bar - //int rightest_point = getRect().mRight - mMoreTextBox->getRect().getWidth(); - int rightest_point = getRect().mRight - mMoreCtrl->getRect().getWidth(); - // - //lets find first changed button - while (child_it != childs->end() && first_changed_item_index < mItems.size()) - { - LLFavoriteLandmarkButton* button = dynamic_cast (*child_it); - if (button) - { - const LLViewerInventoryItem *item = mItems[first_changed_item_index].get(); - if (item) - { - // an child's order and mItems should be same - if (button->getLandmarkId() != item->getUUID() // sort order has been changed - || button->getLabelSelected() != item->getName() // favorite's name has been changed - || button->getRect().mRight < rightest_point) // favbar's width has been changed - { - break; - } - } - first_changed_item_index++; - } - child_it++; - } + if (!force_update) + { + //lets find first changed button + while (child_it != childs->end() && first_changed_item_index < mItems.size()) + { + LLFavoriteLandmarkButton* button = dynamic_cast (*child_it); + if (button) + { + const LLViewerInventoryItem *item = mItems[first_changed_item_index].get(); + if (item) + { + // an child's order and mItems should be same + if (button->getLandmarkId() != item->getUUID() // sort order has been changed + || button->getLabelSelected() != item->getName()) // favorite's name has been changed + { + break; + } + } + first_changed_item_index++; + } + child_it++; + } + } // now first_changed_item_index should contains a number of button that need to change if (first_changed_item_index <= mItems.size()) diff --git a/indra/newview/llfavoritesbar.h b/indra/newview/llfavoritesbar.h index 93b8b8714f..9046110428 100644 --- a/indra/newview/llfavoritesbar.h +++ b/indra/newview/llfavoritesbar.h @@ -78,7 +78,7 @@ public: void setLandingTab(LLUICtrl* tab) { mLandingTab = tab; } protected: - void updateButtons(); + void updateButtons(bool force_update = false); LLButton* createButton(const LLPointer item, const LLButton::Params& button_params, S32 x_offset ); const LLButton::Params& getButtonParams(); BOOL collectFavoriteItems(LLInventoryModel::item_array_t &items); diff --git a/indra/newview/llfloater360capture.cpp b/indra/newview/llfloater360capture.cpp new file mode 100644 index 0000000000..4d9935c74d --- /dev/null +++ b/indra/newview/llfloater360capture.cpp @@ -0,0 +1,933 @@ +/** + * @file llfloater360capture.cpp + * @author Callum Prentice (callum@lindenlab.com) + * @brief Floater code for the 360 Capture feature + * + * $LicenseInfo:firstyear=2011&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2011, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" + +#include "llfloater360capture.h" + +#include "llagent.h" +#include "llagentui.h" +#include "llbase64.h" +#include "llcallbacklist.h" +#include "llenvironment.h" +#include "llimagejpeg.h" +#include "llmediactrl.h" +#include "llradiogroup.h" +#include "llslurl.h" +#include "lltextbox.h" +#include "lltrans.h" +#include "lluictrlfactory.h" +#include "llversioninfo.h" +#include "llviewercamera.h" +#include "llviewercontrol.h" +#include "llviewerpartsim.h" +#include "llviewerregion.h" +#include "llviewerwindow.h" +#include "pipeline.h" + +#include + +LLFloater360Capture::LLFloater360Capture(const LLSD& key) + : LLFloater(key) +{ + // The handle to embedded browser that we use to + // render the WebGL preview as we as host the + // Cube Map to Equirectangular image code + mWebBrowser = nullptr; + + // Ask the simulator to send us everything (and not just + // what it thinks the connected Viewer can see) until + // such time as we ask it not to (the dtor). If we crash or + // otherwise, exit before this is turned off, the Simulator + // will take care of cleaning up for us. + if (gSavedSettings.getBOOL("360CaptureUseInterestListCap")) + { + // send everything to us for as long as this floater is open + const bool send_everything = true; + changeInterestListMode(send_everything); + } +} + +LLFloater360Capture::~LLFloater360Capture() +{ + if (mWebBrowser) + { + mWebBrowser->navigateStop(); + mWebBrowser->clearCache(); + mWebBrowser->unloadMediaSource(); + } + + // Tell the Simulator not to send us everything anymore + // and revert to the regular "keyhole" frustum of interest + // list updates. + if (gSavedSettings.getBOOL("360CaptureUseInterestListCap")) + { + const bool send_everything = false; + changeInterestListMode(send_everything); + } +} + +BOOL LLFloater360Capture::postBuild() +{ + mCaptureBtn = getChild("capture_button"); + mCaptureBtn->setCommitCallback(boost::bind(&LLFloater360Capture::onCapture360ImagesBtn, this)); + + mSaveLocalBtn = getChild("save_local_button"); + mSaveLocalBtn->setCommitCallback(boost::bind(&LLFloater360Capture::onSaveLocalBtn, this)); + mSaveLocalBtn->setEnabled(false); + + mWebBrowser = getChild("360capture_contents"); + mWebBrowser->addObserver(this); + + // There is a group of radio buttons that define the quality + // by each having a 'value' that is returns equal to the pixel + // size (width == height) + mQualityRadioGroup = getChild("360_quality_selection"); + mQualityRadioGroup->setCommitCallback(boost::bind(&LLFloater360Capture::onChooseQualityRadioGroup, this)); + + // UX/UI called for preview mode (always the first index/option) + // by default each time vs restoring the last value + mQualityRadioGroup->setSelectedIndex(0); + + // Construct a URL pointing to the first page to load. Although + // we do not use this page for anything (after some significant + // design changes), we retain the code to load the start page + // in case that changes again one day. It also makes sure the + // embedded browser is active and ready to go for when the real + // page with the 360 preview is navigated to. + std::string url = STRINGIZE( + "file:///" << + getHTMLBaseFolder() << + mDefaultHTML + ); + mWebBrowser->navigateTo(url); + + // initial pass at determining what size (width == height since + // the cube map images are square) we should capture at. + setSourceImageSize(); + + // the size of the output equirectangular image. The height of an EQR image + // is always 1/2 of the width so we should not store it but rather, + // calculate it from the width directly + mOutputImageWidth = gSavedSettings.getU32("360CaptureOutputImageWidth"); + mOutputImageHeight = mOutputImageWidth / 2; + + // enable resizing and enable for width and for height + enableResizeCtrls(true, true, true); + + // initial heading that consumers of the equirectangular image + // (such as Facebook or Flickr) use to position initial view - + // we set during capture - stored as degrees (0..359) + mInitialHeadingDeg = 0.0; + + // save directory in which to store the images (must obliviously be + // writable by the viewer). Also create it for users who haven't + // used the 360 feature before. + mImageSaveDir = gDirUtilp->getLindenUserDir() + gDirUtilp->getDirDelimiter() + "eqrimg"; + LLFile::mkdir(mImageSaveDir); + + // We do an initial capture when the floater is opened, albeit at a 'preview' + // quality level (really low resolution, but really fast) + onCapture360ImagesBtn(); + + return true; +} + +// called when the user choose a quality level using +// the buttons in the radio group +void LLFloater360Capture::onChooseQualityRadioGroup() +{ + // set the size of the captured cube map images based + // on the quality level chosen + setSourceImageSize(); +} + +// Using a new capability, tell the simulator that we want it to send everything +// it knows about and not just what is in front of the camera, in its view +// frustum. We need this feature so that the contents of the region that appears +// in the 6 snapshots which we cannot see and is normally not "considered", is +// also rendered. Typically, this is turned on when the 360 capture floater is +// opened and turned off when it is closed. +// Note: for this version, we do not have a way to determine when "everything" +// has arrived and has been rendered so for now, the proposal is that users +// will need to experiment with the low resolution version and wait for some +// (hopefully) small period of time while the full contents resolves. +// Pass in a flag to ask the simulator/interest list to "send everything" or +// not (the default mode) +void LLFloater360Capture::changeInterestListMode(bool send_everything) +{ + LLSD body; + + if (send_everything) + { + body["mode"] = LLSD::String("360"); + } + else + { + body["mode"] = LLSD::String("default"); + } + + if (gAgent.requestPostCapability("InterestList", body, [](const LLSD & response) + { + LL_INFOS("360Capture") << + "InterestList capability responded: \n" << + ll_pretty_print_sd(response) << + LL_ENDL; + })) + { + LL_INFOS("360Capture") << + "Successfully posted an InterestList capability request with payload: \n" << + ll_pretty_print_sd(body) << + LL_ENDL; + } + else + { + LL_INFOS("360Capture") << + "Unable to post an InterestList capability request with payload: \n" << + ll_pretty_print_sd(body) << + LL_ENDL; + } +} + +// There is is a setting (360CaptureSourceImageSize) that holds the size +// (width == height since it's a square) of each of the 6 source snapshots. +// However there are some known (and I dare say, some more unknown conditions +// where the specified size is not possible and this function tries to figure it +// out and change that setting to the optimal value for the current conditions. +void LLFloater360Capture::setSourceImageSize() +{ + mSourceImageSize = mQualityRadioGroup->getSelectedValue().asInteger(); + + // If deferred rendering is off, we need to shrink the window we capture + // until it's smaller than the Viewer window dimensions. + if (!LLPipeline::sRenderDeferred) + { + LLRect window_rect = gViewerWindow->getWindowRectRaw(); + S32 window_width = window_rect.getWidth(); + S32 window_height = window_rect.getHeight(); + + // It's not possible (as I had hoped) to always render to an off screen + // buffer regardless of deferred rendering status so the next best + // option is to render to a buffer that is the size of the users app + // window. Note, this was changed - before it chose the smallest + // power of 2 less than the window size - but since that meant a + // 1023 height app window would result in a 512 pixel capture, Maxim + // tried this and it does indeed appear to work. Mayb need to revisit + // after the project viewer pass if people on low end graphics systems + // after having issues. + if (mSourceImageSize > window_width || mSourceImageSize > window_height) + { + mSourceImageSize = llmin(window_width, window_height, mSourceImageSize); + LL_INFOS("360Capture") << "Deferred rendering is forcing a smaller capture size: " << mSourceImageSize << LL_ENDL; + } + + // there has to be an easier way than this to get the value + // from the radio group item at index 0. Why doesn't + // LLRadioGroup::getSelectedValue(int index) exist? + int index = mQualityRadioGroup->getSelectedIndex(); + mQualityRadioGroup->setSelectedIndex(0); + int min_size = mQualityRadioGroup->getSelectedValue().asInteger(); + mQualityRadioGroup->setSelectedIndex(index); + + // If the maximum size we can support falls below a threshold then + // we should display a message in the log so we can try to debug + // why this is happening + if (mSourceImageSize < min_size) + { + LL_INFOS("360Capture") << "Small snapshot size due to deferred rendering and small app window" << LL_ENDL; + } + } +} + +// This function shouldn't exist! We use the tooltip text from +// the corresponding XUI file (floater_360capture.xml) as the +// overlay text for the final web page to inform the user +// about the quality level in play. There ought to be a +// UI function like LLView* getSelectedItemView() or similar +// but as far as I can tell, there isn't so we have to resort +// to finding it ourselves with this icky code.. +const std::string LLFloater360Capture::getSelectedQualityTooltip() +{ + // safey (or bravery?) + if (mQualityRadioGroup != nullptr) + { + // for all the child widgets for the radio group + // (just the radio buttons themselves I think) + for (child_list_const_reverse_iter_t iter = mQualityRadioGroup->getChildList()->rbegin(); + iter != mQualityRadioGroup->getChildList()->rend(); + ++iter) + { + // if we match the selected index (which we can get easily) + // with our position in the list of children + if (mQualityRadioGroup->getSelectedIndex() == + std::distance(mQualityRadioGroup->getChildList()->rend(), iter) - 1) + { + // return the plain old tooltip text + return (*iter)->getToolTip(); + } + } + } + + // if it's not found or not available, return an empty string + return std::string(); +} + +// Some of the 'magic' happens via a web page in an HTML directory +// and this code provides a single point of reference for its' location +const std::string LLFloater360Capture::getHTMLBaseFolder() +{ + // It's in the default skin folder... + //std::string folder_name = gDirUtilp->getSkinDir(); + std::string folder_name = gDirUtilp->getDefaultSkinDir(); + // + folder_name += gDirUtilp->getDirDelimiter(); + folder_name += "html"; + folder_name += gDirUtilp->getDirDelimiter(); + folder_name += "common"; + folder_name += gDirUtilp->getDirDelimiter(); + folder_name += "equirectangular"; + folder_name += gDirUtilp->getDirDelimiter(); + + return folder_name; +} + +// triggered when the 'capture' button in the UI is pressed +void LLFloater360Capture::onCapture360ImagesBtn() +{ + // launch the main capture code in a coroutine so we can + // yield/suspend at some points to give the main UI + // thread a look-in occasionally. + LLCoros::instance().launch("capture360cap", [this]() + { + capture360Images(); + }); +} + +// Gets the full path name for a given JavaScript file in the HTML folder. We +// use this ultimately as a parameter to the main web app so it knows where to find +// the JavaScript array containing the 6 cube map images, stored as data URLs +const std::string LLFloater360Capture::makeFullPathToJS(const std::string filename) +{ + std::string full_js_path = mImageSaveDir; + full_js_path += gDirUtilp->getDirDelimiter(); + full_js_path += filename; + + return full_js_path; +} + +// Write the header/prequel portion of the JavaScript array of data urls +// that we use to store the cube map images in (so the web code can load +// them without tweaking browser security - we'd have to do this if they +// we stored as plain old images) This deliberately overwrites the old +// one, if it exists +void LLFloater360Capture::writeDataURLHeader(const std::string filename) +{ + llofstream file_handle(filename.c_str()); + if (file_handle.is_open()) + { + file_handle << "// cube map images for Second Life Viewer panorama 360 images" << std::endl; + file_handle.close(); + } +} + +// Write the footer/sequel portion of the JavaScript image code. When this is +// called, the current file on disk will contain the header and the 6 data +// URLs, each with a well specified name. This final piece of JavaScript code +// creates an array from those data URLs that the main application can +// reference and read. +void LLFloater360Capture::writeDataURLFooter(const std::string filename) +{ + llofstream file_handle(filename.c_str(), std::ios_base::app); + if (file_handle.is_open()) + { + file_handle << "var cubemap_img_js = [" << std::endl; + file_handle << " img_posx, img_negx," << std::endl; + file_handle << " img_posy, img_negy," << std::endl; + file_handle << " img_posz, img_negz," << std::endl; + file_handle << "];" << std::endl; + + file_handle.close(); + } +} + +// Given a filename, a chunk of data (representing an image file) and the size +// of the buffer, we create a BASE64 encoded string and use it to build a JavaScript +// data URL that represents the image in a web browser environment +bool LLFloater360Capture::writeDataURL(const std::string filename, const std::string prefix, U8* data, unsigned int data_len) +{ + LL_INFOS("360Capture") << "Writing data URL for " << prefix << " to " << filename << LL_ENDL; + + const std::string data_url = LLBase64::encode(data, data_len); + + llofstream file_handle(filename.c_str(), std::ios_base::app); + if (file_handle.is_open()) + { + file_handle << "var img_"; + file_handle << prefix; + file_handle << " = '"; + file_handle << "data:image/jpeg; base64,"; + file_handle << data_url; + file_handle << "'"; + file_handle << std::endl; + file_handle.close(); + + return true; + } + + return false; +} + +// Encode the image from each of the 6 snapshots and save it out to +// the JavaScript array of data URLs +void LLFloater360Capture::encodeAndSave(LLPointer raw_image, const std::string filename, const std::string prefix) +{ + // the default quality for the JPEG encoding is set quite high + // but this still seems to be a reasonable compromise for + // quality/size and is still much smaller than equivalent PNGs + int jpeg_encode_quality = gSavedSettings.getU32("360CaptureJPEGEncodeQuality"); + LLPointer jpeg_image = new LLImageJPEG(jpeg_encode_quality); + + // Actually encode the JPEG image. This is where a lot of time + // is spent now that the snapshot capture process has been + // optimized. The encode_time parameter doesn't appear to be + // used anymore. + const int encode_time = 0; + bool resultjpeg = jpeg_image->encode(raw_image, encode_time); + + if (resultjpeg) + { + // save individual cube map images as real JPEG files + // for debugging or curiosity) based on debug settings + if (gSavedSettings.getBOOL("360CaptureDebugSaveImage")) + { + const std::string jpeg_filename = STRINGIZE( + gDirUtilp->getLindenUserDir() << + gDirUtilp->getDirDelimiter() << + "eqrimg" << + gDirUtilp->getDirDelimiter() << + prefix << + "." << + jpeg_image->getExtension() + ); + + LL_INFOS("360Capture") << "Saving debug JPEG image as " << jpeg_filename << LL_ENDL; + jpeg_image->save(jpeg_filename); + } + + // actually write the JPEG image to disk as a data URL + writeDataURL(filename, prefix, jpeg_image->getData(), jpeg_image->getDataSize()); + } +} + +// Defer back to the main loop for a single rendered frame to give +// the renderer a chance to update the UI if it is needed +void LLFloater360Capture::suspendForAFrame() +{ + const U32 frame_count_delta = 1; + U32 curr_frame_count = LLFrameTimer::getFrameCount(); + while (LLFrameTimer::getFrameCount() <= curr_frame_count + frame_count_delta) + { + llcoro::suspend(); + } +} + +// A debug version of the snapshot code that simply fills the +// buffer with a pattern that can be used to investigate +// issues with encoding and saving off each RAW image. +// Probably not needed anymore but saving here just in case. +void LLFloater360Capture::mockSnapShot(LLImageRaw* raw) +{ + unsigned int width = raw->getWidth(); + unsigned int height = raw->getHeight(); + unsigned int depth = raw->getComponents(); + unsigned char* pixels = raw->getData(); + + for (int y = 0; y < height; y++) + { + for (int x = 0; x < width; x++) + { + unsigned long offset = y * width * depth + x * depth; + unsigned char red = x * 256 / width; + unsigned char green = y * 256 / height; + unsigned char blue = ((x + y) / 2) * 256 / (width + height) / 2; + pixels[offset + 0] = red; + pixels[offset + 1] = green; + pixels[offset + 2] = blue; + } + } +} + +// The main code that actually captures all 6 images and then saves them out to +// disk before navigating the embedded web browser to the page with the WebGL +// application that consumes them and creates an EQR image. This code runs as a +// coroutine so it can be suspended at certain points. +void LLFloater360Capture::capture360Images() +{ + // recheck the size of the cube map source images in case it changed + // since it was set when we opened the floater + setSourceImageSize(); + + // disable buttons while we are capturing + mCaptureBtn->setEnabled(false); + mSaveLocalBtn->setEnabled(false); + + bool render_attached_lights = LLPipeline::sRenderAttachedLights; + // determine whether or not to include avatar in the scene as we capture the 360 panorama + if (gSavedSettings.getBOOL("360CaptureHideAvatars")) + { + // Turn off the avatar if UI tells us to hide it. + // Note: the original call to gAvatar.hide(FALSE) did *not* hide + // attachments and so for most residents, there would be some debris + // left behind in the snapshot. + // Note: this toggles so if it set to on, this will turn it off and + // the subsequent call to the same thing after capture is finished + // will turn it back on again. Similarly, for the case where it + // was set to off - I think this is what we need + LLPipeline::toggleRenderTypeControl(LLPipeline::RENDER_TYPE_AVATAR); + LLPipeline::toggleRenderTypeControl(LLPipeline::RENDER_TYPE_PARTICLES); + LLPipeline::sRenderAttachedLights = FALSE; + } + + // these are the 6 directions we will point the camera - essentially, + // North, South, East, West, Up, Down + LLVector3 look_dirs[6] = { LLVector3(1, 0, 0), LLVector3(0, 1, 0), LLVector3(0, 0, 1), LLVector3(-1, 0, 0), LLVector3(0, -1, 0), LLVector3(0, 0, -1) }; + LLVector3 look_upvecs[6] = { LLVector3(0, 0, 1), LLVector3(0, 0, 1), LLVector3(0, -1, 0), LLVector3(0, 0, 1), LLVector3(0, 0, 1), LLVector3(0, 1, 0) }; + + // save current view/camera settings so we can restore them afterwards + S32 old_occlusion = LLPipeline::sUseOcclusion; + + // set new parameters specific to the 360 requirements + LLPipeline::sUseOcclusion = 0; + LLViewerCamera* camera = LLViewerCamera::getInstance(); + F32 old_fov = camera->getView(); + F32 old_aspect = camera->getAspect(); + F32 old_yaw = camera->getYaw(); + + // stop the motion of as much of the world moving as much as we can + freezeWorld(true); + + // Save the direction (in degrees) the camera is looking when we + // take the shot since that is what we write to image metadata + // 'GPano:InitialViewHeadingDegrees' field. + // We need to convert from the angle getYaw() gives us into something + // the XMP data field wants (N=0, E=90, S=180, W= 270 etc.) + mInitialHeadingDeg = (360 + 90 - (int)(camera->getYaw() * RAD_TO_DEG)) % 360; + LL_INFOS("360Capture") << "Recording a heading of " << (int)(mInitialHeadingDeg) << LL_ENDL; + + // camera constants for the square, cube map capture image + camera->setAspect(1.0); // must set aspect ratio first to avoid undesirable clamping of vertical FoV + camera->setView(F_PI_BY_TWO); + camera->yaw(0.0); + + // record how many times we changed camera to try to understand the "all shots are the same issue" + unsigned int camera_changed_times = 0; + + // the name of the JavaScript file written out that contains the 6 cube map images + // stored as a JavaScript array of data URLs. If you change this filename, you must + // also change the corresponding entry in the HTML file that uses it - + // (newview/skins/default/html/common/equirectangular/display_eqr.html) + const std::string cumemap_js_filename("cubemap_img.js"); + + // construct the full path to this file - typically stored in the users' + // Second Life settings / username / eqrimg folder. + const std::string cubemap_js_full_path = makeFullPathToJS(cumemap_js_filename); + + // Write the JavaScript file header (the top of the file before the + // declarations of the actual data URLs array). In practice, all this writes + // is a comment - it's main purpose is to reset the file from the last time + // it was written + writeDataURLHeader(cubemap_js_full_path); + + // the names of the prefixes we assign as the name to each data URL and are then + // consumed by the WebGL application. Nominally, they stand for positive and + // negative in the X/Y/Z directions. + static const std::string prefixes[6] = + { + "posx", "posz", "posy", + "negx", "negz", "negy", + }; + + // number of times to render the scene (display(..) inside + // the simple snapshot function in llViewerWindow. + // Note: rendering even just 1 more time (for a total of 2) + // has a dramatic effect on the scene contents and *much* + // less of it is missing. More investigation required + // but for the moment, this helps with missing content + // because of interest list issues. + int num_render_passes = gSavedSettings.getU32("360CaptureNumRenderPasses"); + + // time the encode process for later optimization + auto encode_time_total = 0.0; + + // for each of the 6 directions we shoot... + for (int i = 0; i < 6; i++) + { + // these buffers are where the raw, captured pixels are stored and + // the first time we use them, we have to make a new one + if (mRawImages[i] == nullptr) + { + mRawImages[i] = new LLImageRaw(mSourceImageSize, mSourceImageSize, 3); + } + else + // subsequent capture with floater open so we resize the buffer from + // the previous run + { + // LLImageRaw deletes the old one via operator= but just to be + // sure, we delete its' large data member first... + mRawImages[i]->deleteData(); + mRawImages[i] = new LLImageRaw(mSourceImageSize, mSourceImageSize, 3); + } + + // set up camera to look in each direction + camera->lookDir(look_dirs[i], look_upvecs[i]); + + // record if camera changed to try to understand the "all shots are the same issue" + if (camera->isChanged()) + { + ++camera_changed_times; + } + + // call the (very) simplified snapshot code that simply deals + // with a single image, no sub-images etc. but is very fast + gViewerWindow->simpleSnapshot(mRawImages[i], + mSourceImageSize, mSourceImageSize, num_render_passes); + + // encode each image and write to disk while saving how long it took to do so + auto t_start = std::chrono::high_resolution_clock::now(); + encodeAndSave(mRawImages[i], cubemap_js_full_path, prefixes[i]); + auto t_end = std::chrono::high_resolution_clock::now(); + auto duration = std::chrono::duration_cast>(t_end - t_start); + encode_time_total += duration.count(); + + // ping the main loop in case the snapshot process takes a really long + // time and we get disconnected + LLAppViewer::instance()->pingMainloopTimeout("LLFloater360Capture::capture360Images"); + } + + // display time to encode all 6 images. It tends to be a fairly linear + // time for each so we don't need to worry about displaying the time + // for each - this gives us plenty to use for optimizing + LL_INFOS("360Capture") << + "Time to encode and save 6 images was " << + encode_time_total << + " seconds" << + LL_ENDL; + + // Write the JavaScript file footer (the bottom of the file after the + // declarations of the actual data URLs array). The footer comprises of + // a JavaScript array declaration that references the 6 data URLs generated + // previously and is what is referred to in the display HTML file + // (newview/skins/default/html/common/equirectangular/display_eqr.html) + writeDataURLFooter(cubemap_js_full_path); + + // unfreeze the world now we have our shots + freezeWorld(false); + + // restore original view/camera/avatar settings settings + camera->setAspect(old_aspect); + camera->setView(old_fov); + camera->yaw(old_yaw); + LLPipeline::sUseOcclusion = old_occlusion; + + // if we toggled off the avatar because the Hide check box was ticked, + // we should toggle it back to where it was before we started the capture + if (gSavedSettings.getBOOL("360CaptureHideAvatars")) + { + LLPipeline::toggleRenderTypeControl(LLPipeline::RENDER_TYPE_AVATAR); + LLPipeline::toggleRenderTypeControl(LLPipeline::RENDER_TYPE_PARTICLES); + LLPipeline::sRenderAttachedLights = render_attached_lights; + } + + // record that we missed some shots in the log for later debugging + // note: we use 5 and not 6 because the first shot isn't regarded + // as a change - only the subsequent 5 are + if (camera_changed_times < 5) + { + LL_INFOS("360Capture") << "Warning: we only captured " << camera_changed_times << " images." << LL_ENDL; + } + + // now we have the 6 shots saved in a well specified location, + // we can load the web content that uses them + std::string url = "file:///" + getHTMLBaseFolder() + mEqrGenHTML; + mWebBrowser->navigateTo(url); + + // page is loaded and ready so we can turn on the buttons again + mCaptureBtn->setEnabled(true); + mSaveLocalBtn->setEnabled(true); + + // allow the UI to update by suspending and waiting for the + // main render loop to update the UI + suspendForAFrame(); +} + +// once the request is made to navigate to the web page containing the code +// to process the 6 images into an EQR one, we have to wait for it to finish +// loaded - we get a "navigate complete" event when that happens that we can act on +void LLFloater360Capture::handleMediaEvent(LLPluginClassMedia* self, EMediaEvent event) +{ + switch (event) + { + // not used right now but retaining because this event might + // be useful for a feature I am hoping to add + case MEDIA_EVENT_LOCATION_CHANGED: + break; + + // navigation in the browser completed + case MEDIA_EVENT_NAVIGATE_COMPLETE: + { + // Confirm that the navigation event does indeed apply to the + // page we are looking for. At the moment, this is the only + // one we care about so the test is superfluous but that might change. + std::string navigate_url = self->getNavigateURI(); + if (navigate_url.find(mEqrGenHTML) != std::string::npos) + { + // this string is being passed across to the web so replace all the windows backslash + // characters with forward slashes or (I think) the backslashes are treated as escapes + std::replace(mImageSaveDir.begin(), mImageSaveDir.end(), '\\', '/'); + + // we store the camera FOV (field of view) in a saved setting since this feels + // like something it would be interesting to change and experiment with + int camera_fov = gSavedSettings.getU32("360CaptureCameraFOV"); + + // compose the overlay for the final web page that tells the user + // what level of quality the capture was taken with + std::string overlay_label = "'" + getSelectedQualityTooltip() + "'"; + + // so now our page is loaded and images are in place - call + // the JavaScript init script with some parameters to initialize + // the WebGL based preview + const std::string cmd = STRINGIZE( + "init(" + << mOutputImageWidth + << ", " + << mOutputImageHeight + << ", " + << "'" + << mImageSaveDir + << "'" + << ", " + << camera_fov + << ", " + << LLViewerCamera::getInstance()->getYaw() + << ", " + << overlay_label + << ")" + ); + + // execute the command on the page + mWebBrowser->getMediaPlugin()->executeJavaScript(cmd); + } + } + break; + + default: + break; + } +} + +// called when the user wants to save the cube maps off to the final EQR image +void LLFloater360Capture::onSaveLocalBtn() +{ + // region name and URL + std::string region_name; // no sensible default + std::string region_url("http://secondlife.com"); + LLViewerRegion* region = gAgent.getRegion(); + if (region) + { + // region names can (and do) contain characters that would make passing + // them into a JavaScript function problematic - single quotes for example + // so we must escape/encode both + region_name = region->getName(); + + // escaping/encoding is a minefield - let's just remove any offending characters from the region name + region_name.erase(std::remove(region_name.begin(), region_name.end(), '\''), region_name.end()); + region_name.erase(std::remove(region_name.begin(), region_name.end(), '\"'), region_name.end()); + + // fortunately there is already an escaping function built into the SLURL generation code + LLSLURL slurl; + bool is_escaped = true; + LLAgentUI::buildSLURL(slurl, is_escaped); + region_url = slurl.getSLURLString(); + } + + // build suggested filename (the one that appears as the default + // in the Save dialog box) + const std::string suggested_filename = generate_proposed_filename(); + + // This string (the name of the product plus a truncated version number (no build)) + // is used in the XMP block as the name of the generating and stitching software. + // We save the version number here and not in the more generic 'software' item + // because that might help us determine something about the image in the future. + const std::string client_version = STRINGIZE( + LLVersionInfo::instance().getChannel() << + " " << + LLVersionInfo::instance().getShortVersion() + ); + + // save the time the image was created. I don't know if this should be + // UTC/ZULU or the users' local time. It probably doesn't matter. + std::time_t result = std::time(nullptr); + std::string ctime_str = std::ctime(&result); + std::string time_str = ctime_str.substr(0, ctime_str.length() - 1); + + // build the JavaScript data structure that is used to pass all the + // variables into the JavaScript function on the web page loaded into + // the embedded browser component of the floater. + const std::string xmp_details = STRINGIZE( + "{ " << + "pano_version: '" << "2.2.1" << "', " << + "software: '" << LLVersionInfo::instance().getChannel() << "', " << + "capture_software: '" << client_version << "', " << + "stitching_software: '" << client_version << "', " << + "width: " << mOutputImageWidth << ", " << + "height: " << mOutputImageHeight << ", " << + "heading: " << mInitialHeadingDeg << ", " << + "actual_source_image_size: " << mQualityRadioGroup->getSelectedValue().asInteger() << ", " << + "scaled_source_image_size: " << mSourceImageSize << ", " << + "first_photo_date: '" << time_str << "', " << + "last_photo_date: '" << time_str << "', " << + "region_name: '" << region_name << "', " << + "region_url: '" << region_url << "', " << + " }" + ); + + // build the JavaScript command to send to the web browser + const std::string cmd = "saveAsEqrImage(\"" + suggested_filename + "\", " + xmp_details + ")"; + + // send it to the browser instance, triggering the equirectangular capture + // process and complimentary offer to save the image + mWebBrowser->getMediaPlugin()->executeJavaScript(cmd); +} + +// We capture all 6 images sequentially and if parts of the world are moving +// E.G. clouds, water, objects - then we may get seams or discontinuities +// when the images are combined to form the EQR image. This code tries to +// stop everything so we can shoot for seamless shots. There is probably more +// we can do here - e.g. waves in the water probably won't line up. +void LLFloater360Capture::freezeWorld(bool enable) +{ + static bool clouds_scroll_paused = false; + if (enable) + { + // record the cloud scroll current value so we can restore it + clouds_scroll_paused = LLEnvironment::instance().isCloudScrollPaused(); + + // stop the clouds moving + LLEnvironment::instance().pauseCloudScroll(); + + // freeze all avatars + LLCharacter* avatarp; + for (std::vector::iterator iter = LLCharacter::sInstances.begin(); + iter != LLCharacter::sInstances.end(); ++iter) + { + avatarp = *iter; + mAvatarPauseHandles.push_back(avatarp->requestPause()); + } + + // freeze everything else + gSavedSettings.setBOOL("FreezeTime", true); + + // disable particle system + LLViewerPartSim::getInstance()->enable(false); + } + else // turning off freeze world mode, either temporarily or not. + { + // restart the clouds moving if they were not paused before + // we starting using the 360 capture floater + if (clouds_scroll_paused == false) + { + LLEnvironment::instance().resumeCloudScroll(); + } + + // thaw all avatars + mAvatarPauseHandles.clear(); + + // thaw everything else + gSavedSettings.setBOOL("FreezeTime", false); + + //enable particle system + LLViewerPartSim::getInstance()->enable(true); + } +} + +// Build the default filename that appears in the Save dialog box. We try +// to encode some metadata about too (region name, EQR dimensions, capture +// time) but the user if free to replace this with anything else before +// the images is saved. +const std::string LLFloater360Capture::generate_proposed_filename() +{ + std::ostringstream filename(""); + + // base name + filename << "sl360_"; + + LLViewerRegion* region = gAgent.getRegion(); + if (region) + { + // this looks complex but it's straightforward - removes all non-alpha chars from a string + // which in this case is the SL region name - we use it as a proposed filename but the user is free to change + std::string region_name = region->getName(); + std::replace_if(region_name.begin(), region_name.end(), std::not1(std::ptr_fun(isalnum)), '_'); + if (region_name.length() > 0) + { + filename << region_name; + filename << "_"; + } + } + + // add in resolution to make it easier to tell what you captured later + filename << mOutputImageWidth; + filename << "x"; + filename << mOutputImageHeight; + filename << "_"; + + // Add in the size of the source image (width == height since it was square) + // Might be useful later for quality comparisons + filename << mSourceImageSize; + filename << "_"; + + // add in the current HH-MM-SS (with leading 0's) so users can easily save many shots in same folder + std::time_t cur_epoch = std::time(nullptr); + std::tm* tm_time = std::localtime(&cur_epoch); + filename << std::setfill('0') << std::setw(4) << (tm_time->tm_year + 1900); + filename << std::setfill('0') << std::setw(2) << (tm_time->tm_mon + 1); + filename << std::setfill('0') << std::setw(2) << tm_time->tm_mday; + filename << "_"; + filename << std::setfill('0') << std::setw(2) << tm_time->tm_hour; + filename << std::setfill('0') << std::setw(2) << tm_time->tm_min; + filename << std::setfill('0') << std::setw(2) << tm_time->tm_sec; + + // the unusual way we save the output image (originates in the + // embedded browser and not the C++ code) means that the system + // appends ".jpeg" to the file automatically on macOS at least, + // so we only need to do it ourselves for windows. +#if LL_WINDOWS + filename << ".jpg"; +#endif + + return filename.str(); +} diff --git a/indra/newview/llfloater360capture.h b/indra/newview/llfloater360capture.h new file mode 100644 index 0000000000..6da7ee074a --- /dev/null +++ b/indra/newview/llfloater360capture.h @@ -0,0 +1,97 @@ +/** + * @file llfloater360capture.h + * @author Callum Prentice (callum@lindenlab.com) + * @brief Floater for the 360 capture feature + * + * $LicenseInfo:firstyear=2011&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2011, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LL_FLOATER_360CAPTURE_H +#define LL_FLOATER_360CAPTURE_H + +#include "llfloater.h" +#include "llmediactrl.h" +#include "llcharacter.h" + +class LLImageRaw; +class LLTextBox; +class LLRadioGroup; + +class LLFloater360Capture: + public LLFloater, + public LLViewerMediaObserver +{ + friend class LLFloaterReg; + + private: + LLFloater360Capture(const LLSD& key); + + ~LLFloater360Capture(); + BOOL postBuild() override; + void handleMediaEvent(LLPluginClassMedia* self, EMediaEvent event) override; + + void changeInterestListMode(bool send_everything); + + const std::string getHTMLBaseFolder(); + void capture360Images(); + + const std::string makeFullPathToJS(const std::string filename); + void writeDataURLHeader(const std::string filename); + void writeDataURLFooter(const std::string filename); + bool writeDataURL(const std::string filename, const std::string prefix, U8* data, unsigned int data_len); + void encodeAndSave(LLPointer raw_image, const std::string filename, const std::string prefix); + + std::vector mAvatarPauseHandles; + void freezeWorld(bool enable); + + void mockSnapShot(LLImageRaw* raw); + + void suspendForAFrame(); + + const std::string generate_proposed_filename(); + + void setSourceImageSize(); + + LLMediaCtrl* mWebBrowser; + const std::string mDefaultHTML = "default.html"; + const std::string mEqrGenHTML = "eqr_gen.html"; + + LLUICtrl* mCaptureBtn; + void onCapture360ImagesBtn(); + + void onSaveLocalBtn(); + LLUICtrl* mSaveLocalBtn; + + LLRadioGroup* mQualityRadioGroup; + void onChooseQualityRadioGroup(); + const std::string getSelectedQualityTooltip(); + + int mSourceImageSize; + float mInitialHeadingDeg; + int mOutputImageWidth; + int mOutputImageHeight; + std::string mImageSaveDir; + + LLPointer mRawImages[6]; +}; + +#endif // LL_FLOATER_360CAPTURE_H diff --git a/indra/newview/llfloaterautoreplacesettings.cpp b/indra/newview/llfloaterautoreplacesettings.cpp index ec05ba924c..6b91491dba 100644 --- a/indra/newview/llfloaterautoreplacesettings.cpp +++ b/indra/newview/llfloaterautoreplacesettings.cpp @@ -64,6 +64,7 @@ #include "llnotificationhandler.h" #include "llnotificationmanager.h" #include "llnotificationsutil.h" +#include "llviewercontrol.h" LLFloaterAutoReplaceSettings::LLFloaterAutoReplaceSettings(const LLSD& key) @@ -419,6 +420,14 @@ void LLFloaterAutoReplaceSettings::onNewList() bool LLFloaterAutoReplaceSettings::callbackNewListName(const LLSD& notification, const LLSD& response) { LL_DEBUGS("AutoReplace")<<"called"< FIRE-31256: Add Cancel button for new auto-replace list dialog + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + if (option != 0) + { + return false; + } + // LLSD newList = notification["payload"]["list"]; diff --git a/indra/newview/llfloateravatarrendersettings.cpp b/indra/newview/llfloateravatarrendersettings.cpp index 15870faa62..1864612487 100644 --- a/indra/newview/llfloateravatarrendersettings.cpp +++ b/indra/newview/llfloateravatarrendersettings.cpp @@ -91,7 +91,6 @@ BOOL LLFloaterAvatarRenderSettings::postBuild() LLFloater::postBuild(); mAvatarSettingsList = getChild("render_settings_list"); mAvatarSettingsList->setRightMouseDownCallback(boost::bind(&LLFloaterAvatarRenderSettings::onAvatarListRightClick, this, _1, _2, _3)); - getChild("people_filter_input")->setCommitCallback(boost::bind(&LLFloaterAvatarRenderSettings::onFilterEdit, this, _2)); return TRUE; } @@ -135,37 +134,13 @@ void LLFloaterAvatarRenderSettings::updateList() { item_params.value = iter->first; LLAvatarNameCache::get(iter->first, &av_name); - if(!isHiddenRow(av_name.getCompleteName())) - { - item_params.columns.add().value(av_name.getCompleteName()).column("name"); - std::string setting = getString(iter->second == 1 ? "av_never_render" : "av_always_render"); - item_params.columns.add().value(setting).column("setting"); - std::string timestamp = createTimestamp(LLRenderMuteList::getInstance()->getVisualMuteDate(iter->first)); - item_params.columns.add().value(timestamp).column("timestamp"); - mAvatarSettingsList->addNameItemRow(item_params); - } + item_params.columns.add().value(av_name.getCompleteName()).column("name"); + std::string setting = getString(iter->second == 1 ? "av_never_render" : "av_always_render"); + item_params.columns.add().value(setting).column("setting"); + mAvatarSettingsList->addNameItemRow(item_params); } } -void LLFloaterAvatarRenderSettings::onFilterEdit(const std::string& search_string) -{ - std::string filter_upper = search_string; - LLStringUtil::toUpper(filter_upper); - if (mNameFilter != filter_upper) - { - mNameFilter = filter_upper; - mNeedsUpdate = true; - } -} - -bool LLFloaterAvatarRenderSettings::isHiddenRow(const std::string& av_name) -{ - if (mNameFilter.empty()) return false; - std::string upper_name = av_name; - LLStringUtil::toUpper(upper_name); - return std::string::npos == upper_name.find(mNameFilter); -} - static LLVOAvatar* find_avatar(const LLUUID& id) { LLViewerObject *obj = gObjectList.findObject(id); @@ -216,6 +191,10 @@ bool LLFloaterAvatarRenderSettings::isActionChecked(const LLSD& userdata, const { return (visual_setting == S32(LLVOAvatar::AV_RENDER_NORMALLY)); } + else if ("non_default" == command_name) + { + return (visual_setting != S32(LLVOAvatar::AV_RENDER_NORMALLY)); + } else if ("never" == command_name) { return (visual_setting == S32(LLVOAvatar::AV_DO_NOT_RENDER)); diff --git a/indra/newview/llfloateravatarrendersettings.h b/indra/newview/llfloateravatarrendersettings.h index af36b67bd0..d03f035b4d 100644 --- a/indra/newview/llfloateravatarrendersettings.h +++ b/indra/newview/llfloateravatarrendersettings.h @@ -50,7 +50,6 @@ public: void onAvatarListRightClick(LLUICtrl* ctrl, S32 x, S32 y); void updateList(); - void onFilterEdit(const std::string& search_string); void onCustomAction (const LLSD& userdata, const LLUUID& av_id); bool isActionChecked(const LLSD& userdata, const LLUUID& av_id); void onClickAdd(const LLSD& userdata); @@ -61,15 +60,12 @@ public: static void setNeedsUpdate(); private: - bool isHiddenRow(const std::string& av_name); void callbackAvatarPicked(const uuid_vec_t& ids, S32 visual_setting); void removePicker(); bool mNeedsUpdate; LLListContextMenu* mContextMenu; LLNameListCtrl* mAvatarSettingsList; - - std::string mNameFilter; }; diff --git a/indra/newview/llfloaterbuyland.cpp b/indra/newview/llfloaterbuyland.cpp index ca38104e49..a7a3a6ef5e 100644 --- a/indra/newview/llfloaterbuyland.cpp +++ b/indra/newview/llfloaterbuyland.cpp @@ -1005,7 +1005,8 @@ void LLFloaterBuyLandUI::draw() // virtual BOOL LLFloaterBuyLandUI::canClose() { - bool can_close = (mTransaction ? FALSE : TRUE) && mCurrency.canCancel(); + // mTransactionType check for pre-buy estimation stage and mCurrency to allow exit after transaction + bool can_close = !mTransaction && (mTransactionType != TransactionBuy || mCurrency.canCancel()); if (!can_close) { // explain to user why they can't do this, see DEV-9605 diff --git a/indra/newview/llfloatercolorpicker.cpp b/indra/newview/llfloatercolorpicker.cpp index 12572f8ad6..4032aa6e28 100644 --- a/indra/newview/llfloatercolorpicker.cpp +++ b/indra/newview/llfloatercolorpicker.cpp @@ -59,7 +59,7 @@ #include "llwindow.h" #include "llnotificationsutil.h" // Add float LSL color entry widgets -#include +#include "llregex.h" // System includes #include @@ -773,7 +773,7 @@ void LLFloaterColorPicker::onTextEntryChanged ( LLUICtrl* ctrl ) std::string reg_ex("[[:xdigit:]]{6}"); boost::regex pattern(reg_ex.c_str()); - if (!boost::regex_match(hex_string, pattern)) + if (!ll_regex_match(hex_string, pattern)) { return; } diff --git a/indra/newview/llfloatereditextdaycycle.cpp b/indra/newview/llfloatereditextdaycycle.cpp index 0501c287ad..eb0cd28190 100644 --- a/indra/newview/llfloatereditextdaycycle.cpp +++ b/indra/newview/llfloatereditextdaycycle.cpp @@ -98,6 +98,11 @@ namespace { const std::string TABS_SKYS("sky_tabs"); const std::string TABS_WATER("water_tabs"); + // 'Play' buttons + const std::string BTN_PLAY("play_btn"); + const std::string BTN_SKIP_BACK("skip_back_btn"); + const std::string BTN_SKIP_FORWARD("skip_forward_btn"); + const std::string EVNT_DAYTRACK("DayCycle.Track"); const std::string EVNT_PLAY("DayCycle.PlayActions"); @@ -1205,6 +1210,11 @@ void LLFloaterEditExtDayCycle::updateButtons() mDeleteFrameButton->setEnabled(can_manipulate && isRemovingFrameAllowed()); mLoadFrame->setEnabled(can_manipulate); + BOOL enable_play = mEditDay ? TRUE : FALSE; + childSetEnabled(BTN_PLAY, enable_play); + childSetEnabled(BTN_SKIP_BACK, enable_play); + childSetEnabled(BTN_SKIP_FORWARD, enable_play); + // update track buttons bool extended_env = LLEnvironment::instance().isExtendedEnvironmentEnabled(); for (S32 track = 0; track < LLSettingsDay::TRACK_MAX; ++track) @@ -1457,14 +1467,22 @@ void LLFloaterEditExtDayCycle::reblendSettings() { F64 position = mTimeSlider->getCurSliderValue(); - if ((mSkyBlender->getTrack() != mCurrentTrack) && (mCurrentTrack != LLSettingsDay::TRACK_WATER)) + if (mSkyBlender) { - mSkyBlender->switchTrack(mCurrentTrack, position); + if ((mSkyBlender->getTrack() != mCurrentTrack) && (mCurrentTrack != LLSettingsDay::TRACK_WATER)) + { + mSkyBlender->switchTrack(mCurrentTrack, position); + } + else + { + mSkyBlender->setPosition(position); + } } - else - mSkyBlender->setPosition(position); - mWaterBlender->setPosition(position); + if (mWaterBlender) + { + mWaterBlender->setPosition(position); + } } void LLFloaterEditExtDayCycle::doApplyCommit(LLSettingsDay::ptr_t day) @@ -1567,15 +1585,22 @@ void LLFloaterEditExtDayCycle::onIdlePlay(void* user_data) { LLFloaterEditExtDayCycle* self = (LLFloaterEditExtDayCycle*)user_data; - F32 prcnt_played = self->mPlayTimer.getElapsedTimeF32() / DAY_CYCLE_PLAY_TIME_SECONDS; - F32 new_frame = fmod(self->mPlayStartFrame + prcnt_played, 1.f); + if (self->mSkyBlender == nullptr || self->mWaterBlender == nullptr) + { + self->stopPlay(); + } + else + { - self->mTimeSlider->setCurSliderValue(new_frame); // will do the rounding - self->mSkyBlender->setPosition(new_frame); - self->mWaterBlender->setPosition(new_frame); - self->synchronizeTabs(); - self->updateTimeAndLabel(); - self->updateButtons(); + F32 prcnt_played = self->mPlayTimer.getElapsedTimeF32() / DAY_CYCLE_PLAY_TIME_SECONDS; + F32 new_frame = fmod(self->mPlayStartFrame + prcnt_played, 1.f); + + self->mTimeSlider->setCurSliderValue(new_frame); // will do the rounding + + self->synchronizeTabs(); + self->updateTimeAndLabel(); + self->updateButtons(); + } } } diff --git a/indra/newview/llfloatergodtools.cpp b/indra/newview/llfloatergodtools.cpp index adc7f71586..4b22f7427b 100644 --- a/indra/newview/llfloatergodtools.cpp +++ b/indra/newview/llfloatergodtools.cpp @@ -248,6 +248,29 @@ void LLFloaterGodTools::processRegionInfo(LLMessageSystem* msg) region_flags = flags; } + if (msg->has(_PREHASH_RegionInfo5)) + { + F32 chat_whisper_range; + F32 chat_normal_range; + F32 chat_shout_range; + F32 chat_whisper_offset; + F32 chat_normal_offset; + F32 chat_shout_offset; + U32 chat_flags; + + msg->getF32Fast(_PREHASH_RegionInfo5, _PREHASH_ChatWhisperRange, chat_whisper_range); + msg->getF32Fast(_PREHASH_RegionInfo5, _PREHASH_ChatNormalRange, chat_normal_range); + msg->getF32Fast(_PREHASH_RegionInfo5, _PREHASH_ChatShoutRange, chat_shout_range); + msg->getF32Fast(_PREHASH_RegionInfo5, _PREHASH_ChatWhisperOffset, chat_whisper_offset); + msg->getF32Fast(_PREHASH_RegionInfo5, _PREHASH_ChatNormalOffset, chat_normal_offset); + msg->getF32Fast(_PREHASH_RegionInfo5, _PREHASH_ChatShoutOffset, chat_shout_offset); + msg->getU32Fast(_PREHASH_RegionInfo5, _PREHASH_ChatFlags, chat_flags); + + LL_INFOS() << "Whisper range: " << chat_whisper_range << " normal range: " << chat_normal_range << " shout range: " << chat_shout_range + << " whisper offset: " << chat_whisper_offset << " normal offset: " << chat_normal_offset << " shout offset: " << chat_shout_offset + << " chat flags: " << chat_flags << LL_ENDL; + } + if (host != gAgent.getRegionHost()) { // Update is for a different region than the one we're in. diff --git a/indra/newview/llfloaterimsessiontab.cpp b/indra/newview/llfloaterimsessiontab.cpp index 1d2b587d3f..d0cb0ca798 100644 --- a/indra/newview/llfloaterimsessiontab.cpp +++ b/indra/newview/llfloaterimsessiontab.cpp @@ -520,9 +520,12 @@ void LLFloaterIMSessionTab::addConversationViewParticipant(LLConversationItem* p LLFolderViewItem* widget = get_ptr_in_map(mConversationsWidgets,uuid); // If not already present, create the participant view and attach it to the root, otherwise, just refresh it - if (widget && update_view) + if (widget) { - updateConversationViewParticipant(uuid); // overkill? + if (update_view) + { + updateConversationViewParticipant(uuid); // overkill? + } } else { diff --git a/indra/newview/llfloaterlinkreplace.cpp b/indra/newview/llfloaterlinkreplace.cpp index 204e7b036e..16c91370f0 100644 --- a/indra/newview/llfloaterlinkreplace.cpp +++ b/indra/newview/llfloaterlinkreplace.cpp @@ -204,7 +204,7 @@ void LLFloaterLinkReplace::onStartClicked() else { LLSD args; - args["TYPE"] = LLWearableType::getTypeName(source_item->getWearableType()); + args["TYPE"] = LLWearableType::getInstance()->getTypeName(source_item->getWearableType()); params.substitutions(args); LLNotifications::instance().add(params); } diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp index 8a63756457..6c3b06ad60 100644 --- a/indra/newview/llfloaterpreference.cpp +++ b/indra/newview/llfloaterpreference.cpp @@ -53,6 +53,7 @@ #include "llfloaterreg.h" #include "llfloaterabout.h" #include "llfavoritesbar.h" +#include "llfloaterpreferencesgraphicsadvanced.h" #include "llfloatersidepanelcontainer.h" // [FS communication UI] //#include "llfloaterimsession.h" @@ -84,7 +85,6 @@ #include "llviewereventrecorder.h" #include "llviewermessage.h" #include "llviewerwindow.h" -#include "llviewershadermgr.h" #include "llviewerthrottle.h" #include "llvoavatarself.h" #include "llvotree.h" @@ -108,11 +108,9 @@ #include "lltextbox.h" #include "llui.h" #include "llviewerobjectlist.h" -#include "llvoavatar.h" #include "llvovolume.h" #include "llwindow.h" #include "llworld.h" -#include "pipeline.h" #include "lluictrlfactory.h" #include "llviewermedia.h" #include "llpluginclassmedia.h" @@ -128,8 +126,6 @@ #include "llpresetsmanager.h" #include "llviewercontrol.h" #include "llpresetsmanager.h" -#include "llfeaturemanager.h" -#include "llviewertexturelist.h" #include "llsearchableui.h" @@ -143,18 +139,19 @@ #include "llaudioengine.h" // Output device selection #include "llavatarname.h" // Deeper name cache stuffs #include "llclipboard.h" // Support preferences search SLURLs -#include "lleventtimer.h" -#include "llviewermenufile.h" // FIRE-23606 Reveal path to external script editor in prefernces #include "lldiriterator.h" // for populating the fonts combo +#include "lleventtimer.h" #include "llline.h" #include "lllocationhistory.h" #include "llpanelblockedlist.h" #include "llpanelmaininventory.h" #include "llscrolllistctrl.h" -#include "llspellcheck.h" #include "llsdserialize.h" // KB: SkinsSelector +#include "llspellcheck.h" #include "lltoolbarview.h" +#include "llviewermenufile.h" // FIRE-23606 Reveal path to external script editor in prefernces #include "llviewernetwork.h" // +#include "llviewershadermgr.h" #include "NACLantispam.h" #include "../llcrashlogger/llcrashlogger.h" #if LL_WINDOWS @@ -168,9 +165,11 @@ #endif // +#include "fsperfstats.h"// perfstats + // FIRE-19539 - Include the alert messages in Prefs>Notifications>Alerts in preference Search. #include "llfiltereditor.h" - +#include "llviewershadermgr.h" // FIRE-6340, FIRE-6567 - Setting Bandwidth issues //const F32 BANDWIDTH_UPDATER_TIMEOUT = 0.5f; char const* const VISIBILITY_DEFAULT = "default"; @@ -427,9 +426,11 @@ std::string LLFloaterPreference::sSkin = ""; LLFloaterPreference::LLFloaterPreference(const LLSD& key) : LLFloater(key), mGotPersonalInfo(false), + // Keep this for OpenSim mOriginalIMViaEmail(false), mLanguageChanged(false), - mAvatarDataInitialized(false) + mAvatarDataInitialized(false), + mSearchDataDirty(true) { LLConversationLog::instance().addObserver(this); @@ -507,6 +508,8 @@ LLFloaterPreference::LLFloaterPreference(const LLSD& key) LLAvatarPropertiesProcessor::getInstance()->addObserver( gAgent.getID(), this ); + mComplexityChangedSignal = gSavedSettings.getControl("RenderAvatarMaxComplexity")->getCommitSignal()->connect(boost::bind(&LLFloaterPreference::updateComplexityText, this)); + mCommitCallbackRegistrar.add("Pref.ClearLog", boost::bind(&LLConversationLog::onClearLog, &LLConversationLog::instance())); mCommitCallbackRegistrar.add("Pref.DeleteTranscripts", boost::bind(&LLFloaterPreference::onDeleteTranscripts, this)); mCommitCallbackRegistrar.add("UpdateFilter", boost::bind(&LLFloaterPreference::onUpdateFilterTerm, this, false)); // Hook up for filtering @@ -746,7 +749,11 @@ BOOL LLFloaterPreference::postBuild() // Group Notices and chiclets location setting conversion BOOL => S32 // Show email address in preferences (FIRE-1071) - getChild("send_im_to_email")->setLabelArg("[EMAIL]", getString("LoginToChange")); + getChild("send_im_to_email")->setEnabled(FALSE); + getChild("send_im_to_email")->setVisible(FALSE); + childSetVisible("email_settings", false); + childSetEnabled("email_settings", false); + childSetVisible("email_settings_login_to_change", true); // Load the list of font settings populateFontSelectionCombo(); @@ -892,6 +899,7 @@ void LLFloaterPreference::onDoNotDisturbResponseChanged() LLFloaterPreference::~LLFloaterPreference() { LLConversationLog::instance().removeObserver(this); + mComplexityChangedSignal.disconnect(); } // FIRE-19539 - Include the alert messages in Prefs>Notifications>Alerts in preference Search. @@ -966,9 +974,12 @@ void LLFloaterPreference::apply() if (mGotPersonalInfo) { + // Keep this for OpenSim bool new_im_via_email = getChild("send_im_to_email")->getValue().asBoolean(); bool new_hide_online = getChild("online_visibility")->getValue().asBoolean(); + // Keep this for OpenSim + //if (new_hide_online != mOriginalHideOnlineStatus) if ((new_im_via_email != mOriginalIMViaEmail) ||(new_hide_online != mOriginalHideOnlineStatus)) { @@ -984,6 +995,8 @@ void LLFloaterPreference::apply() //Update showonline value, otherwise multiple applys won't work mOriginalHideOnlineStatus = new_hide_online; } + // Keep this for OpenSim + //gAgent.sendAgentUpdateUserInfo(mDirectoryVisibility); gAgent.sendAgentUpdateUserInfo(new_im_via_email,mDirectoryVisibility); } } @@ -1276,33 +1289,6 @@ void LLFloaterPreference::onRenderOptionEnable() refreshEnabledGraphics(); } -void LLFloaterPreferenceGraphicsAdvanced::onRenderOptionEnable() -{ - LLFloaterPreference* instance = LLFloaterReg::findTypedInstance("preferences"); - if (instance) - { - instance->refresh(); - } - - refreshEnabledGraphics(); -} - -void LLFloaterPreferenceGraphicsAdvanced::onAdvancedAtmosphericsEnable() -{ - LLFloaterPreference* instance = LLFloaterReg::findTypedInstance("preferences"); - if (instance) - { - instance->refresh(); - } - - refreshEnabledGraphics(); -} - -void LLFloaterPreferenceGraphicsAdvanced::refreshEnabledGraphics() -{ - refreshEnabledState(); -} - void LLFloaterPreference::onAvatarImpostorsEnable() { refreshEnabledGraphics(); @@ -1577,16 +1563,16 @@ void LLFloaterPreference::onBtnCancel(const LLSD& userdata) } // static -// Show email address in preferences (FIRE-1071) -//void LLFloaterPreference::updateUserInfo(const std::string& visibility, bool im_via_email, bool is_verified_email) -void LLFloaterPreference::updateUserInfo(const std::string& visibility, bool im_via_email, bool is_verified_email, const std::string& email) +// Show email address in preferences (FIRE-1071) and keep it for OpenSim +//void LLFloaterPreference::updateUserInfo(const std::string& visibility) +void LLFloaterPreference::updateUserInfo(const std::string& visibility, bool im_via_email, const std::string& email) { LLFloaterPreference* instance = LLFloaterReg::findTypedInstance("preferences"); if (instance) { - // Show email address in preferences (FIRE-1071) - //instance->setPersonalInfo(visibility, im_via_email, is_verified_email); - instance->setPersonalInfo(visibility, im_via_email, is_verified_email, email); + // Show email address in preferences (FIRE-1071) and keep it for OpenSim + //instance->setPersonalInfo(visibility); + instance->setPersonalInfo(visibility, im_via_email, email); } } @@ -2325,129 +2311,6 @@ void LLFloaterPreference::onCopySearch() } // -void LLFloaterPreferenceGraphicsAdvanced::refreshEnabledState() -{ - LLComboBox* ctrl_reflections = getChild("Reflections"); - LLTextBox* reflections_text = getChild("ReflectionsText"); - - // Reflections - BOOL reflections = gGLManager.mHasCubeMap && LLCubeMap::sUseCubeMaps; - ctrl_reflections->setEnabled(reflections); - reflections_text->setEnabled(reflections); - - // Transparent Water - LLCheckBoxCtrl* transparent_water_ctrl = getChild("TransparentWater"); - - // Bump & Shiny - LLCheckBoxCtrl* bumpshiny_ctrl = getChild("BumpShiny"); - bool bumpshiny = gGLManager.mHasCubeMap && LLCubeMap::sUseCubeMaps && LLFeatureManager::getInstance()->isFeatureAvailable("RenderObjectBump"); - bumpshiny_ctrl->setEnabled(bumpshiny ? TRUE : FALSE); - - // Avatar Mode - // Enable Avatar Shaders - LLCheckBoxCtrl* ctrl_avatar_vp = getChild("AvatarVertexProgram"); - // Avatar Render Mode - LLCheckBoxCtrl* ctrl_avatar_cloth = getChild("AvatarCloth"); - - bool avatar_vp_enabled = LLFeatureManager::getInstance()->isFeatureAvailable("RenderAvatarVP"); - if (LLViewerShaderMgr::sInitialized) - { - S32 max_avatar_shader = LLViewerShaderMgr::instance()->mMaxAvatarShaderLevel; - avatar_vp_enabled = (max_avatar_shader > 0) ? TRUE : FALSE; - } - - ctrl_avatar_vp->setEnabled(avatar_vp_enabled); - - if (gSavedSettings.getBOOL("RenderAvatarVP") == FALSE) - { - ctrl_avatar_cloth->setEnabled(FALSE); - } - else - { - ctrl_avatar_cloth->setEnabled(TRUE); - } - - /* remove orphaned code left over from EEP - // Vertex Shaders, Global Shader Enable - // SL-12594 Basic shaders are always enabled. DJH TODO clean up now-orphaned state handling code - LLSliderCtrl* terrain_detail = getChild("TerrainDetail"); // can be linked with control var - LLTextBox* terrain_text = getChild("TerrainDetailText"); - terrain_detail->setEnabled(FALSE); - terrain_text->setEnabled(FALSE); - */ - - // WindLight - LLCheckBoxCtrl* ctrl_wind_light = getChild("WindLightUseAtmosShaders"); - LLSliderCtrl* sky = getChild("SkyMeshDetail"); - LLTextBox* sky_text = getChild("SkyMeshDetailText"); -// [RLVa:KB] - Checked: 2010-03-18 (RLVa-1.2.0a) | Modified: RLVa-0.2.0a - // "Atmospheric Shaders" can't be disabled - but can be enabled - under @setenv=n - ctrl_wind_light->setEnabled( (RlvActions::canChangeEnvironment()) || (!gSavedSettings.getBOOL("WindLightUseAtmosShaders"))); -// [/RLVa:KB] -// ctrl_wind_light->setEnabled(TRUE); - sky->setEnabled(TRUE); - sky_text->setEnabled(TRUE); - - //Deferred/SSAO/Shadows - LLCheckBoxCtrl* ctrl_deferred = getChild("UseLightShaders"); - - BOOL enabled = LLFeatureManager::getInstance()->isFeatureAvailable("RenderDeferred") && - ((bumpshiny_ctrl && bumpshiny_ctrl->get()) ? TRUE : FALSE) && - ((transparent_water_ctrl && transparent_water_ctrl->get()) ? TRUE : FALSE) && - gGLManager.mHasFramebufferObject && - gSavedSettings.getBOOL("RenderAvatarVP") && - (ctrl_wind_light->get()) ? TRUE : FALSE; - - ctrl_deferred->setEnabled(enabled); - - LLCheckBoxCtrl* ctrl_ssao = getChild("UseSSAO"); - LLCheckBoxCtrl* ctrl_dof = getChild("UseDoF"); - LLComboBox* ctrl_shadow = getChild("ShadowDetail"); - LLTextBox* shadow_text = getChild("RenderShadowDetailText"); - - // note, okay here to get from ctrl_deferred as it's twin, ctrl_deferred2 will alway match it - enabled = enabled && LLFeatureManager::getInstance()->isFeatureAvailable("RenderDeferredSSAO") && (ctrl_deferred->get() ? TRUE : FALSE); - - ctrl_deferred->set(gSavedSettings.getBOOL("RenderDeferred")); - - ctrl_ssao->setEnabled(enabled); - ctrl_dof->setEnabled(enabled); - - enabled = enabled && LLFeatureManager::getInstance()->isFeatureAvailable("RenderShadowDetail"); - - ctrl_shadow->setEnabled(enabled); - shadow_text->setEnabled(enabled); - - // Hardware settings - F32 mem_multiplier = gSavedSettings.getF32("RenderTextureMemoryMultiple"); - S32Megabytes min_tex_mem = LLViewerTextureList::getMinVideoRamSetting(); - S32Megabytes max_tex_mem = LLViewerTextureList::getMaxVideoRamSetting(false, mem_multiplier); - getChild("GraphicsCardTextureMemory")->setMinValue(min_tex_mem.value()); - getChild("GraphicsCardTextureMemory")->setMaxValue(max_tex_mem.value()); - - if (!LLFeatureManager::getInstance()->isFeatureAvailable("RenderVBOEnable") || - !gGLManager.mHasVertexBufferObject) - { - getChildView("vbo")->setEnabled(FALSE); - } - - if (!LLFeatureManager::getInstance()->isFeatureAvailable("RenderCompressTextures") || - !gGLManager.mHasVertexBufferObject) - { - getChildView("texture compression")->setEnabled(FALSE); - } - - // if no windlight shaders, turn off nighttime brightness, gamma, and fog distance - LLUICtrl* gamma_ctrl = getChild("gamma"); - gamma_ctrl->setEnabled(!gPipeline.canUseWindLightShaders()); - getChildView("(brightness, lower is brighter)")->setEnabled(!gPipeline.canUseWindLightShaders()); - getChildView("fog")->setEnabled(!gPipeline.canUseWindLightShaders()); - getChildView("antialiasing restart")->setVisible(!LLFeatureManager::getInstance()->isFeatureAvailable("RenderDeferred")); - - // now turn off any features that are unavailable - disableUnavailableSettings(); -} - // static void LLAvatarComplexityControls::setIndirectControls() @@ -2594,118 +2457,6 @@ void LLFloaterPreference::disableUnavailableSettings() } } -void LLFloaterPreferenceGraphicsAdvanced::disableUnavailableSettings() -{ - LLComboBox* ctrl_reflections = getChild("Reflections"); - LLTextBox* reflections_text = getChild("ReflectionsText"); - LLCheckBoxCtrl* ctrl_avatar_vp = getChild("AvatarVertexProgram"); - LLCheckBoxCtrl* ctrl_avatar_cloth = getChild("AvatarCloth"); - LLCheckBoxCtrl* ctrl_wind_light = getChild("WindLightUseAtmosShaders"); - LLCheckBoxCtrl* ctrl_deferred = getChild("UseLightShaders"); - LLComboBox* ctrl_shadows = getChild("ShadowDetail"); - LLTextBox* shadows_text = getChild("RenderShadowDetailText"); - LLCheckBoxCtrl* ctrl_ssao = getChild("UseSSAO"); - LLCheckBoxCtrl* ctrl_dof = getChild("UseDoF"); - LLSliderCtrl* sky = getChild("SkyMeshDetail"); - LLTextBox* sky_text = getChild("SkyMeshDetailText"); - - // disabled windlight - if (!LLFeatureManager::getInstance()->isFeatureAvailable("WindLightUseAtmosShaders")) - { - ctrl_wind_light->setEnabled(FALSE); - ctrl_wind_light->setValue(FALSE); - - sky->setEnabled(FALSE); - sky_text->setEnabled(FALSE); - - //deferred needs windlight, disable deferred - ctrl_shadows->setEnabled(FALSE); - ctrl_shadows->setValue(0); - shadows_text->setEnabled(FALSE); - - ctrl_ssao->setEnabled(FALSE); - ctrl_ssao->setValue(FALSE); - - ctrl_dof->setEnabled(FALSE); - ctrl_dof->setValue(FALSE); - - ctrl_deferred->setEnabled(FALSE); - ctrl_deferred->setValue(FALSE); - } - - // disabled deferred - if (!LLFeatureManager::getInstance()->isFeatureAvailable("RenderDeferred") || - !gGLManager.mHasFramebufferObject) - { - ctrl_shadows->setEnabled(FALSE); - ctrl_shadows->setValue(0); - shadows_text->setEnabled(FALSE); - - ctrl_ssao->setEnabled(FALSE); - ctrl_ssao->setValue(FALSE); - - ctrl_dof->setEnabled(FALSE); - ctrl_dof->setValue(FALSE); - - ctrl_deferred->setEnabled(FALSE); - ctrl_deferred->setValue(FALSE); - } - - // disabled deferred SSAO - if (!LLFeatureManager::getInstance()->isFeatureAvailable("RenderDeferredSSAO")) - { - ctrl_ssao->setEnabled(FALSE); - ctrl_ssao->setValue(FALSE); - } - - // disabled deferred shadows - if (!LLFeatureManager::getInstance()->isFeatureAvailable("RenderShadowDetail")) - { - ctrl_shadows->setEnabled(FALSE); - ctrl_shadows->setValue(0); - shadows_text->setEnabled(FALSE); - } - - // disabled reflections - if (!LLFeatureManager::getInstance()->isFeatureAvailable("RenderReflectionDetail")) - { - ctrl_reflections->setEnabled(FALSE); - ctrl_reflections->setValue(FALSE); - reflections_text->setEnabled(FALSE); - } - - // disabled av - if (!LLFeatureManager::getInstance()->isFeatureAvailable("RenderAvatarVP")) - { - ctrl_avatar_vp->setEnabled(FALSE); - ctrl_avatar_vp->setValue(FALSE); - - ctrl_avatar_cloth->setEnabled(FALSE); - ctrl_avatar_cloth->setValue(FALSE); - - //deferred needs AvatarVP, disable deferred - ctrl_shadows->setEnabled(FALSE); - ctrl_shadows->setValue(0); - shadows_text->setEnabled(FALSE); - - ctrl_ssao->setEnabled(FALSE); - ctrl_ssao->setValue(FALSE); - - ctrl_dof->setEnabled(FALSE); - ctrl_dof->setValue(FALSE); - - ctrl_deferred->setEnabled(FALSE); - ctrl_deferred->setValue(FALSE); - } - - // disabled cloth - if (!LLFeatureManager::getInstance()->isFeatureAvailable("RenderAvatarCloth")) - { - ctrl_avatar_cloth->setEnabled(FALSE); - ctrl_avatar_cloth->setValue(FALSE); - } -} - void LLFloaterPreference::refresh() { LLPanel::refresh(); @@ -2730,32 +2481,6 @@ void LLFloaterPreference::refresh() updateClickActionViews(); } -void LLFloaterPreferenceGraphicsAdvanced::refresh() -{ - getChild("fsaa")->setValue((LLSD::Integer) gSavedSettings.getU32("RenderFSAASamples")); - - // sliders and their text boxes - // mPostProcess = gSavedSettings.getS32("RenderGlowResolutionPow"); - // slider text boxes - updateSliderText(getChild("ObjectMeshDetail", true), getChild("ObjectMeshDetailText", true)); - updateSliderText(getChild("FlexibleMeshDetail", true), getChild("FlexibleMeshDetailText", true)); - updateSliderText(getChild("TreeMeshDetail", true), getChild("TreeMeshDetailText", true)); - updateSliderText(getChild("AvatarMeshDetail", true), getChild("AvatarMeshDetailText", true)); - updateSliderText(getChild("AvatarPhysicsDetail", true), getChild("AvatarPhysicsDetailText", true)); - updateSliderText(getChild("TerrainMeshDetail", true), getChild("TerrainMeshDetailText", true)); - updateSliderText(getChild("RenderPostProcess", true), getChild("PostProcessText", true)); - updateSliderText(getChild("SkyMeshDetail", true), getChild("SkyMeshDetailText", true)); - updateSliderText(getChild("TerrainDetail", true), getChild("TerrainDetailText", true)); - LLAvatarComplexityControls::setIndirectControls(); - setMaxNonImpostorsText( - gSavedSettings.getU32("RenderAvatarMaxNonImpostors"), - getChild("IndirectMaxNonImpostorsText", true)); - LLAvatarComplexityControls::setText( - gSavedSettings.getU32("RenderAvatarMaxComplexity"), - getChild("IndirectMaxComplexityText", true)); - refreshEnabledState(); -} - void LLFloaterPreference::onCommitWindowedMode() { refresh(); @@ -2953,12 +2678,13 @@ bool LLFloaterPreference::moveTranscriptsAndLog() return true; } -// Show email address in preferences (FIRE-1071) -//void LLFloaterPreference::setPersonalInfo(const std::string& visibility, bool im_via_email, bool is_verified_email) -void LLFloaterPreference::setPersonalInfo(const std::string& visibility, bool im_via_email, bool is_verified_email, const std::string& email) +// Show email address in preferences (FIRE-1071) and keep it for OpenSim +//void LLFloaterPreference::setPersonalInfo(const std::string& visibility) +void LLFloaterPreference::setPersonalInfo(const std::string& visibility, bool im_via_email, const std::string& email) // Show email address in preferences (FIRE-1071) { mGotPersonalInfo = true; + // Keep this for OpenSim mOriginalIMViaEmail = im_via_email; mDirectoryVisibility = visibility; @@ -2981,16 +2707,6 @@ void LLFloaterPreference::setPersonalInfo(const std::string& visibility, bool im getChildView("friends_online_notify_checkbox")->setEnabled(TRUE); getChild("online_visibility")->setValue(mOriginalHideOnlineStatus); getChild("online_visibility")->setLabelArg("[DIR_VIS]", mDirectoryVisibility); - getChildView("send_im_to_email")->setEnabled(is_verified_email); - - std::string tooltip; - if (!is_verified_email) - tooltip = getString("email_unverified_tooltip"); - - getChildView("send_im_to_email")->setToolTip(tooltip); - - // *TODO: Show or hide verify email text here based on is_verified_email - getChild("send_im_to_email")->setValue(im_via_email); getChildView("favorites_on_login_check")->setEnabled(TRUE); //getChildView("log_path_button")->setEnabled(TRUE); // Does not exist as of 12-09-2014 getChildView("chat_font_size")->setEnabled(TRUE); @@ -3007,15 +2723,29 @@ void LLFloaterPreference::setPersonalInfo(const std::string& visibility, bool im { getChildView("reset_logpath")->setEnabled(TRUE); } - // Show email address in preferences (FIRE-1071) - std::string display_email(email); - if(display_email.size() > 30) + // Keep this for OpenSim + if (LLGridManager::instance().isInSecondLife()) { - display_email.resize(30); - display_email += "..."; + childSetEnabled("email_settings", true); + childSetVisible("email_settings", true); } - getChild("send_im_to_email")->setLabelArg("[EMAIL]", display_email); - // Show email address in preferences (FIRE-1071) + else + { + std::string display_email(email); + if (display_email.size() > 30) + { + display_email.resize(30); + display_email += "..."; + } + + LLCheckBoxCtrl* send_im_to_email = getChild("send_im_to_email"); + send_im_to_email->setVisible(TRUE); + send_im_to_email->setEnabled(TRUE); + send_im_to_email->setValue(im_via_email); + send_im_to_email->setLabelArg("[EMAIL]", display_email); + } + childSetVisible("email_settings_login_to_change", false); + // // FIRE-420: Show end of last conversation in history getChildView("LogShowHistory")->setEnabled(TRUE); @@ -3119,64 +2849,7 @@ void LLFloaterPreference::updateMaxComplexityLabel(const LLSD& newvalue) } // -void LLFloaterPreferenceGraphicsAdvanced::updateSliderText(LLSliderCtrl* ctrl, LLTextBox* text_box) -{ - if (text_box == NULL || ctrl== NULL) - return; - - // get range and points when text should change - F32 value = (F32)ctrl->getValue().asReal(); - F32 min = ctrl->getMinValue(); - F32 max = ctrl->getMaxValue(); - F32 range = max - min; - llassert(range > 0); - F32 midPoint = min + range / 3.0f; - F32 highPoint = min + (2.0f * range / 3.0f); - - // choose the right text - if (value < midPoint) - { - text_box->setText(LLTrans::getString("GraphicsQualityLow")); - } - else if (value < highPoint) - { - text_box->setText(LLTrans::getString("GraphicsQualityMid")); - } - else - { - text_box->setText(LLTrans::getString("GraphicsQualityHigh")); - } -} - -void LLFloaterPreferenceGraphicsAdvanced::updateMaxNonImpostors() -{ - // Called when the IndirectMaxNonImpostors control changes - // Responsible for fixing the slider label (IndirectMaxNonImpostorsText) and setting RenderAvatarMaxNonImpostors - LLSliderCtrl* ctrl = getChild("IndirectMaxNonImpostors",true); - U32 value = ctrl->getValue().asInteger(); - - if (0 == value || LLVOAvatar::NON_IMPOSTORS_MAX_SLIDER <= value) - { - value=0; - } - gSavedSettings.setU32("RenderAvatarMaxNonImpostors", value); - LLVOAvatar::updateImpostorRendering(value); // make it effective immediately - setMaxNonImpostorsText(value, getChild("IndirectMaxNonImpostorsText")); -} - -void LLFloaterPreferenceGraphicsAdvanced::setMaxNonImpostorsText(U32 value, LLTextBox* text_box) -{ - if (0 == value) - { - text_box->setText(LLTrans::getString("no_limit")); - } - else - { - text_box->setText(llformat("%d", value)); - } -} - -void LLAvatarComplexityControls::updateMax(LLSliderCtrl* slider, LLTextBox* value_label) +void LLAvatarComplexityControls::updateMax(LLSliderCtrl* slider, LLTextBox* value_label, bool short_val) { // Called when the IndirectMaxComplexity control changes // Responsible for fixing the slider label (IndirectMaxComplexityText) and setting RenderAvatarMaxComplexity @@ -3198,10 +2871,10 @@ void LLAvatarComplexityControls::updateMax(LLSliderCtrl* slider, LLTextBox* valu } gSavedSettings.setU32("RenderAvatarMaxComplexity", (U32)max_arc); - setText(max_arc, value_label); + setText(max_arc, value_label, short_val); } -void LLAvatarComplexityControls::setText(U32 value, LLTextBox* text_box) +void LLAvatarComplexityControls::setText(U32 value, LLTextBox* text_box, bool short_val) { if (0 == value) { @@ -3210,28 +2883,45 @@ void LLAvatarComplexityControls::setText(U32 value, LLTextBox* text_box) else { // Proper number formatting with delimiter - //text_box->setText(llformat("%d", value)); + //std::string text_value = short_val ? llformat("%d", value / 1000) : llformat("%d", value); + //text_box->setText(text_value); std::string output_string; LLLocale locale(""); - LLResMgr::getInstance()->getIntegerString(output_string, value); + LLResMgr::getInstance()->getIntegerString(output_string, (short_val ? value / 1000 : value)); text_box->setText(output_string); } } +// redner time controls +void LLAvatarComplexityControls::updateMaxRenderTime(LLSliderCtrl* slider, LLTextBox* value_label, bool short_val) +{ + setRenderTimeText((F32)(FSPerfStats::renderAvatarMaxART_ns/1000), value_label, short_val); +} + +void LLAvatarComplexityControls::setRenderTimeText(F32 value, LLTextBox* text_box, bool short_val) +{ + if (0 == value) + { + text_box->setText(LLTrans::getString("no_limit")); + } + else + { + text_box->setText(llformat("%.0f", value)); + } +} +// void LLFloaterPreference::updateMaxComplexity() { // Called when the IndirectMaxComplexity control changes LLAvatarComplexityControls::updateMax( getChild("IndirectMaxComplexity"), getChild("IndirectMaxComplexityText")); +} - LLFloaterPreferenceGraphicsAdvanced* floater_graphics_advanced = LLFloaterReg::findTypedInstance("prefs_graphics_advanced"); - if (floater_graphics_advanced) - { - LLAvatarComplexityControls::updateMax( - floater_graphics_advanced->getChild("IndirectMaxComplexity"), - floater_graphics_advanced->getChild("IndirectMaxComplexityText")); - } +void LLFloaterPreference::updateComplexityText() +{ + LLAvatarComplexityControls::setText(gSavedSettings.getU32("RenderAvatarMaxComplexity"), + getChild("IndirectMaxComplexityText", true)); } bool LLFloaterPreference::loadFromFilename(const std::string& filename, std::map &label_map) @@ -3273,22 +2963,6 @@ bool LLFloaterPreference::loadFromFilename(const std::string& filename, std::map return true; } -void LLFloaterPreferenceGraphicsAdvanced::updateMaxComplexity() -{ - // Called when the IndirectMaxComplexity control changes - LLAvatarComplexityControls::updateMax( - getChild("IndirectMaxComplexity"), - getChild("IndirectMaxComplexityText")); - - LLFloaterPreference* floater_preferences = LLFloaterReg::findTypedInstance("preferences"); - if (floater_preferences) - { - LLAvatarComplexityControls::updateMax( - floater_preferences->getChild("IndirectMaxComplexity"), - floater_preferences->getChild("IndirectMaxComplexityText")); - } -} - void LLFloaterPreference::onChangeMaturity() { U8 sim_access = gSavedSettings.getU32("PreferredMaturity"); @@ -3561,6 +3235,11 @@ void LLFloaterPreference::updateClickActionViews() getChild("double_click_action_combo")->setValue(dbl_click_to_teleport ? 2 : (int)dbl_click_to_walk); } +void LLFloaterPreference::updateSearchableItems() +{ + mSearchDataDirty = true; +} + void LLFloaterPreference::applyUIColor(LLUICtrl* ctrl, const LLSD& param) { LLUIColorTable::instance().setColor(param.asString(), LLColor4(ctrl->getValue())); @@ -3835,7 +3514,7 @@ BOOL LLPanelPreference::postBuild() //////////////////////PanelSetup /////////////////// // FIRE-6340, FIRE-6567 - Setting Bandwidth issues - //if (hasChild("max_bandwidth"), TRUE) + //if (hasChild("max_bandwidth", TRUE)) //{ // mBandWidthUpdater = new LLPanelPreference::Updater(boost::bind(&handleBandwidthChanged, _1), BANDWIDTH_UPDATER_TIMEOUT); // gSavedSettings.getControl("ThrottleBandwidthKBPS")->getSignal()->connect(boost::bind(&LLPanelPreference::Updater::update, mBandWidthUpdater, _2)); @@ -4646,10 +4325,19 @@ void LLPanelPreferenceControls::populateControlTable() filename = "control_table_contents_columns_basic.xml"; break; default: - // Either unknown mode or MODE_SAVED_SETTINGS - // It doesn't have UI or actual settings yet - LL_INFOS() << "Unimplemented mode" << LL_ENDL; - return; + { + // Either unknown mode or MODE_SAVED_SETTINGS + // It doesn't have UI or actual settings yet + LL_WARNS() << "Unimplemented mode" << LL_ENDL; + + // Searchable columns were removed, mark searchables for an update + LLFloaterPreference* instance = LLFloaterReg::findTypedInstance("preferences"); + if (instance) + { + instance->updateSearchableItems(); + } + return; + } } addControlTableColumns(filename); @@ -4680,8 +4368,15 @@ void LLPanelPreferenceControls::populateControlTable() } else { - LL_INFOS() << "Unimplemented mode" << LL_ENDL; - return; + LL_WARNS() << "Unimplemented mode" << LL_ENDL; + } + + // Searchable columns were removed and readded, mark searchables for an update + // Note: at the moment tables/lists lack proper llsearchableui support + LLFloaterPreference* instance = LLFloaterReg::findTypedInstance("preferences"); + if (instance) + { + instance->updateSearchableItems(); } } @@ -4924,7 +4619,12 @@ void LLPanelPreferenceControls::setKeyBind(const std::string &control, EMouseCli break; } } - mConflictHandler[mode].registerControl(control, index, click, key, mask, true); + // At the moment 'ignore_mask' mask is mostly ignored, a placeholder + // Todo: implement it since it's preferable for things like teleport to match + // mask exactly but for things like running to ignore additional masks + // Ideally this needs representation in keybindings UI + bool ignore_mask = true; + mConflictHandler[mode].registerControl(control, index, click, key, mask, ignore_mask); } else if (!set) { @@ -5050,18 +4750,6 @@ void LLPanelPreferenceControls::onCancelKeyBind() pControlsTable->deselectAllItems(); } -LLFloaterPreferenceGraphicsAdvanced::LLFloaterPreferenceGraphicsAdvanced(const LLSD& key) - : LLFloater(key) -{ - mCommitCallbackRegistrar.add("Pref.RenderOptionUpdate", boost::bind(&LLFloaterPreferenceGraphicsAdvanced::onRenderOptionEnable, this)); - mCommitCallbackRegistrar.add("Pref.UpdateIndirectMaxNonImpostors", boost::bind(&LLFloaterPreferenceGraphicsAdvanced::updateMaxNonImpostors,this)); - mCommitCallbackRegistrar.add("Pref.UpdateIndirectMaxComplexity", boost::bind(&LLFloaterPreferenceGraphicsAdvanced::updateMaxComplexity,this)); -} - -LLFloaterPreferenceGraphicsAdvanced::~LLFloaterPreferenceGraphicsAdvanced() -{ -} - LLFloaterPreferenceProxy::LLFloaterPreferenceProxy(const LLSD& key) : LLFloater(key), mSocksSettingsDirty(false) @@ -5071,41 +4759,6 @@ LLFloaterPreferenceProxy::LLFloaterPreferenceProxy(const LLSD& key) mCommitCallbackRegistrar.add("Proxy.Change", boost::bind(&LLFloaterPreferenceProxy::onChangeSocksSettings, this)); } -BOOL LLFloaterPreferenceGraphicsAdvanced::postBuild() -{ - // Don't do this on Mac as their braindead GL versioning - // sets this when 8x and 16x are indeed available - // -#if !LL_DARWIN - if (gGLManager.mIsIntel || gGLManager.mGLVersion < 3.f) - { //remove FSAA settings above "4x" - LLComboBox* combo = getChild("fsaa"); - combo->remove("8x"); - combo->remove("16x"); - } - - LLCheckBoxCtrl *use_HiDPI = getChild("use HiDPI"); - use_HiDPI->setVisible(FALSE); -#endif - - return TRUE; -} - -void LLFloaterPreferenceGraphicsAdvanced::onOpen(const LLSD& key) -{ - refresh(); -} - -void LLFloaterPreferenceGraphicsAdvanced::onClickCloseBtn(bool app_quitting) -{ - LLFloaterPreference* instance = LLFloaterReg::findTypedInstance("preferences"); - if (instance) - { - instance->cancel(); - } - updateMaxComplexity(); -} - LLFloaterPreferenceProxy::~LLFloaterPreferenceProxy() { } @@ -5299,6 +4952,12 @@ void LLFloaterPreference::onUpdateFilterTerm(bool force) if( !mSearchData || (mSearchData->mLastFilter == seachValue && !force)) return; + if (mSearchDataDirty) + { + // Data exists, but is obsolete, regenerate + collectSearchableItems(); + } + mSearchData->mLastFilter = seachValue; if( !mSearchData->mRootTab ) @@ -5396,6 +5055,7 @@ void LLFloaterPreference::collectSearchableItems() collectChildren( this, ll::prefs::PanelDataPtr(), pRootTabcontainer ); } + mSearchDataDirty = false; } // [SL:KB] - Patch: Viewer-CrashReporting | Checked: 2010-11-16 (Catznip-2.6.0a) | Added: Catznip-2.4.0b diff --git a/indra/newview/llfloaterpreference.h b/indra/newview/llfloaterpreference.h index 5722332a13..70b86ede01 100644 --- a/indra/newview/llfloaterpreference.h +++ b/indra/newview/llfloaterpreference.h @@ -97,9 +97,9 @@ public: /*virtual*/ void changed(const LLUUID& session_id, U32 mask) {}; // static data update, called from message handler - // Show email address in preferences (FIRE-1071) - //static void updateUserInfo(const std::string& visibility, bool im_via_email, bool is_verified_email); - static void updateUserInfo(const std::string& visibility, bool im_via_email, bool is_verified_email, const std::string& email); + // Show email address in preferences (FIRE-1071) and keep for OpenSim + //static void updateUserInfo(const std::string& visibility); + static void updateUserInfo(const std::string& visibility, bool im_via_email, const std::string& email); // refresh all the graphics preferences menus static void refreshEnabledGraphics(); @@ -119,13 +119,12 @@ public: void getControlNames(std::vector& names); // updates click/double-click action controls depending on values from settings.xml void updateClickActionViews(); + void updateSearchableItems(); -// Make onBtnOk() public for settings backup panel -//protected: - void onBtnOK(const LLSD& userdata); -protected: -// - void onBtnCancel(const LLSD& userdata); + void onBtnOK(const LLSD& userdata); + void onBtnCancel(const LLSD& userdata); + +protected: //void onClickClearCache(); // Clear viewer texture cache, file cache on next startup // AO: was protected, moved to public void onClickBrowserClearCache(); // Clear web history and caches as well as viewer caches above @@ -229,9 +228,9 @@ public: //[FIX FIRE-2765 : SJ] Making sure Reset button resets works void onClickResetLogPath(); void enableHistory(); - // Show email address in preferences (FIRE-1071) - //void setPersonalInfo(const std::string& visibility, bool im_via_email, bool is_verified_email); - void setPersonalInfo(const std::string& visibility, bool im_via_email, bool is_verified_email, const std::string& email); + // Show email address in preferences (FIRE-1071) and keep for OpenSim + //void setPersonalInfo(const std::string& visibility); + void setPersonalInfo(const std::string& visibility, bool im_via_email, const std::string& email); // Show email address in preferences (FIRE-1071) void refreshEnabledState(); // Improved graphics preferences @@ -301,11 +300,13 @@ private: void onDeleteTranscriptsResponse(const LLSD& notification, const LLSD& response); void updateDeleteTranscriptsButton(); void updateMaxComplexity(); + void updateComplexityText(); static bool loadFromFilename(const std::string& filename, std::map &label_map); static std::string sSkin; notifications_map mNotificationOptions; bool mGotPersonalInfo; + // Keep it for OpenSim bool mOriginalIMViaEmail; bool mLanguageChanged; bool mAvatarDataInitialized; @@ -320,6 +321,9 @@ private: LLSearchEditor *mFilterEdit; std::unique_ptr< ll::prefs::SearchData > mSearchData; + bool mSearchDataDirty; + + boost::signals2::connection mComplexityChangedSignal; void onUpdateFilterTerm( bool force = false ); void collectSearchableItems(); @@ -473,37 +477,15 @@ private: S32 mEditingMode; }; -class LLFloaterPreferenceGraphicsAdvanced : public LLFloater -{ - public: - LLFloaterPreferenceGraphicsAdvanced(const LLSD& key); - ~LLFloaterPreferenceGraphicsAdvanced(); - /*virtual*/ BOOL postBuild(); - void onOpen(const LLSD& key); - void onClickCloseBtn(bool app_quitting); - void disableUnavailableSettings(); - void refreshEnabledGraphics(); - void refreshEnabledState(); - void updateSliderText(LLSliderCtrl* ctrl, LLTextBox* text_box); - void updateMaxNonImpostors(); - void setMaxNonImpostorsText(U32 value, LLTextBox* text_box); - void updateMaxComplexity(); - void setMaxComplexityText(U32 value, LLTextBox* text_box); - static void setIndirectControls(); - static void setIndirectMaxNonImpostors(); - static void setIndirectMaxArc(); - void refresh(); - // callback for when client modifies a render option - void onRenderOptionEnable(); - void onAdvancedAtmosphericsEnable(); - LOG_CLASS(LLFloaterPreferenceGraphicsAdvanced); -}; - class LLAvatarComplexityControls { public: - static void updateMax(LLSliderCtrl* slider, LLTextBox* value_label); - static void setText(U32 value, LLTextBox* text_box); + static void updateMax(LLSliderCtrl* slider, LLTextBox* value_label, bool short_val = false); + static void setText(U32 value, LLTextBox* text_box, bool short_val = false); + // for render time support + static void updateMaxRenderTime(LLSliderCtrl* slider, LLTextBox* value_label, bool short_val = false); + static void setRenderTimeText(F32 value, LLTextBox* text_box, bool short_val = false); + // static void setIndirectControls(); static void setIndirectMaxNonImpostors(); static void setIndirectMaxArc(); diff --git a/indra/newview/llfloaterpreferencesgraphicsadvanced.cpp b/indra/newview/llfloaterpreferencesgraphicsadvanced.cpp new file mode 100644 index 0000000000..653d26ff30 --- /dev/null +++ b/indra/newview/llfloaterpreferencesgraphicsadvanced.cpp @@ -0,0 +1,474 @@ +/** + * @file llfloaterpreferencesgraphicsadvanced.cpp + * @brief floater for adjusting camera position + * + * $LicenseInfo:firstyear=2021&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2021, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" +#include "llfloaterpreferencesgraphicsadvanced.h" + +#include "llcheckboxctrl.h" +#include "llcombobox.h" +#include "llfeaturemanager.h" +#include "llfloaterpreference.h" +#include "llfloaterreg.h" +#include "llsliderctrl.h" +#include "lltextbox.h" +#include "lltrans.h" +#include "llviewershadermgr.h" +#include "llviewertexturelist.h" +#include "llvoavatar.h" +#include "pipeline.h" +#include "llviewercontrol.h" +#include "rlvactions.h" + +LLFloaterPreferenceGraphicsAdvanced::LLFloaterPreferenceGraphicsAdvanced(const LLSD& key) + : LLFloater(key) +{ + mCommitCallbackRegistrar.add("Pref.RenderOptionUpdate", boost::bind(&LLFloaterPreferenceGraphicsAdvanced::onRenderOptionEnable, this)); + mCommitCallbackRegistrar.add("Pref.UpdateIndirectMaxNonImpostors", boost::bind(&LLFloaterPreferenceGraphicsAdvanced::updateMaxNonImpostors,this)); + mCommitCallbackRegistrar.add("Pref.UpdateIndirectMaxComplexity", boost::bind(&LLFloaterPreferenceGraphicsAdvanced::updateMaxComplexity,this)); + + mCommitCallbackRegistrar.add("Pref.Cancel", boost::bind(&LLFloaterPreferenceGraphicsAdvanced::onBtnCancel, this, _2)); + mCommitCallbackRegistrar.add("Pref.OK", boost::bind(&LLFloaterPreferenceGraphicsAdvanced::onBtnOK, this, _2)); +} + +LLFloaterPreferenceGraphicsAdvanced::~LLFloaterPreferenceGraphicsAdvanced() +{ + mComplexityChangedSignal.disconnect(); +} + +BOOL LLFloaterPreferenceGraphicsAdvanced::postBuild() +{ + // Don't do this on Mac as their braindead GL versioning + // sets this when 8x and 16x are indeed available + // +#if !LL_DARWIN + if (gGLManager.mIsIntel || gGLManager.mGLVersion < 3.f) + { //remove FSAA settings above "4x" + LLComboBox* combo = getChild("fsaa"); + combo->remove("8x"); + combo->remove("16x"); + } + + LLCheckBoxCtrl *use_HiDPI = getChild("use HiDPI"); + use_HiDPI->setVisible(FALSE); +#endif + + mComplexityChangedSignal = gSavedSettings.getControl("RenderAvatarMaxComplexity")->getCommitSignal()->connect(boost::bind(&LLFloaterPreferenceGraphicsAdvanced::updateComplexityText, this)); + + return TRUE; +} + +void LLFloaterPreferenceGraphicsAdvanced::onOpen(const LLSD& key) +{ + refresh(); +} + +void LLFloaterPreferenceGraphicsAdvanced::onClickCloseBtn(bool app_quitting) +{ + LLFloaterPreference* instance = LLFloaterReg::findTypedInstance("preferences"); + if (instance) + { + instance->cancel(); + } + updateMaxComplexity(); +} + +void LLFloaterPreferenceGraphicsAdvanced::onRenderOptionEnable() +{ + LLFloaterPreference* instance = LLFloaterReg::findTypedInstance("preferences"); + if (instance) + { + instance->refresh(); + } + + refreshEnabledGraphics(); +} + +void LLFloaterPreferenceGraphicsAdvanced::onAdvancedAtmosphericsEnable() +{ + LLFloaterPreference* instance = LLFloaterReg::findTypedInstance("preferences"); + if (instance) + { + instance->refresh(); + } + + refreshEnabledGraphics(); +} + +void LLFloaterPreferenceGraphicsAdvanced::refresh() +{ + getChild("fsaa")->setValue((LLSD::Integer) gSavedSettings.getU32("RenderFSAASamples")); + + // sliders and their text boxes + // mPostProcess = gSavedSettings.getS32("RenderGlowResolutionPow"); + // slider text boxes + updateSliderText(getChild("ObjectMeshDetail", true), getChild("ObjectMeshDetailText", true)); + updateSliderText(getChild("FlexibleMeshDetail", true), getChild("FlexibleMeshDetailText", true)); + updateSliderText(getChild("TreeMeshDetail", true), getChild("TreeMeshDetailText", true)); + updateSliderText(getChild("AvatarMeshDetail", true), getChild("AvatarMeshDetailText", true)); + updateSliderText(getChild("AvatarPhysicsDetail", true), getChild("AvatarPhysicsDetailText", true)); + updateSliderText(getChild("TerrainMeshDetail", true), getChild("TerrainMeshDetailText", true)); + updateSliderText(getChild("RenderPostProcess", true), getChild("PostProcessText", true)); + updateSliderText(getChild("SkyMeshDetail", true), getChild("SkyMeshDetailText", true)); + updateSliderText(getChild("TerrainDetail", true), getChild("TerrainDetailText", true)); + LLAvatarComplexityControls::setIndirectControls(); + setMaxNonImpostorsText( + gSavedSettings.getU32("RenderAvatarMaxNonImpostors"), + getChild("IndirectMaxNonImpostorsText", true)); + LLAvatarComplexityControls::setText( + gSavedSettings.getU32("RenderAvatarMaxComplexity"), + getChild("IndirectMaxComplexityText", true)); + refreshEnabledState(); +} + +void LLFloaterPreferenceGraphicsAdvanced::refreshEnabledGraphics() +{ + refreshEnabledState(); +} + +void LLFloaterPreferenceGraphicsAdvanced::updateMaxComplexity() +{ + // Called when the IndirectMaxComplexity control changes + LLAvatarComplexityControls::updateMax( + getChild("IndirectMaxComplexity"), + getChild("IndirectMaxComplexityText")); +} + +void LLFloaterPreferenceGraphicsAdvanced::updateComplexityText() +{ + LLAvatarComplexityControls::setText(gSavedSettings.getU32("RenderAvatarMaxComplexity"), + getChild("IndirectMaxComplexityText", true)); +} + +void LLFloaterPreferenceGraphicsAdvanced::updateSliderText(LLSliderCtrl* ctrl, LLTextBox* text_box) +{ + if (text_box == NULL || ctrl== NULL) + return; + + // get range and points when text should change + F32 value = (F32)ctrl->getValue().asReal(); + F32 min = ctrl->getMinValue(); + F32 max = ctrl->getMaxValue(); + F32 range = max - min; + llassert(range > 0); + F32 midPoint = min + range / 3.0f; + F32 highPoint = min + (2.0f * range / 3.0f); + + // choose the right text + if (value < midPoint) + { + text_box->setText(LLTrans::getString("GraphicsQualityLow")); + } + else if (value < highPoint) + { + text_box->setText(LLTrans::getString("GraphicsQualityMid")); + } + else + { + text_box->setText(LLTrans::getString("GraphicsQualityHigh")); + } +} + +void LLFloaterPreferenceGraphicsAdvanced::updateMaxNonImpostors() +{ + // Called when the IndirectMaxNonImpostors control changes + // Responsible for fixing the slider label (IndirectMaxNonImpostorsText) and setting RenderAvatarMaxNonImpostors + LLSliderCtrl* ctrl = getChild("IndirectMaxNonImpostors",true); + U32 value = ctrl->getValue().asInteger(); + + if (0 == value || LLVOAvatar::NON_IMPOSTORS_MAX_SLIDER <= value) + { + value=0; + } + gSavedSettings.setU32("RenderAvatarMaxNonImpostors", value); + LLVOAvatar::updateImpostorRendering(value); // make it effective immediately + setMaxNonImpostorsText(value, getChild("IndirectMaxNonImpostorsText")); +} + +void LLFloaterPreferenceGraphicsAdvanced::setMaxNonImpostorsText(U32 value, LLTextBox* text_box) +{ + if (0 == value) + { + text_box->setText(LLTrans::getString("no_limit")); + } + else + { + text_box->setText(llformat("%d", value)); + } +} + +void LLFloaterPreferenceGraphicsAdvanced::disableUnavailableSettings() +{ + LLComboBox* ctrl_reflections = getChild("Reflections"); + LLTextBox* reflections_text = getChild("ReflectionsText"); + LLCheckBoxCtrl* ctrl_avatar_vp = getChild("AvatarVertexProgram"); + LLCheckBoxCtrl* ctrl_avatar_cloth = getChild("AvatarCloth"); + LLCheckBoxCtrl* ctrl_wind_light = getChild("WindLightUseAtmosShaders"); + LLCheckBoxCtrl* ctrl_deferred = getChild("UseLightShaders"); + LLComboBox* ctrl_shadows = getChild("ShadowDetail"); + LLTextBox* shadows_text = getChild("RenderShadowDetailText"); + LLCheckBoxCtrl* ctrl_ssao = getChild("UseSSAO"); + LLCheckBoxCtrl* ctrl_dof = getChild("UseDoF"); + LLSliderCtrl* sky = getChild("SkyMeshDetail"); + LLTextBox* sky_text = getChild("SkyMeshDetailText"); + + // disabled windlight + if (!LLFeatureManager::getInstance()->isFeatureAvailable("WindLightUseAtmosShaders")) + { + ctrl_wind_light->setEnabled(FALSE); + ctrl_wind_light->setValue(FALSE); + + sky->setEnabled(FALSE); + sky_text->setEnabled(FALSE); + + //deferred needs windlight, disable deferred + ctrl_shadows->setEnabled(FALSE); + ctrl_shadows->setValue(0); + shadows_text->setEnabled(FALSE); + + ctrl_ssao->setEnabled(FALSE); + ctrl_ssao->setValue(FALSE); + + ctrl_dof->setEnabled(FALSE); + ctrl_dof->setValue(FALSE); + + ctrl_deferred->setEnabled(FALSE); + ctrl_deferred->setValue(FALSE); + } + + // disabled deferred + if (!LLFeatureManager::getInstance()->isFeatureAvailable("RenderDeferred") || + !gGLManager.mHasFramebufferObject) + { + ctrl_shadows->setEnabled(FALSE); + ctrl_shadows->setValue(0); + shadows_text->setEnabled(FALSE); + + ctrl_ssao->setEnabled(FALSE); + ctrl_ssao->setValue(FALSE); + + ctrl_dof->setEnabled(FALSE); + ctrl_dof->setValue(FALSE); + + ctrl_deferred->setEnabled(FALSE); + ctrl_deferred->setValue(FALSE); + } + + // disabled deferred SSAO + if (!LLFeatureManager::getInstance()->isFeatureAvailable("RenderDeferredSSAO")) + { + ctrl_ssao->setEnabled(FALSE); + ctrl_ssao->setValue(FALSE); + } + + // disabled deferred shadows + if (!LLFeatureManager::getInstance()->isFeatureAvailable("RenderShadowDetail")) + { + ctrl_shadows->setEnabled(FALSE); + ctrl_shadows->setValue(0); + shadows_text->setEnabled(FALSE); + } + + // disabled reflections + if (!LLFeatureManager::getInstance()->isFeatureAvailable("RenderReflectionDetail")) + { + ctrl_reflections->setEnabled(FALSE); + ctrl_reflections->setValue(FALSE); + reflections_text->setEnabled(FALSE); + } + + // disabled av + if (!LLFeatureManager::getInstance()->isFeatureAvailable("RenderAvatarVP")) + { + ctrl_avatar_vp->setEnabled(FALSE); + ctrl_avatar_vp->setValue(FALSE); + + ctrl_avatar_cloth->setEnabled(FALSE); + ctrl_avatar_cloth->setValue(FALSE); + + //deferred needs AvatarVP, disable deferred + ctrl_shadows->setEnabled(FALSE); + ctrl_shadows->setValue(0); + shadows_text->setEnabled(FALSE); + + ctrl_ssao->setEnabled(FALSE); + ctrl_ssao->setValue(FALSE); + + ctrl_dof->setEnabled(FALSE); + ctrl_dof->setValue(FALSE); + + ctrl_deferred->setEnabled(FALSE); + ctrl_deferred->setValue(FALSE); + } + + // disabled cloth + if (!LLFeatureManager::getInstance()->isFeatureAvailable("RenderAvatarCloth")) + { + ctrl_avatar_cloth->setEnabled(FALSE); + ctrl_avatar_cloth->setValue(FALSE); + } +} + +void LLFloaterPreferenceGraphicsAdvanced::refreshEnabledState() +{ + LLComboBox* ctrl_reflections = getChild("Reflections"); + LLTextBox* reflections_text = getChild("ReflectionsText"); + + // Reflections + BOOL reflections = gGLManager.mHasCubeMap && LLCubeMap::sUseCubeMaps; + ctrl_reflections->setEnabled(reflections); + reflections_text->setEnabled(reflections); + + // Transparent Water + LLCheckBoxCtrl* transparent_water_ctrl = getChild("TransparentWater"); + + // Bump & Shiny + LLCheckBoxCtrl* bumpshiny_ctrl = getChild("BumpShiny"); + bool bumpshiny = gGLManager.mHasCubeMap && LLCubeMap::sUseCubeMaps && LLFeatureManager::getInstance()->isFeatureAvailable("RenderObjectBump"); + bumpshiny_ctrl->setEnabled(bumpshiny ? TRUE : FALSE); + + // Avatar Mode + // Enable Avatar Shaders + LLCheckBoxCtrl* ctrl_avatar_vp = getChild("AvatarVertexProgram"); + // Avatar Render Mode + LLCheckBoxCtrl* ctrl_avatar_cloth = getChild("AvatarCloth"); + + bool avatar_vp_enabled = LLFeatureManager::getInstance()->isFeatureAvailable("RenderAvatarVP"); + if (LLViewerShaderMgr::sInitialized) + { + S32 max_avatar_shader = LLViewerShaderMgr::instance()->mMaxAvatarShaderLevel; + avatar_vp_enabled = (max_avatar_shader > 0) ? TRUE : FALSE; + } + + ctrl_avatar_vp->setEnabled(avatar_vp_enabled); + + if (gSavedSettings.getBOOL("RenderAvatarVP") == FALSE) + { + ctrl_avatar_cloth->setEnabled(FALSE); + } + else + { + ctrl_avatar_cloth->setEnabled(TRUE); + } + + /* remove orphaned code left over from EEP + // Vertex Shaders, Global Shader Enable + // SL-12594 Basic shaders are always enabled. DJH TODO clean up now-orphaned state handling code + LLSliderCtrl* terrain_detail = getChild("TerrainDetail"); // can be linked with control var + LLTextBox* terrain_text = getChild("TerrainDetailText"); + + terrain_detail->setEnabled(FALSE); + terrain_text->setEnabled(FALSE); + */ + + // WindLight + LLCheckBoxCtrl* ctrl_wind_light = getChild("WindLightUseAtmosShaders"); + LLSliderCtrl* sky = getChild("SkyMeshDetail"); + LLTextBox* sky_text = getChild("SkyMeshDetailText"); +// [RLVa:KB] - Checked: 2010-03-18 (RLVa-1.2.0a) | Modified: RLVa-0.2.0a + // "Atmospheric Shaders" can't be disabled - but can be enabled - under @setenv=n + ctrl_wind_light->setEnabled((RlvActions::canChangeEnvironment()) || (!gSavedSettings.getBOOL("WindLightUseAtmosShaders"))); +// [/RLVa:KB] +// ctrl_wind_light->setEnabled(TRUE); + sky->setEnabled(TRUE); + sky_text->setEnabled(TRUE); + + //Deferred/SSAO/Shadows + LLCheckBoxCtrl* ctrl_deferred = getChild("UseLightShaders"); + + BOOL enabled = LLFeatureManager::getInstance()->isFeatureAvailable("RenderDeferred") && + ((bumpshiny_ctrl && bumpshiny_ctrl->get()) ? TRUE : FALSE) && + ((transparent_water_ctrl && transparent_water_ctrl->get()) ? TRUE : FALSE) && + gGLManager.mHasFramebufferObject && + gSavedSettings.getBOOL("RenderAvatarVP") && + (ctrl_wind_light->get()) ? TRUE : FALSE; + + ctrl_deferred->setEnabled(enabled); + + LLCheckBoxCtrl* ctrl_ssao = getChild("UseSSAO"); + LLCheckBoxCtrl* ctrl_dof = getChild("UseDoF"); + LLComboBox* ctrl_shadow = getChild("ShadowDetail"); + LLTextBox* shadow_text = getChild("RenderShadowDetailText"); + + // note, okay here to get from ctrl_deferred as it's twin, ctrl_deferred2 will alway match it + enabled = enabled && LLFeatureManager::getInstance()->isFeatureAvailable("RenderDeferredSSAO") && (ctrl_deferred->get() ? TRUE : FALSE); + + ctrl_deferred->set(gSavedSettings.getBOOL("RenderDeferred")); + + ctrl_ssao->setEnabled(enabled); + ctrl_dof->setEnabled(enabled); + + enabled = enabled && LLFeatureManager::getInstance()->isFeatureAvailable("RenderShadowDetail"); + + ctrl_shadow->setEnabled(enabled); + shadow_text->setEnabled(enabled); + + // Hardware settings + F32 mem_multiplier = gSavedSettings.getF32("RenderTextureMemoryMultiple"); + S32Megabytes min_tex_mem = LLViewerTextureList::getMinVideoRamSetting(); + S32Megabytes max_tex_mem = LLViewerTextureList::getMaxVideoRamSetting(false, mem_multiplier); + getChild("GraphicsCardTextureMemory")->setMinValue(min_tex_mem.value()); + getChild("GraphicsCardTextureMemory")->setMaxValue(max_tex_mem.value()); + + if (!LLFeatureManager::getInstance()->isFeatureAvailable("RenderVBOEnable") || + !gGLManager.mHasVertexBufferObject) + { + getChildView("vbo")->setEnabled(FALSE); + } + + if (!LLFeatureManager::getInstance()->isFeatureAvailable("RenderCompressTextures") || + !gGLManager.mHasVertexBufferObject) + { + getChildView("texture compression")->setEnabled(FALSE); + } + + // if no windlight shaders, turn off nighttime brightness, gamma, and fog distance + LLUICtrl* gamma_ctrl = getChild("gamma"); + gamma_ctrl->setEnabled(!gPipeline.canUseWindLightShaders()); + getChildView("(brightness, lower is brighter)")->setEnabled(!gPipeline.canUseWindLightShaders()); + getChildView("fog")->setEnabled(!gPipeline.canUseWindLightShaders()); + getChildView("antialiasing restart")->setVisible(!LLFeatureManager::getInstance()->isFeatureAvailable("RenderDeferred")); + + // now turn off any features that are unavailable + disableUnavailableSettings(); +} + +void LLFloaterPreferenceGraphicsAdvanced::onBtnOK(const LLSD& userdata) +{ + LLFloaterPreference* instance = LLFloaterReg::getTypedInstance("preferences"); + if (instance) + { + instance->onBtnOK(userdata); + } +} + +void LLFloaterPreferenceGraphicsAdvanced::onBtnCancel(const LLSD& userdata) +{ + LLFloaterPreference* instance = LLFloaterReg::getTypedInstance("preferences"); + if (instance) + { + instance->onBtnCancel(userdata); + } +} diff --git a/indra/newview/llfloaterpreferencesgraphicsadvanced.h b/indra/newview/llfloaterpreferencesgraphicsadvanced.h new file mode 100644 index 0000000000..c5d21ba35b --- /dev/null +++ b/indra/newview/llfloaterpreferencesgraphicsadvanced.h @@ -0,0 +1,65 @@ +/** + * @file llfloaterpreferencesgraphicsadvanced.h + * + * $LicenseInfo:firstyear=2021&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2021, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LLFLOATERPREFERENCEGRAPHICSADVANCED_H +#define LLFLOATERPREFERENCEGRAPHICSADVANCED_H + +#include "llcontrol.h" +#include "llfloater.h" + +class LLSliderCtrl; +class LLTextBox; + +class LLFloaterPreferenceGraphicsAdvanced : public LLFloater +{ +public: + LLFloaterPreferenceGraphicsAdvanced(const LLSD& key); + ~LLFloaterPreferenceGraphicsAdvanced(); + /*virtual*/ BOOL postBuild(); + void onOpen(const LLSD& key); + void onClickCloseBtn(bool app_quitting); + void disableUnavailableSettings(); + void refreshEnabledGraphics(); + void refreshEnabledState(); + void updateSliderText(LLSliderCtrl* ctrl, LLTextBox* text_box); + void updateMaxNonImpostors(); + void setMaxNonImpostorsText(U32 value, LLTextBox* text_box); + void updateMaxComplexity(); + void updateComplexityText(); + void refresh(); + // callback for when client modifies a render option + void onRenderOptionEnable(); + void onAdvancedAtmosphericsEnable(); + LOG_CLASS(LLFloaterPreferenceGraphicsAdvanced); + +protected: + void onBtnOK(const LLSD& userdata); + void onBtnCancel(const LLSD& userdata); + + boost::signals2::connection mComplexityChangedSignal; +}; + +#endif //LLFLOATERPREFERENCEGRAPHICSADVANCED_H + diff --git a/indra/newview/llfloaterregioninfo.cpp b/indra/newview/llfloaterregioninfo.cpp index 379f3fdce5..9464bcd770 100644 --- a/indra/newview/llfloaterregioninfo.cpp +++ b/indra/newview/llfloaterregioninfo.cpp @@ -501,6 +501,29 @@ void LLFloaterRegionInfo::processRegionInfo(LLMessageSystem* msg) region_flags = flags; } + if (msg->has(_PREHASH_RegionInfo5)) + { + F32 chat_whisper_range; + F32 chat_normal_range; + F32 chat_shout_range; + F32 chat_whisper_offset; + F32 chat_normal_offset; + F32 chat_shout_offset; + U32 chat_flags; + + msg->getF32Fast(_PREHASH_RegionInfo5, _PREHASH_ChatWhisperRange, chat_whisper_range); + msg->getF32Fast(_PREHASH_RegionInfo5, _PREHASH_ChatNormalRange, chat_normal_range); + msg->getF32Fast(_PREHASH_RegionInfo5, _PREHASH_ChatShoutRange, chat_shout_range); + msg->getF32Fast(_PREHASH_RegionInfo5, _PREHASH_ChatWhisperOffset, chat_whisper_offset); + msg->getF32Fast(_PREHASH_RegionInfo5, _PREHASH_ChatNormalOffset, chat_normal_offset); + msg->getF32Fast(_PREHASH_RegionInfo5, _PREHASH_ChatShoutOffset, chat_shout_offset); + msg->getU32Fast(_PREHASH_RegionInfo5, _PREHASH_ChatFlags, chat_flags); + + LL_INFOS() << "Whisper range: " << chat_whisper_range << " normal range: " << chat_normal_range << " shout range: " << chat_shout_range + << " whisper offset: " << chat_whisper_offset << " normal offset: " << chat_normal_offset << " shout offset: " << chat_shout_offset + << " chat flags: " << chat_flags << LL_ENDL; + } + // GENERAL PANEL panel = tab->getChild("General"); panel->getChild("region_text")->setValue(LLSD(sim_name)); diff --git a/indra/newview/llfloatersnapshot.cpp b/indra/newview/llfloatersnapshot.cpp index 3abdecf955..8019e523db 100644 --- a/indra/newview/llfloatersnapshot.cpp +++ b/indra/newview/llfloatersnapshot.cpp @@ -202,6 +202,10 @@ void LLFloaterSnapshotBase::ImplBase::updateLayout(LLFloaterSnapshotBase* floate LLUICtrl* thumbnail_placeholder = floaterp->getChild("thumbnail_placeholder"); floaterp->getChild("image_res_text")->setVisible(mAdvanced); floaterp->getChild("file_size_label")->setVisible(mAdvanced); + if (floaterp->hasChild("360_label", TRUE)) + { + floaterp->getChild("360_label")->setVisible(mAdvanced); + } if(!floaterp->isMinimized()) { LLView* controls_container = floaterp->getChild("controls_container"); @@ -1125,6 +1129,13 @@ BOOL LLFloaterSnapshot::postBuild() getChild("retract_btn")->setCommitCallback(boost::bind(&LLFloaterSnapshot::onExtendFloater, this)); getChild("extend_btn")->setCommitCallback(boost::bind(&LLFloaterSnapshot::onExtendFloater, this)); + // Better 360 snapshot button + //getChild("360_label")->setSoundFlags(LLView::MOUSE_UP); + //getChild("360_label")->setShowCursorHand(false); + //getChild("360_label")->setClickedCallback(boost::bind(&LLFloaterSnapshot::on360Snapshot, this)); + getChild("360_label")->setCommitCallback(boost::bind(&LLFloaterSnapshot::on360Snapshot, this)); + // + // Filters LLComboBox* filterbox = getChild("filters_combobox"); std::vector filter_list = LLImageFiltersManager::getInstance()->getFiltersList(); @@ -1296,6 +1307,12 @@ void LLFloaterSnapshot::onExtendFloater() impl->setAdvanced(gSavedSettings.getBOOL("AdvanceSnapshot")); } +void LLFloaterSnapshot::on360Snapshot() +{ + LLFloaterReg::showInstance("360capture"); + closeFloater(); +} + // FIRE-16043: Remember last used snapshot option //virtual void LLFloaterSnapshot::onClose(bool app_quitting) diff --git a/indra/newview/llfloatersnapshot.h b/indra/newview/llfloatersnapshot.h index d6b5e1cd56..5977cb9a57 100644 --- a/indra/newview/llfloatersnapshot.h +++ b/indra/newview/llfloatersnapshot.h @@ -156,6 +156,7 @@ public: static void update(); void onExtendFloater(); + void on360Snapshot(); static LLFloaterSnapshot* getInstance(); static LLFloaterSnapshot* findInstance(); diff --git a/indra/newview/llfloaterwindowsize.cpp b/indra/newview/llfloaterwindowsize.cpp index 47987a5e99..eb7a907f6a 100644 --- a/indra/newview/llfloaterwindowsize.cpp +++ b/indra/newview/llfloaterwindowsize.cpp @@ -34,19 +34,17 @@ #include "llcombobox.h" #include "llfloater.h" #include "llfloaterreg.h" +#include "llregex.h" #include "lluictrl.h" #include "llviewercontrol.h" -// System libraries -#include - // Extract from strings of the form " x ", e.g. "640 x 480". bool extractWindowSizeFromString(const std::string& instr, U32 *width, U32 *height) { boost::cmatch what; // matches (any number)(any non-number)(any number) const boost::regex expression("([0-9]+)[^0-9]+([0-9]+)"); - if (boost::regex_match(instr.c_str(), what, expression)) + if (ll_regex_match(instr.c_str(), what, expression)) { *width = atoi(what[1].first); *height = atoi(what[2].first); diff --git a/indra/newview/llhasheduniqueid.cpp b/indra/newview/llhasheduniqueid.cpp index 03192d3e61..38dafc167f 100644 --- a/indra/newview/llhasheduniqueid.cpp +++ b/indra/newview/llhasheduniqueid.cpp @@ -35,8 +35,8 @@ bool llHashedUniqueID(unsigned char id[MD5HEX_STR_SIZE]) bool idIsUnique = true; LLMD5 hashed_unique_id; unsigned char unique_id[MAC_ADDRESS_BYTES]; - if ( LLUUID::getNodeID(unique_id) - || LLMachineID::getUniqueID(unique_id, sizeof(unique_id)) + if ( LLMachineID::getUniqueID(unique_id, sizeof(unique_id)) + || LLUUID::getNodeID(unique_id) ) { hashed_unique_id.update(unique_id, MAC_ADDRESS_BYTES); diff --git a/indra/newview/llimprocessing.cpp b/indra/newview/llimprocessing.cpp index df2c2dbcbd..6fc0c0374f 100644 --- a/indra/newview/llimprocessing.cpp +++ b/indra/newview/llimprocessing.cpp @@ -45,6 +45,7 @@ #include "llnotificationsutil.h" #include "llnotificationmanager.h" #include "llpanelgroup.h" +#include "llregex.h" #include "llregionhandle.h" #include "llsdserialize.h" #include "llslurl.h" @@ -58,7 +59,6 @@ #include "llviewerregion.h" #include "llvoavatarself.h" -#include #include "boost/lexical_cast.hpp" // [RLVa:KB] - Checked: 2010-03-09 (RLVa-1.2.0a) @@ -146,7 +146,7 @@ static std::string clean_name_from_task_im(const std::string& msg, boost::smatch match; static const boost::regex returned_exp( "(.*been returned to your inventory lost and found folder by )(.+)( (from|near).*)"); - if (boost::regex_match(msg, match, returned_exp)) + if (ll_regex_match(msg, match, returned_exp)) { // match objects are 1-based for groups std::string final = match[1].str(); diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp index 3b571ac75a..4be59857e1 100644 --- a/indra/newview/llinventorybridge.cpp +++ b/indra/newview/llinventorybridge.cpp @@ -795,7 +795,7 @@ void hide_context_entries(LLMenuGL& menu, found = !(is_entry_separator && is_previous_entry_separator); is_previous_entry_separator = is_entry_separator; } - + if (!found) { if (!menu_item->getLastVisible()) @@ -6039,11 +6039,20 @@ void LLTextureBridge::buildContextMenu(LLMenuGL& menu, U32 flags) getClipboardEntries(true, items, disabled_items, flags); items.push_back(std::string("Texture Separator")); - items.push_back(std::string("Save As")); - if (!canSaveTexture()) - { - disabled_items.push_back(std::string("Save As")); - } + + if ((flags & ITEM_IN_MULTI_SELECTION) != 0) + { + items.push_back(std::string("Save Selected As")); + } + else + { + items.push_back(std::string("Save As")); + if (!canSaveTexture()) + { + disabled_items.push_back(std::string("Save As")); + } + } + items.push_back(std::string("Wearable And Object Separator")); // Add separator // [RLVa:KB] - Checked: 2010-03-01 (RLVa-1.2.0b) | Modified: RLVa-1.1.0a if (rlv_handler_t::isEnabled()) @@ -6076,6 +6085,23 @@ void LLTextureBridge::performAction(LLInventoryModel* model, std::string action) preview_texture->saveAs(); } } + else if ("save_selected_as" == action) + { + openItem(); + if (canSaveTexture()) + { + LLPreviewTexture* preview_texture = LLFloaterReg::getTypedInstance("preview_texture", mUUID); + if (preview_texture) + { + preview_texture->saveMultipleToFile(mFileName); + } + } + else + { + LL_WARNS() << "You don't have permission to save " << getName() << " to disk." << LL_ENDL; + } + + } else LLItemBridge::performAction(model, action); } @@ -7599,7 +7625,7 @@ void LLWearableBridge::buildContextMenu(LLMenuGL& menu, U32 flags) // [/RLVa:KB] } - if (LLWearableType::getAllowMultiwear(mWearableType)) + if (LLWearableType::getInstance()->getAllowMultiwear(mWearableType)) { items.push_back(std::string("Wearable Add")); if (!gAgentWearables.canAddWearable(mWearableType)) @@ -8456,6 +8482,7 @@ void LLFolderViewGroupedItemBridge::groupFilterContextMenu(folder_view_item_dequ disabled_items.push_back(std::string("Wearable Add")); disabled_items.push_back(std::string("Attach To")); disabled_items.push_back(std::string("Attach To HUD")); + disabled_items.push_back(std::string("Wearable And Object Separator")); // Add separator } } disable_context_entries_if_present(menu, disabled_items); diff --git a/indra/newview/llinventorybridge.h b/indra/newview/llinventorybridge.h index 17ab5eab8d..e0f17bb182 100644 --- a/indra/newview/llinventorybridge.h +++ b/indra/newview/llinventorybridge.h @@ -430,6 +430,9 @@ public: virtual void buildContextMenu(LLMenuGL& menu, U32 flags); virtual void performAction(LLInventoryModel* model, std::string action); bool canSaveTexture(void); + void setFileName(const std::string& file_name) { mFileName = file_name; } +protected: + std::string mFileName; }; class LLSoundBridge : public LLItemBridge diff --git a/indra/newview/llinventoryfilter.cpp b/indra/newview/llinventoryfilter.cpp index 21a2c5cbbf..8de8071ac7 100644 --- a/indra/newview/llinventoryfilter.cpp +++ b/indra/newview/llinventoryfilter.cpp @@ -36,13 +36,14 @@ #include "llinventorymodelbackgroundfetch.h" #include "llinventoryfunctions.h" #include "llmarketplacefunctions.h" +#include "llregex.h" #include "llviewercontrol.h" #include "llfolderview.h" #include "llinventorybridge.h" #include "llviewerfoldertype.h" #include "llradiogroup.h" #include "llstartup.h" -#include + // linden library includes #include "llclipboard.h" #include "lltrans.h" @@ -931,7 +932,7 @@ void LLInventoryFilter::setFilterSubString(const std::string& string) boost::regex mPattern = boost::regex("\"\\s*([^<]*)?\\s*\"", boost::regex::perl | boost::regex::icase); boost::match_results matches; - mExactToken = (boost::regex_match(filter_sub_string_new, matches, mPattern) && matches[1].matched) + mExactToken = (ll_regex_match(filter_sub_string_new, matches, mPattern) && matches[1].matched) ? matches[1] : LLStringUtil::null; if ((old_token.empty() && !mExactToken.empty()) diff --git a/indra/newview/llinventoryfunctions.cpp b/indra/newview/llinventoryfunctions.cpp index d2715a008c..9468581c70 100644 --- a/indra/newview/llinventoryfunctions.cpp +++ b/indra/newview/llinventoryfunctions.cpp @@ -47,6 +47,7 @@ #include "llappviewer.h" #include "llavataractions.h" #include "llclipboard.h" +#include "lldirpicker.h" #include "lldonotdisturbnotificationstorage.h" #include "llfloatersidepanelcontainer.h" #include "llfocusmgr.h" @@ -88,6 +89,7 @@ #include "llwearablelist.h" // [RLVa:KB] - Checked: 2011-05-22 (RLVa-1.3.1a) #include "rlvactions.h" +#include "rlvhandler.h" #include "rlvlocks.h" // [/RLVa:KB] @@ -884,6 +886,13 @@ void show_item_profile(const LLUUID& item_uuid) void show_item_original(const LLUUID& item_uuid) { + // Don't show if @showinv=n + if (rlv_handler_t::isEnabled() && gRlvHandler.hasBehaviour(RLV_BHVR_SHOWINV)) + { + return; + } + // + LLFloater* floater_inventory = LLFloaterReg::getInstance("inventory"); if (!floater_inventory) { @@ -2754,6 +2763,10 @@ void LLInventoryAction::doToSelected(LLInventoryModel* model, LLFolderView* root { LLAppearanceMgr::instance().removeItemsFromAvatar(ids); } + else if ("save_selected_as" == action) + { + (new LLDirPickerThread(boost::bind(&LLInventoryAction::saveMultipleTextures, _1, selected_items, model), std::string()))->getFile(); + } // FIRE-22851: Show texture "Save as" file picker subsequently instead all at once else if (action == "save_as") // "save_as" is only available for textures as of 01/08/2018 { @@ -2787,6 +2800,41 @@ void LLInventoryAction::doToSelected(LLInventoryModel* model, LLFolderView* root } } +void LLInventoryAction::saveMultipleTextures(const std::vector& filenames, std::set selected_items, LLInventoryModel* model) +{ + gSavedSettings.setString("TextureSaveLocation", filenames[0]); + + LLMultiPreview* multi_previewp = new LLMultiPreview(); + gFloaterView->addChild(multi_previewp); + + LLFloater::setFloaterHost(multi_previewp); + + std::map tex_names_map; + std::set::iterator set_iter; + + for (set_iter = selected_items.begin(); set_iter != selected_items.end(); ++set_iter) + { + LLFolderViewItem* folder_item = *set_iter; + if(!folder_item) continue; + LLTextureBridge* bridge = (LLTextureBridge*)folder_item->getViewModelItem(); + if(!bridge) continue; + + std::string tex_name = bridge->getName(); + if(!tex_names_map.insert(std::pair(tex_name, 0)).second) + { + tex_names_map[tex_name]++; + bridge->setFileName(tex_name + llformat("_%.3d", tex_names_map[tex_name])); + } + bridge->performAction(model, "save_selected_as"); + } + + LLFloater::setFloaterHost(NULL); + if (multi_previewp) + { + multi_previewp->openFloater(LLSD()); + } +} + void LLInventoryAction::removeItemFromDND(LLFolderView* root) { if(gAgent.isDoNotDisturb()) diff --git a/indra/newview/llinventoryfunctions.h b/indra/newview/llinventoryfunctions.h index 01a9757305..ee3b58a5fc 100644 --- a/indra/newview/llinventoryfunctions.h +++ b/indra/newview/llinventoryfunctions.h @@ -491,6 +491,8 @@ struct LLInventoryAction static void onItemsRemovalConfirmation(const LLSD& notification, const LLSD& response, LLHandle root); static void removeItemFromDND(LLFolderView* root); + static void saveMultipleTextures(const std::vector& filenames, std::set selected_items, LLInventoryModel* model); + // Unused as of 24-08-2017 //static const int sConfirmOnDeleteItemsNumber; diff --git a/indra/newview/llinventoryicon.cpp b/indra/newview/llinventoryicon.cpp index 554ba49d34..d7389597af 100644 --- a/indra/newview/llinventoryicon.cpp +++ b/indra/newview/llinventoryicon.cpp @@ -201,7 +201,7 @@ const std::string& LLInventoryIcon::getIconName(LLInventoryType::EIconName idx) LLInventoryType::EIconName LLInventoryIcon::assignWearableIcon(U32 misc_flag) { const LLWearableType::EType wearable_type = LLWearableType::inventoryFlagsToWearableType(misc_flag); - return LLWearableType::getIconName(wearable_type); + return LLWearableType::getInstance()->getIconName(wearable_type); } LLInventoryType::EIconName LLInventoryIcon::assignSettingsIcon(U32 misc_flag) diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp index e8542dcaf6..aa1a6972b6 100644 --- a/indra/newview/llinventorymodel.cpp +++ b/indra/newview/llinventorymodel.cpp @@ -520,7 +520,8 @@ const LLUUID LLInventoryModel::findCategoryUUIDForTypeInRoot( S32 count = cats->size(); for(S32 i = 0; i < count; ++i) { - if(cats->at(i)->getPreferredType() == preferred_type) + LLViewerInventoryCategory* p_cat = cats->at(i); + if(p_cat && p_cat->getPreferredType() == preferred_type) { const LLUUID& folder_id = cats->at(i)->getUUID(); if (rv.isNull() || folder_id < rv) @@ -1814,9 +1815,18 @@ void LLInventoryModel::notifyObservers(const LLUUID& transaction_id) iter = mObservers.upper_bound(observer); } - mModifyMask = LLInventoryObserver::NONE; + // If there were any changes that arrived during notifyObservers, + // shedule them for next loop + mModifyMask = mModifyMaskBacklog; mChangedItemIDs.clear(); + mChangedItemIDs.insert(mChangedItemIDsBacklog.begin(), mChangedItemIDsBacklog.end()); mAddedItemIDs.clear(); + mAddedItemIDs.insert(mAddedItemIDsBacklog.begin(), mAddedItemIDsBacklog.end()); + + mModifyMaskBacklog = LLInventoryObserver::NONE; + mChangedItemIDsBacklog.clear(); + mAddedItemIDsBacklog.clear(); + // [SL:KB] - Patch: UI-Notifications | Checked: Catznip-6.5 mTransactionId.setNull(); // [/SL:KB] @@ -1831,8 +1841,10 @@ void LLInventoryModel::addChangedMask(U32 mask, const LLUUID& referent) { // Something marked an item for change within a call to notifyObservers // (which is in the process of processing the list of items marked for change). - // This means the change may fail to be processed. - LL_WARNS(LOG_INV) << "Adding changed mask within notify observers! Change will likely be lost." << LL_ENDL; + // This means the change will have to be processed later. + // It's preferable for this not to happen, but it's not an issue unless code + // specifically wants to notifyObservers immediately (changes won't happen untill later) + LL_WARNS(LOG_INV) << "Adding changed mask within notify observers! Change's processing will be performed on idle." << LL_ENDL; LLViewerInventoryItem *item = getItem(referent); if (item) { @@ -1847,17 +1859,40 @@ void LLInventoryModel::addChangedMask(U32 mask, const LLUUID& referent) } } } - - mModifyMask |= mask; + + if (mIsNotifyObservers) + { + mModifyMaskBacklog |= mask; + } + else + { + mModifyMask |= mask; + } + if (referent.notNull() && (mChangedItemIDs.find(referent) == mChangedItemIDs.end())) { - mChangedItemIDs.insert(referent); + if (mIsNotifyObservers) + { + mChangedItemIDsBacklog.insert(referent); + } + else + { + mChangedItemIDs.insert(referent); + } + update_marketplace_category(referent, false); - if (mask & LLInventoryObserver::ADD) - { - mAddedItemIDs.insert(referent); - } + if (mask & LLInventoryObserver::ADD) + { + if (mIsNotifyObservers) + { + mAddedItemIDsBacklog.insert(referent); + } + else + { + mAddedItemIDs.insert(referent); + } + } // Update all linked items. Starting with just LABEL because I'm // not sure what else might need to be accounted for this. @@ -2880,7 +2915,10 @@ void LLInventoryModel::createCommonSystemCategories() gInventory.findCategoryUUIDForType(LLFolderType::FT_FAVORITE,true); gInventory.findCategoryUUIDForType(LLFolderType::FT_CALLINGCARD,true); gInventory.findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS,true); + gInventory.findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT, true); + gInventory.findCategoryUUIDForType(LLFolderType::FT_LANDMARK, true); // folder should exist before user tries to 'landmark this' gInventory.findCategoryUUIDForType(LLFolderType::FT_SETTINGS, true); + gInventory.findCategoryUUIDForType(LLFolderType::FT_INBOX, true); } struct LLUUIDAndName @@ -4179,17 +4217,18 @@ void LLInventoryModel::dumpInventory() const // returning an overall good/bad flag. bool LLInventoryModel::validate() const { - bool valid = true; + const S32 MAX_VERBOSE_ERRORS = 40; // too many errors can cause disconect or freeze + S32 error_count = 0; if (getRootFolderID().isNull()) { LL_WARNS() << "no root folder id" << LL_ENDL; - valid = false; + error_count++; } if (getLibraryRootFolderID().isNull()) { LL_WARNS() << "no root folder id" << LL_ENDL; - valid = false; + error_count++; } if (mCategoryMap.size() + 1 != mParentChildCategoryTree.size()) @@ -4197,7 +4236,7 @@ bool LLInventoryModel::validate() const // ParentChild should be one larger because of the special entry for null uuid. LL_INFOS() << "unexpected sizes: cat map size " << mCategoryMap.size() << " parent/child " << mParentChildCategoryTree.size() << LL_ENDL; - valid = false; + error_count++; } S32 cat_lock = 0; S32 item_lock = 0; @@ -4209,23 +4248,32 @@ bool LLInventoryModel::validate() const const LLViewerInventoryCategory *cat = cit->second; if (!cat) { - LL_WARNS() << "invalid cat" << LL_ENDL; - valid = false; + if (error_count < MAX_VERBOSE_ERRORS) + { + LL_WARNS() << "invalid cat" << LL_ENDL; + } + error_count++; continue; } if (cat_id != cat->getUUID()) { - LL_WARNS() << "cat id/index mismatch " << cat_id << " " << cat->getUUID() << LL_ENDL; - valid = false; + if (error_count < MAX_VERBOSE_ERRORS) + { + LL_WARNS() << "cat id/index mismatch " << cat_id << " " << cat->getUUID() << LL_ENDL; + } + error_count++; } if (cat->getParentUUID().isNull()) { if (cat_id != getRootFolderID() && cat_id != getLibraryRootFolderID()) { - LL_WARNS() << "cat " << cat_id << " has no parent, but is not root (" - << getRootFolderID() << ") or library root (" - << getLibraryRootFolderID() << ")" << LL_ENDL; + if (error_count < MAX_VERBOSE_ERRORS) + { + LL_WARNS() << "cat " << cat_id << " has no parent, but is not root (" + << getRootFolderID() << ") or library root (" + << getLibraryRootFolderID() << ")" << LL_ENDL; + } } } cat_array_t* cats; @@ -4233,8 +4281,11 @@ bool LLInventoryModel::validate() const getDirectDescendentsOf(cat_id,cats,items); if (!cats || !items) { - LL_WARNS() << "invalid direct descendents for " << cat_id << LL_ENDL; - valid = false; + if (error_count < MAX_VERBOSE_ERRORS) + { + LL_WARNS() << "invalid direct descendents for " << cat_id << LL_ENDL; + } + error_count++; continue; } if (cat->getDescendentCount() == LLViewerInventoryCategory::DESCENDENT_COUNT_UNKNOWN) @@ -4243,12 +4294,15 @@ bool LLInventoryModel::validate() const } else if (cats->size() + items->size() != cat->getDescendentCount()) { - LL_WARNS() << "invalid desc count for " << cat_id << " name [" << cat->getName() - << "] parent " << cat->getParentUUID() - << " cached " << cat->getDescendentCount() - << " expected " << cats->size() << "+" << items->size() - << "=" << cats->size() +items->size() << LL_ENDL; - valid = false; + if (error_count < MAX_VERBOSE_ERRORS) + { + LL_WARNS() << "invalid desc count for " << cat_id << " name [" << cat->getName() + << "] parent " << cat->getParentUUID() + << " cached " << cat->getDescendentCount() + << " expected " << cats->size() << "+" << items->size() + << "=" << cats->size() + items->size() << LL_ENDL; + } + error_count++; } if (cat->getVersion() == LLViewerInventoryCategory::VERSION_UNKNOWN) { @@ -4268,8 +4322,11 @@ bool LLInventoryModel::validate() const if (!item) { - LL_WARNS() << "null item at index " << i << " for cat " << cat_id << LL_ENDL; - valid = false; + if (error_count < MAX_VERBOSE_ERRORS) + { + LL_WARNS() << "null item at index " << i << " for cat " << cat_id << LL_ENDL; + } + error_count++; continue; } @@ -4277,10 +4334,13 @@ bool LLInventoryModel::validate() const if (item->getParentUUID() != cat_id) { - LL_WARNS() << "wrong parent for " << item_id << " found " - << item->getParentUUID() << " expected " << cat_id - << LL_ENDL; - valid = false; + if (error_count < MAX_VERBOSE_ERRORS) + { + LL_WARNS() << "wrong parent for " << item_id << " found " + << item->getParentUUID() << " expected " << cat_id + << LL_ENDL; + } + error_count++; } @@ -4288,17 +4348,24 @@ bool LLInventoryModel::validate() const item_map_t::const_iterator it = mItemMap.find(item_id); if (it == mItemMap.end()) { - LL_WARNS() << "item " << item_id << " found as child of " - << cat_id << " but not in top level mItemMap" << LL_ENDL; - valid = false; + + if (error_count < MAX_VERBOSE_ERRORS) + { + LL_WARNS() << "item " << item_id << " found as child of " + << cat_id << " but not in top level mItemMap" << LL_ENDL; + } + error_count++; } else { LLViewerInventoryItem *top_item = it->second; if (top_item != item) { - LL_WARNS() << "item mismatch, item_id " << item_id - << " top level entry is different, uuid " << top_item->getUUID() << LL_ENDL; + if (error_count < MAX_VERBOSE_ERRORS) + { + LL_WARNS() << "item mismatch, item_id " << item_id + << " top level entry is different, uuid " << top_item->getUUID() << LL_ENDL; + } } } @@ -4307,19 +4374,25 @@ bool LLInventoryModel::validate() const bool found = getObjectTopmostAncestor(item_id, topmost_ancestor_id); if (!found) { - LL_WARNS() << "unable to find topmost ancestor for " << item_id << LL_ENDL; - valid = false; + if (error_count < MAX_VERBOSE_ERRORS) + { + LL_WARNS() << "unable to find topmost ancestor for " << item_id << LL_ENDL; + } + error_count++; } else { if (topmost_ancestor_id != getRootFolderID() && topmost_ancestor_id != getLibraryRootFolderID()) { - LL_WARNS() << "unrecognized top level ancestor for " << item_id - << " got " << topmost_ancestor_id - << " expected " << getRootFolderID() - << " or " << getLibraryRootFolderID() << LL_ENDL; - valid = false; + if (error_count < MAX_VERBOSE_ERRORS) + { + LL_WARNS() << "unrecognized top level ancestor for " << item_id + << " got " << topmost_ancestor_id + << " expected " << getRootFolderID() + << " or " << getLibraryRootFolderID() << LL_ENDL; + } + error_count++; } } } @@ -4333,9 +4406,12 @@ bool LLInventoryModel::validate() const getDirectDescendentsOf(parent_id,cats,items); if (!cats) { - LL_WARNS() << "cat " << cat_id << " name [" << cat->getName() - << "] orphaned - no child cat array for alleged parent " << parent_id << LL_ENDL; - valid = false; + if (error_count < MAX_VERBOSE_ERRORS) + { + LL_WARNS() << "cat " << cat_id << " name [" << cat->getName() + << "] orphaned - no child cat array for alleged parent " << parent_id << LL_ENDL; + } + error_count++; } else { @@ -4351,8 +4427,11 @@ bool LLInventoryModel::validate() const } if (!found) { - LL_WARNS() << "cat " << cat_id << " name [" << cat->getName() - << "] orphaned - not found in child cat array of alleged parent " << parent_id << LL_ENDL; + if (error_count < MAX_VERBOSE_ERRORS) + { + LL_WARNS() << "cat " << cat_id << " name [" << cat->getName() + << "] orphaned - not found in child cat array of alleged parent " << parent_id << LL_ENDL; + } } } } @@ -4364,24 +4443,33 @@ bool LLInventoryModel::validate() const LLViewerInventoryItem *item = iit->second; if (item->getUUID() != item_id) { - LL_WARNS() << "item_id " << item_id << " does not match " << item->getUUID() << LL_ENDL; - valid = false; + if (error_count < MAX_VERBOSE_ERRORS) + { + LL_WARNS() << "item_id " << item_id << " does not match " << item->getUUID() << LL_ENDL; + } + error_count++; } const LLUUID& parent_id = item->getParentUUID(); if (parent_id.isNull()) { - LL_WARNS() << "item " << item_id << " name [" << item->getName() << "] has null parent id!" << LL_ENDL; + if (error_count < MAX_VERBOSE_ERRORS) + { + LL_WARNS() << "item " << item_id << " name [" << item->getName() << "] has null parent id!" << LL_ENDL; + } } - else + else if (error_count < MAX_VERBOSE_ERRORS) { cat_array_t* cats; item_array_t* items; getDirectDescendentsOf(parent_id,cats,items); if (!items) { - LL_WARNS() << "item " << item_id << " name [" << item->getName() - << "] orphaned - alleged parent has no child items list " << parent_id << LL_ENDL; + if (error_count < MAX_VERBOSE_ERRORS) + { + LL_WARNS() << "item " << item_id << " name [" << item->getName() + << "] orphaned - alleged parent has no child items list " << parent_id << LL_ENDL; + } } else { @@ -4396,63 +4484,70 @@ bool LLInventoryModel::validate() const } if (!found) { - LL_WARNS() << "item " << item_id << " name [" << item->getName() - << "] orphaned - not found as child of alleged parent " << parent_id << LL_ENDL; + if (error_count < MAX_VERBOSE_ERRORS) + { + LL_WARNS() << "item " << item_id << " name [" << item->getName() + << "] orphaned - not found as child of alleged parent " << parent_id << LL_ENDL; + } } } } - // Link checking - if (item->getIsLinkType()) - { - const LLUUID& link_id = item->getUUID(); - const LLUUID& target_id = item->getLinkedUUID(); - LLViewerInventoryItem *target_item = getItem(target_id); - LLViewerInventoryCategory *target_cat = getCategory(target_id); - // Linked-to UUID should have back reference to this link. - if (!hasBacklinkInfo(link_id, target_id)) - { - LL_WARNS() << "link " << item->getUUID() << " type " << item->getActualType() - << " missing backlink info at target_id " << target_id - << LL_ENDL; - } - // Links should have referents. - if (item->getActualType() == LLAssetType::AT_LINK && !target_item) - { - LL_WARNS() << "broken item link " << item->getName() << " id " << item->getUUID() << LL_ENDL; - } - else if (item->getActualType() == LLAssetType::AT_LINK_FOLDER && !target_cat) - { - LL_WARNS() << "broken folder link " << item->getName() << " id " << item->getUUID() << LL_ENDL; - } - if (target_item && target_item->getIsLinkType()) - { - LL_WARNS() << "link " << item->getName() << " references a link item " - << target_item->getName() << " " << target_item->getUUID() << LL_ENDL; - } - // Links should not have backlinks. - std::pair range = mBacklinkMMap.equal_range(link_id); - if (range.first != range.second) - { - LL_WARNS() << "Link item " << item->getName() << " has backlinks!" << LL_ENDL; - } - } - else - { - // Check the backlinks of a non-link item. - const LLUUID& target_id = item->getUUID(); - std::pair range = mBacklinkMMap.equal_range(target_id); - for (backlink_mmap_t::const_iterator it = range.first; it != range.second; ++it) - { - const LLUUID& link_id = it->second; - LLViewerInventoryItem *link_item = getItem(link_id); - if (!link_item || !link_item->getIsLinkType()) - { - LL_WARNS() << "invalid backlink from target " << item->getName() << " to " << link_id << LL_ENDL; - } - } - } + // Link checking + if (error_count < MAX_VERBOSE_ERRORS) + { + if (item->getIsLinkType()) + { + const LLUUID& link_id = item->getUUID(); + const LLUUID& target_id = item->getLinkedUUID(); + LLViewerInventoryItem *target_item = getItem(target_id); + LLViewerInventoryCategory *target_cat = getCategory(target_id); + // Linked-to UUID should have back reference to this link. + if (!hasBacklinkInfo(link_id, target_id)) + { + LL_WARNS() << "link " << item->getUUID() << " type " << item->getActualType() + << " missing backlink info at target_id " << target_id + << LL_ENDL; + } + // Links should have referents. + if (item->getActualType() == LLAssetType::AT_LINK && !target_item) + { + LL_WARNS() << "broken item link " << item->getName() << " id " << item->getUUID() << LL_ENDL; + } + else if (item->getActualType() == LLAssetType::AT_LINK_FOLDER && !target_cat) + { + LL_WARNS() << "broken folder link " << item->getName() << " id " << item->getUUID() << LL_ENDL; + } + if (target_item && target_item->getIsLinkType()) + { + LL_WARNS() << "link " << item->getName() << " references a link item " + << target_item->getName() << " " << target_item->getUUID() << LL_ENDL; + } + + // Links should not have backlinks. + std::pair range = mBacklinkMMap.equal_range(link_id); + if (range.first != range.second) + { + LL_WARNS() << "Link item " << item->getName() << " has backlinks!" << LL_ENDL; + } + } + else + { + // Check the backlinks of a non-link item. + const LLUUID& target_id = item->getUUID(); + std::pair range = mBacklinkMMap.equal_range(target_id); + for (backlink_mmap_t::const_iterator it = range.first; it != range.second; ++it) + { + const LLUUID& link_id = it->second; + LLViewerInventoryItem *link_item = getItem(link_id); + if (!link_item || !link_item->getIsLinkType()) + { + LL_WARNS() << "invalid backlink from target " << item->getName() << " to " << link_id << LL_ENDL; + } + } + } + } } if (cat_lock > 0 || item_lock > 0) @@ -4469,9 +4564,9 @@ bool LLInventoryModel::validate() const LL_INFOS() << "Found " << version_unknown_count << " cats with unknown version" << LL_ENDL; } - LL_INFOS() << "Validate done, valid = " << (U32) valid << LL_ENDL; + LL_INFOS() << "Validate done, found " << error_count << " errors" << LL_ENDL; - return valid; + return error_count == 0; } #endif diff --git a/indra/newview/llinventorymodel.h b/indra/newview/llinventorymodel.h index 91ce633498..19b8f123cb 100644 --- a/indra/newview/llinventorymodel.h +++ b/indra/newview/llinventorymodel.h @@ -590,6 +590,11 @@ private: U32 mModifyMask; changed_items_t mChangedItemIDs; changed_items_t mAddedItemIDs; + // Fallback when notifyObservers is in progress + U32 mModifyMaskBacklog; + changed_items_t mChangedItemIDsBacklog; + changed_items_t mAddedItemIDsBacklog; + // [SL:KB] - Patch: UI-Notifications | Checked: Catznip-6.5 LLUUID mTransactionId; // [/SL:KB] diff --git a/indra/newview/llinventorypanel.cpp b/indra/newview/llinventorypanel.cpp index 01b856e685..4836c950a6 100644 --- a/indra/newview/llinventorypanel.cpp +++ b/indra/newview/llinventorypanel.cpp @@ -44,6 +44,7 @@ #include "llinventoryfunctions.h" #include "llinventorymodelbackgroundfetch.h" #include "llnotificationsutil.h" +#include "llpanelmaininventory.h" #include "llpreview.h" #include "llsidepanelinventory.h" #include "llstartup.h" @@ -1804,7 +1805,7 @@ void LLInventoryPanel::openInventoryPanelAndSetSelection(BOOL auto_open, const L bool show_inbox = gSavedSettings.getBOOL("FSShowInboxFolder"); // Optional hiding of Received Items folder aka Inbox // FIRE-22167: Make "Show in Main View" work properly - //if (main_panel && !in_inbox) + //if (!in_inbox && (main_panel || !sidepanel_inventory->getMainInventoryPanel()->isRecentItemsPanelSelected())) //if (main_panel && !in_inbox) //{ // sidepanel_inventory->selectAllItemsPanel(); //} diff --git a/indra/newview/lllogchat.cpp b/indra/newview/lllogchat.cpp index 2738b4c0d5..2bdaf59fd5 100644 --- a/indra/newview/lllogchat.cpp +++ b/indra/newview/lllogchat.cpp @@ -30,6 +30,7 @@ #include "llagentui.h" #include "llavatarnamecache.h" #include "lllogchat.h" +#include "llregex.h" #include "lltrans.h" #include "llviewercontrol.h" @@ -43,7 +44,6 @@ #include #include -#include #include #include @@ -321,8 +321,8 @@ std::string LLLogChat::makeLogFileName(std::string filename) **/ boost::match_results matches; - bool inboundConf = boost::regex_match(filename, matches, INBOUND_CONFERENCE); - bool outboundConf = boost::regex_match(filename, matches, OUTBOUND_CONFERENCE); + bool inboundConf = ll_regex_match(filename, matches, INBOUND_CONFERENCE); + bool outboundConf = ll_regex_match(filename, matches, OUTBOUND_CONFERENCE); if (!(inboundConf || outboundConf)) { if( gSavedPerAccountSettings.getBOOL("LogFileNamewithDate") ) @@ -949,8 +949,8 @@ bool LLLogChat::isTranscriptFileFound(std::string fullname) //matching a timestamp boost::match_results matches; // Seconds in timestamp - //if (boost::regex_match(remove_utf8_bom(buffer), matches, TIMESTAMP)) - if (boost::regex_match(remove_utf8_bom(buffer), matches, TIMESTAMP) || boost::regex_match(remove_utf8_bom(buffer), matches, TIMESTAMP_AND_SEC)) + //if (ll_regex_match(remove_utf8_bom(buffer), matches, TIMESTAMP)) + if (ll_regex_match(remove_utf8_bom(buffer), matches, TIMESTAMP) || ll_regex_match(remove_utf8_bom(buffer), matches, TIMESTAMP_AND_SEC)) // { result = true; @@ -1037,15 +1037,15 @@ bool LLChatLogParser::parse(std::string& raw, LLSD& im, const LLSD& parse_params // So we use the original regex for timestamps without seconds to find out what // case it is. For this to work, the timestamp part in the TIMESTAMP_AND_STUFF_SEC // regex is NOT optional! - //if (!boost::regex_match(raw, matches, TIMESTAMP_AND_STUFF)) return false; + //if (!ll_regex_match(raw, matches, TIMESTAMP_AND_STUFF)) return false; bool has_sec = false; - if (boost::regex_match(raw, matches, TIMESTAMP_AND_STUFF_SEC)) + if (ll_regex_match(raw, matches, TIMESTAMP_AND_STUFF_SEC)) { has_sec = true; } else { - if (!boost::regex_match(raw, matches, TIMESTAMP_AND_STUFF)) + if (!ll_regex_match(raw, matches, TIMESTAMP_AND_STUFF)) { return false; } @@ -1093,7 +1093,7 @@ bool LLChatLogParser::parse(std::string& raw, LLSD& im, const LLSD& parse_params //matching a name and a text std::string stuff = matches[IDX_STUFF]; boost::match_results name_and_text; - if (!boost::regex_match(stuff, name_and_text, NAME_AND_TEXT)) return false; + if (!ll_regex_match(stuff, name_and_text, NAME_AND_TEXT)) return false; bool has_name = name_and_text[IDX_NAME].matched; std::string name = LLURI::unescape(name_and_text[IDX_NAME]); diff --git a/indra/newview/llmachineid.cpp b/indra/newview/llmachineid.cpp index 51127928d1..583742f970 100644 --- a/indra/newview/llmachineid.cpp +++ b/indra/newview/llmachineid.cpp @@ -30,34 +30,367 @@ #if LL_WINDOWS #define _WIN32_DCOM #include -using namespace std; #include #include +#elif LL_DARWIN +#include +#include #endif unsigned char static_unique_id[] = {0,0,0,0,0,0}; +unsigned char static_legacy_id[] = {0,0,0,0,0,0}; bool static has_static_unique_id = false; +bool static has_static_legacy_id = false; #if LL_WINDOWS -class LLComInitialize +class LLWMIMethods { - HRESULT mHR; public: - LLComInitialize() + LLWMIMethods() + : pLoc(NULL), + pSvc(NULL) { - mHR = CoInitializeEx(0, COINIT_MULTITHREADED); - if (FAILED(mHR)) - LL_DEBUGS("AppInit") << "Failed to initialize COM library. Error code = 0x" << hex << mHR << LL_ENDL; + initCOMObjects(); } - ~LLComInitialize() + ~LLWMIMethods() { - if (SUCCEEDED(mHR)) - CoUninitialize(); + if (isInitialized()) + { + cleanCOMObjects(); + } } + + bool isInitialized() { return SUCCEEDED(mHR); } + bool getWindowsProductNumber(unsigned char *unique_id, size_t len); + bool getDiskDriveSerialNumber(unsigned char *unique_id, size_t len); + bool getProcessorSerialNumber(unsigned char *unique_id, size_t len); + bool getMotherboardSerialNumber(unsigned char *unique_id, size_t len); + bool getComputerSystemProductUUID(unsigned char *unique_id, size_t len); + bool getGenericSerialNumber(const BSTR &select, const LPCWSTR &variable, unsigned char *unique_id, size_t len, bool validate_as_uuid = false); + +private: + void initCOMObjects(); + void cleanCOMObjects(); + + HRESULT mHR; + IWbemLocator *pLoc; + IWbemServices *pSvc; }; -#endif //LL_WINDOWS + +void LLWMIMethods::initCOMObjects() +{ +# pragma comment(lib, "wbemuuid.lib") + // Step 1: -------------------------------------------------- + // Initialize COM. ------------------------------------------ + + mHR = CoInitializeEx(0, COINIT_MULTITHREADED); + if (FAILED(mHR)) + { + LL_DEBUGS("AppInit") << "Failed to initialize COM library. Error code = 0x" << std::hex << mHR << LL_ENDL; + return; + } + + // Step 2: -------------------------------------------------- + // Set general COM security levels -------------------------- + // Note: If you are using Windows 2000, you need to specify - + // the default authentication credentials for a user by using + // a SOLE_AUTHENTICATION_LIST structure in the pAuthList ---- + // parameter of CoInitializeSecurity ------------------------ + + mHR = CoInitializeSecurity( + NULL, + -1, // COM authentication + NULL, // Authentication services + NULL, // Reserved + RPC_C_AUTHN_LEVEL_DEFAULT, // Default authentication + RPC_C_IMP_LEVEL_IMPERSONATE, // Default Impersonation + NULL, // Authentication info + EOAC_NONE, // Additional capabilities + NULL // Reserved + ); + + if (FAILED(mHR)) + { + LL_WARNS("AppInit") << "Failed to initialize security. Error code = 0x" << std::hex << mHR << LL_ENDL; + CoUninitialize(); + return; // Program has failed. + } + + // Step 3: --------------------------------------------------- + // Obtain the initial locator to WMI ------------------------- + + mHR = CoCreateInstance( + CLSID_WbemLocator, + 0, + CLSCTX_INPROC_SERVER, + IID_IWbemLocator, (LPVOID *)&pLoc); + + if (FAILED(mHR)) + { + LL_WARNS("AppInit") << "Failed to create IWbemLocator object." << " Err code = 0x" << std::hex << mHR << LL_ENDL; + CoUninitialize(); + return; // Program has failed. + } + + // Step 4: ----------------------------------------------------- + // Connect to WMI through the IWbemLocator::ConnectServer method + + // Connect to the root\cimv2 namespace with + // the current user and obtain pointer pSvc + // to make IWbemServices calls. + mHR = pLoc->ConnectServer( + _bstr_t(L"ROOT\\CIMV2"), // Object path of WMI namespace + NULL, // User name. NULL = current user + NULL, // User password. NULL = current + 0, // Locale. NULL indicates current + NULL, // Security flags. + 0, // Authority (e.g. Kerberos) + 0, // Context object + &pSvc // pointer to IWbemServices proxy + ); + + if (FAILED(mHR)) + { + LL_WARNS("AppInit") << "Could not connect. Error code = 0x" << std::hex << mHR << LL_ENDL; + pLoc->Release(); + CoUninitialize(); + return; // Program has failed. + } + + LL_DEBUGS("AppInit") << "Connected to ROOT\\CIMV2 WMI namespace" << LL_ENDL; + + // Step 5: -------------------------------------------------- + // Set security levels on the proxy ------------------------- + + mHR = CoSetProxyBlanket( + pSvc, // Indicates the proxy to set + RPC_C_AUTHN_WINNT, // RPC_C_AUTHN_xxx + RPC_C_AUTHZ_NONE, // RPC_C_AUTHZ_xxx + NULL, // Server principal name + RPC_C_AUTHN_LEVEL_CALL, // RPC_C_AUTHN_LEVEL_xxx + RPC_C_IMP_LEVEL_IMPERSONATE, // RPC_C_IMP_LEVEL_xxx + NULL, // client identity + EOAC_NONE // proxy capabilities + ); + + if (FAILED(mHR)) + { + LL_WARNS("AppInit") << "Could not set proxy blanket. Error code = 0x" << std::hex << mHR << LL_ENDL; + cleanCOMObjects(); + return; // Program has failed. + } +} + + +void LLWMIMethods::cleanCOMObjects() +{ + pSvc->Release(); + pLoc->Release(); + CoUninitialize(); +} + +bool LLWMIMethods::getWindowsProductNumber(unsigned char *unique_id, size_t len) +{ + // wmic path Win32_ComputerSystemProduct get UUID + return getGenericSerialNumber(bstr_t("SELECT * FROM Win32_OperatingSystem"), L"SerialNumber", unique_id, len); +} + +bool LLWMIMethods::getDiskDriveSerialNumber(unsigned char *unique_id, size_t len) +{ + // wmic path Win32_DiskDrive get DeviceID,SerialNumber + return getGenericSerialNumber(bstr_t("SELECT * FROM Win32_DiskDrive"), L"SerialNumber", unique_id, len); +} + +bool LLWMIMethods::getProcessorSerialNumber(unsigned char *unique_id, size_t len) +{ + // wmic path Win32_Processor get DeviceID,ProcessorId + return getGenericSerialNumber(bstr_t("SELECT * FROM Win32_Processor"), L"ProcessorId", unique_id, len); +} + +bool LLWMIMethods::getMotherboardSerialNumber(unsigned char *unique_id, size_t len) +{ + // wmic path Win32_Processor get DeviceID,ProcessorId + return getGenericSerialNumber(bstr_t("SELECT * FROM Win32_BaseBoard"), L"SerialNumber", unique_id, len); +} + +bool LLWMIMethods::getComputerSystemProductUUID(unsigned char *unique_id, size_t len) +{ + // UUID from Win32_ComputerSystemProduct is motherboard's uuid and is identical to csproduct's uuid + // wmic csproduct get name,identifyingnumber,uuid + // wmic path Win32_ComputerSystemProduct get UUID + return getGenericSerialNumber(bstr_t("SELECT * FROM Win32_ComputerSystemProduct"), L"UUID", unique_id, len, true); +} + +bool LLWMIMethods::getGenericSerialNumber(const BSTR &select, const LPCWSTR &variable, unsigned char *unique_id, size_t len, bool validate_as_uuid) +{ + if (!isInitialized()) + { + return false; + } + + HRESULT hres; + + // Step 6: -------------------------------------------------- + // Use the IWbemServices pointer to make requests of WMI ---- + + // For example, get the name of the operating system + IEnumWbemClassObject* pEnumerator = NULL; + hres = pSvc->ExecQuery( + bstr_t("WQL"), + select, + WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, + NULL, + &pEnumerator); + + if (FAILED(hres)) + { + LL_WARNS("AppInit") << "Query for operating system name failed." << " Error code = 0x" << std::hex << hres << LL_ENDL; + return false; // Program has failed. + } + + // Step 7: ------------------------------------------------- + // Get the data from the query in step 6 ------------------- + + IWbemClassObject *pclsObj = NULL; + ULONG uReturn = 0; + bool found = false; + + while (pEnumerator) + { + HRESULT hr = pEnumerator->Next(WBEM_INFINITE, 1, + &pclsObj, &uReturn); + + if (0 == uReturn) + { + break; + } + + VARIANT vtProp; + + // Get the value of the Name property + hr = pclsObj->Get(variable, 0, &vtProp, 0, 0); + if (FAILED(hr)) + { + LL_WARNS() << "Failed to get SerialNumber. Error code = 0x" << std::hex << hres << LL_ENDL; + pclsObj->Release(); + pclsObj = NULL; + continue; + } + + // use characters in the returned Serial Number to create a byte array of size len + BSTR serialNumber(vtProp.bstrVal); + unsigned int serial_size = SysStringLen(serialNumber); + if (serial_size < 1) // < len? + { + VariantClear(&vtProp); + pclsObj->Release(); + pclsObj = NULL; + continue; + } + + if (validate_as_uuid) + { + std::wstring ws(serialNumber, serial_size); + std::string str(ws.begin(), ws.end()); + + if (!LLUUID::validate(str)) + { + VariantClear(&vtProp); + pclsObj->Release(); + pclsObj = NULL; + continue; + } + + static const LLUUID f_uuid("FFFFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFF"); + LLUUID id(str); + + if (id.isNull() || id == f_uuid) + { + // Not unique id + VariantClear(&vtProp); + pclsObj->Release(); + pclsObj = NULL; + continue; + } + } + LL_INFOS("AppInit") << " Serial Number : " << vtProp.bstrVal << LL_ENDL; + + unsigned int j = 0; + + while (j < serial_size && vtProp.bstrVal[j] != 0) + { + for (unsigned int i = 0; i < len; i++) + { + if (j >= serial_size || vtProp.bstrVal[j] == 0) + break; + + unique_id[i] = (unsigned int)(unique_id[i] + serialNumber[j]); + j++; + } + } + VariantClear(&vtProp); + + pclsObj->Release(); + pclsObj = NULL; + found = true; + break; + } + + // Cleanup + // ======== + + if (pEnumerator) + pEnumerator->Release(); + + return found; +} +#elif LL_DARWIN +bool getSerialNumber(unsigned char *unique_id, size_t len) +{ + CFStringRef serial_cf_str = NULL; + io_service_t platformExpert = IOServiceGetMatchingService(kIOMasterPortDefault, + IOServiceMatching("IOPlatformExpertDevice")); + if (platformExpert) + { + serial_cf_str = (CFStringRef) IORegistryEntryCreateCFProperty(platformExpert, + CFSTR(kIOPlatformSerialNumberKey), + kCFAllocatorDefault, 0); + IOObjectRelease(platformExpert); + } + + if (serial_cf_str) + { + char buffer[64] = {0}; + std::string serial_str(""); + if (CFStringGetCString(serial_cf_str, buffer, 64, kCFStringEncodingUTF8)) + { + serial_str = buffer; + } + + S32 serial_size = serial_str.size(); + + if(serial_str.size() > 0) + { + S32 j = 0; + while (j < serial_size) + { + for (S32 i = 0; i < len; i++) + { + if (j >= serial_size) + break; + + unique_id[i] = (unsigned int)(unique_id[i] + serial_str[j]); + j++; + } + } + return true; + } + } + return false; +} +#endif // get an unique machine id. // NOT THREAD SAFE - do before setting up threads. @@ -69,201 +402,75 @@ S32 LLMachineID::init() memset(static_unique_id, 0, len); S32 ret_code = 0; #if LL_WINDOWS -# pragma comment(lib, "wbemuuid.lib") - // algorithm to detect BIOS serial number found at: - // http://msdn.microsoft.com/en-us/library/aa394077%28VS.85%29.aspx - // we can't use the MAC address since on Windows 7, the first returned MAC address changes with every reboot. + LLWMIMethods comInit; + if (comInit.getWindowsProductNumber(static_legacy_id, len)) + { + // Bios id can change on windows update, so it is not the best id to use + // but since old viewer already use them, we might need this id to decode + // passwords + has_static_legacy_id = true; + } - HRESULT hres; - - // Step 1: -------------------------------------------------- - // Initialize COM. ------------------------------------------ - - LLComInitialize comInit; - - // Step 2: -------------------------------------------------- - // Set general COM security levels -------------------------- - // Note: If you are using Windows 2000, you need to specify - - // the default authentication credentials for a user by using - // a SOLE_AUTHENTICATION_LIST structure in the pAuthList ---- - // parameter of CoInitializeSecurity ------------------------ - - hres = CoInitializeSecurity( - NULL, - -1, // COM authentication - NULL, // Authentication services - NULL, // Reserved - RPC_C_AUTHN_LEVEL_DEFAULT, // Default authentication - RPC_C_IMP_LEVEL_IMPERSONATE, // Default Impersonation - NULL, // Authentication info - EOAC_NONE, // Additional capabilities - NULL // Reserved - ); - - - if (FAILED(hres)) - { - LL_WARNS("AppInit") << "Failed to initialize security. Error code = 0x" << hex << hres << LL_ENDL; - return 1; // Program has failed. - } - - // Step 3: --------------------------------------------------- - // Obtain the initial locator to WMI ------------------------- - - IWbemLocator *pLoc = NULL; - - hres = CoCreateInstance( - CLSID_WbemLocator, - 0, - CLSCTX_INPROC_SERVER, - IID_IWbemLocator, (LPVOID *) &pLoc); - - if (FAILED(hres)) - { - LL_WARNS("AppInit") << "Failed to create IWbemLocator object." << " Err code = 0x" << hex << hres << LL_ENDL; - return 1; // Program has failed. - } - - // Step 4: ----------------------------------------------------- - // Connect to WMI through the IWbemLocator::ConnectServer method - - IWbemServices *pSvc = NULL; - - // Connect to the root\cimv2 namespace with - // the current user and obtain pointer pSvc - // to make IWbemServices calls. - hres = pLoc->ConnectServer( - _bstr_t(L"ROOT\\CIMV2"), // Object path of WMI namespace - NULL, // User name. NULL = current user - NULL, // User password. NULL = current - 0, // Locale. NULL indicates current - NULL, // Security flags. - 0, // Authority (e.g. Kerberos) - 0, // Context object - &pSvc // pointer to IWbemServices proxy - ); - - if (FAILED(hres)) - { - LL_WARNS("AppInit") << "Could not connect. Error code = 0x" << hex << hres << LL_ENDL; - pLoc->Release(); - return 1; // Program has failed. - } - - LL_DEBUGS("AppInit") << "Connected to ROOT\\CIMV2 WMI namespace" << LL_ENDL; - - - // Step 5: -------------------------------------------------- - // Set security levels on the proxy ------------------------- - - hres = CoSetProxyBlanket( - pSvc, // Indicates the proxy to set - RPC_C_AUTHN_WINNT, // RPC_C_AUTHN_xxx - RPC_C_AUTHZ_NONE, // RPC_C_AUTHZ_xxx - NULL, // Server principal name - RPC_C_AUTHN_LEVEL_CALL, // RPC_C_AUTHN_LEVEL_xxx - RPC_C_IMP_LEVEL_IMPERSONATE, // RPC_C_IMP_LEVEL_xxx - NULL, // client identity - EOAC_NONE // proxy capabilities - ); - - if (FAILED(hres)) - { - LL_WARNS("AppInit") << "Could not set proxy blanket. Error code = 0x" << hex << hres << LL_ENDL; - pSvc->Release(); - pLoc->Release(); - return 1; // Program has failed. - } - - // Step 6: -------------------------------------------------- - // Use the IWbemServices pointer to make requests of WMI ---- - - // For example, get the name of the operating system - IEnumWbemClassObject* pEnumerator = NULL; - hres = pSvc->ExecQuery( - bstr_t("WQL"), - bstr_t("SELECT * FROM Win32_OperatingSystem"), - WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, - NULL, - &pEnumerator); - - if (FAILED(hres)) - { - LL_WARNS("AppInit") << "Query for operating system name failed." << " Error code = 0x" << hex << hres << LL_ENDL; - pSvc->Release(); - pLoc->Release(); - return 1; // Program has failed. - } - - // Step 7: ------------------------------------------------- - // Get the data from the query in step 6 ------------------- - - IWbemClassObject *pclsObj = NULL; - ULONG uReturn = 0; - - while (pEnumerator) - { - HRESULT hr = pEnumerator->Next(WBEM_INFINITE, 1, - &pclsObj, &uReturn); - - if(0 == uReturn) - { - break; - } - - VARIANT vtProp; - - // Get the value of the Name property - hr = pclsObj->Get(L"SerialNumber", 0, &vtProp, 0, 0); - if (FAILED(hr)) - { - LL_WARNS() << "Failed to get SerialNumber. Error code = 0x" << hex << hres << LL_ENDL; - pclsObj->Release(); - pclsObj = NULL; - continue; - } - LL_INFOS("AppInit") << " Serial Number : " << vtProp.bstrVal << LL_ENDL; - - // use characters in the returned Serial Number to create a byte array of size len - BSTR serialNumber ( vtProp.bstrVal); - unsigned int serial_size = SysStringLen(serialNumber); - unsigned int j = 0; - - while (j < serial_size && vtProp.bstrVal[j] != 0) - { - for (unsigned int i = 0; i < len; i++) - { - if (j >= serial_size || vtProp.bstrVal[j] == 0) - break; - - static_unique_id[i] = (unsigned int)(static_unique_id[i] + serialNumber[j]); - j++; - } - } - VariantClear(&vtProp); - - pclsObj->Release(); - pclsObj = NULL; - break; - } - - // Cleanup - // ======== - - if (pSvc) - pSvc->Release(); - if (pLoc) - pLoc->Release(); - if (pEnumerator) - pEnumerator->Release(); - ret_code=0; -#else - unsigned char * staticPtr = (unsigned char *)(&static_unique_id[0]); - ret_code = LLUUID::getNodeID(staticPtr); -#endif + // Try motherboard/bios id, if it is present it is supposed to be sufficiently unique + if (comInit.getComputerSystemProductUUID(static_unique_id, len)) + { has_static_unique_id = true; + LL_DEBUGS("AppInit") << "Using product uuid as unique id" << LL_ENDL; + } + + // Fallback to legacy + if (!has_static_unique_id) + { + if (has_static_legacy_id) + { + memcpy(static_unique_id, &static_legacy_id, len); + // Since ids are identical, mark legacy as not present + // to not cause retry's in sechandler + has_static_legacy_id = false; + has_static_unique_id = true; + LL_DEBUGS("AppInit") << "Using legacy serial" << LL_ENDL; + } + else + { + return 1; // Program has failed. + } + } + + ret_code=0; +#elif LL_DARWIN + if (getSerialNumber(static_unique_id, len)) + { + has_static_unique_id = true; + LL_DEBUGS("AppInit") << "Using Serial number as unique id" << LL_ENDL; + } + + { + unsigned char * staticPtr = (unsigned char *)(&static_legacy_id[0]); + ret_code = LLUUID::getNodeID(staticPtr); + has_static_legacy_id = true; + } + + // Fallback to legacy + if (!has_static_unique_id) + { + if (has_static_legacy_id) + { + memcpy(static_unique_id, &static_legacy_id, len); + // Since ids are identical, mark legacy as not present + // to not cause retry's in sechandler + has_static_legacy_id = false; + has_static_unique_id = true; + LL_DEBUGS("AppInit") << "Using legacy serial" << LL_ENDL; + } + } +#else + unsigned char * staticPtr = (unsigned char *)(&static_unique_id[0]); + ret_code = LLUUID::getNodeID(staticPtr); + has_static_unique_id = true; + has_static_legacy_id = false; +#endif LL_INFOS("AppInit") << "UniqueID: 0x"; // Code between here and LL_ENDL is not executed unless the LL_DEBUGS @@ -292,3 +499,13 @@ S32 LLMachineID::getUniqueID(unsigned char *unique_id, size_t len) } return 0; } + +S32 LLMachineID::getLegacyID(unsigned char *unique_id, size_t len) +{ + if (has_static_legacy_id) + { + memcpy(unique_id, &static_legacy_id, len); + return 1; + } + return 0; +} diff --git a/indra/newview/llmachineid.h b/indra/newview/llmachineid.h index 6ef8c36fdb..ec1e855031 100644 --- a/indra/newview/llmachineid.h +++ b/indra/newview/llmachineid.h @@ -34,6 +34,8 @@ public: LLMachineID(); virtual ~LLMachineID(); static S32 getUniqueID(unsigned char *unique_id, size_t len); + // fallback id for windows + static S32 getLegacyID(unsigned char *unique_id, size_t len); static S32 init(); protected: diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp index 0c5cc892ae..45916f7262 100644 --- a/indra/newview/llmeshrepository.cpp +++ b/indra/newview/llmeshrepository.cpp @@ -1738,6 +1738,10 @@ bool LLMeshRepoThread::fetchMeshHeader(const LLVolumeParams& mesh_params, bool c file.read(buffer, bytes); if (headerReceived(mesh_params, buffer, bytes) == MESH_OK) { + std::string mid; + mesh_params.getSculptID().toString(mid); + LL_DEBUGS(LOG_MESH) << "Mesh/Cache: Mesh header for ID " << mid << " - was retrieved from the cache." << LL_ENDL; + // Found mesh in cache return true; } @@ -1753,8 +1757,13 @@ bool LLMeshRepoThread::fetchMeshHeader(const LLVolumeParams& mesh_params, bool c constructUrl(mesh_params.getSculptID(), &http_url, &legacy_cap_version); // [UDP Assets] + if (!http_url.empty()) { + std::string mid; + mesh_params.getSculptID().toString(mid); + LL_DEBUGS(LOG_MESH) << "Mesh/Cache: Mesh header for ID " << mid << " - was retrieved from the simulator." << LL_ENDL; + //grab first 4KB if we're going to bother with a fetch. Cache will prevent future fetches if a full mesh fits //within the first 4KB //NOTE -- this will break of headers ever exceed 4KB @@ -1838,6 +1847,11 @@ bool LLMeshRepoThread::fetchMeshLOD(const LLVolumeParams& mesh_params, S32 lod, if (lodReceived(mesh_params, lod, buffer, size) == MESH_OK) { delete[] buffer; + + std::string mid; + mesh_id.toString(mid); + LL_DEBUGS(LOG_MESH) << "Mesh/Cache: Mesh body for ID " << mid << " - was retrieved from the cache." << LL_ENDL; + return true; } } @@ -1852,9 +1866,13 @@ bool LLMeshRepoThread::fetchMeshLOD(const LLVolumeParams& mesh_params, S32 lod, int legacy_cap_version(0); constructUrl(mesh_id, &http_url, &legacy_cap_version); // [UDP Assets] - + if (!http_url.empty()) { + std::string mid; + mesh_id.toString(mid); + LL_DEBUGS(LOG_MESH) << "Mesh/Cache: Mesh body for ID " << mid << " - was retrieved from the simulator." << LL_ENDL; + LLMeshHandlerBase::ptr_t handler(new LLMeshLODHandler(mesh_params, lod, offset, size)); // [UDP Assets] //LLCore::HttpHandle handle = getByteRange(http_url, offset, size, handler); diff --git a/indra/newview/llnamelistctrl.cpp b/indra/newview/llnamelistctrl.cpp index f82595097c..de04ec5e63 100644 --- a/indra/newview/llnamelistctrl.cpp +++ b/indra/newview/llnamelistctrl.cpp @@ -71,9 +71,11 @@ LLNameListCtrl::LLNameListCtrl(const LLNameListCtrl::Params& p) mNameColumnIndex(p.name_column.column_index), mNameColumn(p.name_column.column_name), mAllowCallingCardDrop(p.allow_calling_card_drop), - mShortNames(p.short_names) + mShortNames(p.short_names), // Fix Baker's NameListCtrl un-fix - //mPendingLookupsRemaining(0) + //mPendingLookupsRemaining(0), + mHoverIconName("Info_Small"), + mNameListType(INDIVIDUAL) {} // public @@ -140,7 +142,12 @@ BOOL LLNameListCtrl::handleDragAndDrop( void LLNameListCtrl::showInspector(const LLUUID& avatar_id, bool is_group, bool is_experience) { - if(is_experience) + if (isSpecialType()) + { + mIconClickedSignal(avatar_id); + return; + } + if(is_experience) { LLFloaterReg::showInstance("experience_profile", avatar_id, true); return; @@ -224,14 +231,16 @@ BOOL LLNameListCtrl::handleToolTip(S32 x, S32 y, MASK mask) S32 column_index = getColumnIndexFromOffset(x); LLNameListItem* hit_item = dynamic_cast(hitItem(x, y)); LLFloater* floater = gFloaterView->getParentFloater(this); - if (floater + + + if (floater && floater->isFrontmost() && hit_item - && column_index == mNameColumnIndex) + && ((column_index == mNameColumnIndex) || isSpecialType())) { - // ...this is the column with the avatar name - LLUUID avatar_id = hit_item->getUUID(); - if (avatar_id.notNull()) + // ...this is the column with the avatar name + LLUUID item_id = isSpecialType() ? hit_item->getSpecialID() : hit_item->getUUID(); + if (item_id.notNull()) { // ...valid avatar id @@ -239,13 +248,13 @@ BOOL LLNameListCtrl::handleToolTip(S32 x, S32 y, MASK mask) if (hit_cell) { S32 row_index = getItemIndex(hit_item); - LLRect cell_rect = getCellRect(row_index, column_index); + LLRect cell_rect = getCellRect(row_index, isSpecialType() ? getNumColumns() - 1 : column_index); // Convert rect local to screen coordinates LLRect sticky_rect; localRectToScreen(cell_rect, &sticky_rect); // Spawn at right side of cell - LLPointer icon = LLUI::getUIImage("Info_Small"); + LLPointer icon = LLUI::getUIImage(mHoverIconName); S32 screenX = sticky_rect.mRight - info_icon_size; S32 screenY = sticky_rect.mTop - (sticky_rect.getHeight() - icon->getHeight()) / 2; LLCoordGL pos(screenX, screenY); @@ -259,7 +268,7 @@ BOOL LLNameListCtrl::handleToolTip(S32 x, S32 y, MASK mask) LLToolTip::Params params; params.background_visible(false); - params.click_callback(boost::bind(&LLNameListCtrl::showInspector, this, avatar_id, is_group, is_experience)); + params.click_callback(boost::bind(&LLNameListCtrl::showInspector, this, item_id, is_group, is_experience)); params.delay_time(0.0f); // spawn instantly on hover params.image(icon); params.message(""); @@ -336,6 +345,7 @@ LLScrollListItem* LLNameListCtrl::addNameItemRow( // use supplied name by default std::string fullname = name_item.name; + switch(name_item.target) { case GROUP: @@ -354,8 +364,10 @@ LLScrollListItem* LLNameListCtrl::addNameItemRow( } break; case SPECIAL: - // just use supplied name - break; + { + item->setSpecialID(name_item.special_id()); + return item; + } case INDIVIDUAL: { LLAvatarName av_name; @@ -366,7 +378,7 @@ LLScrollListItem* LLNameListCtrl::addNameItemRow( else if (LLAvatarNameCache::get(id, &av_name)) { if (mShortNames) - fullname = av_name.getDisplayName(); + fullname = av_name.getDisplayName(true); else fullname = av_name.getCompleteName(); } @@ -437,7 +449,8 @@ void LLNameListCtrl::removeNameItem(const LLUUID& agent_id) for (item_list::iterator it = getItemList().begin(); it != getItemList().end(); it++) { LLScrollListItem* item = *it; - if (item->getUUID() == agent_id) + LLUUID cur_id = isSpecialType() ? dynamic_cast(item)->getSpecialID() : item->getUUID(); + if (cur_id == agent_id) { idx = getItemIndex(item); break; @@ -469,6 +482,34 @@ LLScrollListItem* LLNameListCtrl::getNameItemByAgentId(const LLUUID& agent_id) return NULL; } +void LLNameListCtrl::selectItemBySpecialId(const LLUUID& special_id) +{ + if (special_id.isNull()) + { + return; + } + + for (item_list::iterator it = getItemList().begin(); it != getItemList().end(); it++) + { + LLNameListItem* item = dynamic_cast(*it); + if (item && item->getSpecialID() == special_id) + { + item->setSelected(TRUE); + break; + } + } +} + +LLUUID LLNameListCtrl::getSelectedSpecialId() +{ + LLNameListItem* item = dynamic_cast(getFirstSelected()); + if(item) + { + return item->getSpecialID(); + } + return LLUUID(); +} + void LLNameListCtrl::onAvatarNameCache(const LLUUID& agent_id, const LLAvatarName& av_name, std::string suffix, diff --git a/indra/newview/llnamelistctrl.h b/indra/newview/llnamelistctrl.h index e7c11a343b..ca81c8bfd9 100644 --- a/indra/newview/llnamelistctrl.h +++ b/indra/newview/llnamelistctrl.h @@ -52,6 +52,8 @@ public: void setIsGroup(bool is_group) { mIsGroup = is_group; } bool isExperience() const { return mIsExperience; } void setIsExperience(bool is_experience) { mIsExperience = is_experience; } + void setSpecialID(const LLUUID& special_id) { mSpecialID = special_id; } + const LLUUID& getSpecialID() const { return mSpecialID; } protected: friend class LLNameListCtrl; @@ -74,6 +76,8 @@ protected: private: bool mIsGroup; bool mIsExperience; + + LLUUID mSpecialID; }; @@ -104,10 +108,12 @@ public: { Optional name; Optional target; + Optional special_id; NameItem() : name("name"), - target("target", INDIVIDUAL) + target("target", INDIVIDUAL), + special_id("special_id", LLUUID()) {} }; @@ -168,6 +174,9 @@ public: LLScrollListItem* getNameItemByAgentId(const LLUUID& agent_id); + void selectItemBySpecialId(const LLUUID& special_id); + LLUUID getSelectedSpecialId(); + // LLView interface /*virtual*/ BOOL handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, EDragAndDropType cargo_type, void *cargo_data, @@ -182,6 +191,12 @@ public: /*virtual*/ void updateColumns(bool force_update); /*virtual*/ void mouseOverHighlightNthItem( S32 index ); + + bool isSpecialType() { return (mNameListType == SPECIAL); } + + void setNameListType(e_name_type type) { mNameListType = type; } + void setHoverIconName(std::string icon_name) { mHoverIconName = icon_name; } + private: void showInspector(const LLUUID& avatar_id, bool is_group, bool is_experience = false); void onAvatarNameCache(const LLUUID& agent_id, const LLAvatarName& av_name, std::string suffix, std::string prefix, LLHandle item); @@ -196,17 +211,28 @@ private: avatar_name_cache_connection_map_t mAvatarNameCacheConnections; avatar_name_cache_connection_map_t mGroupNameCacheConnections; -// Fix Baker's NameListCtrl un-fix -// S32 mPendingLookupsRemaining; -// namelist_complete_signal_t mNameListCompleteSignal; -// -//public: -// boost::signals2::connection setOnNameListCompleteCallback(boost::function onNameListCompleteCallback) -// { -// return mNameListCompleteSignal.connect(onNameListCompleteCallback); -// } -// + // Fix Baker's NameListCtrl un-fix + //S32 mPendingLookupsRemaining; + //namelist_complete_signal_t mNameListCompleteSignal; + // + std::string mHoverIconName; + e_name_type mNameListType; + + boost::signals2::signal mIconClickedSignal; + +public: + // Fix Baker's NameListCtrl un-fix + //boost::signals2::connection setOnNameListCompleteCallback(boost::function onNameListCompleteCallback) + //{ + // return mNameListCompleteSignal.connect(onNameListCompleteCallback); + //} + // + + boost::signals2::connection setIconClickedCallback(boost::function cb) + { + return mIconClickedSignal.connect(cb); + } }; diff --git a/indra/newview/llnotificationmanager.cpp b/indra/newview/llnotificationmanager.cpp index a6f20a9f27..b06131cf38 100644 --- a/indra/newview/llnotificationmanager.cpp +++ b/indra/newview/llnotificationmanager.cpp @@ -63,7 +63,7 @@ void LLNotificationManager::init() mChannels.push_back(new LLBrowserNotification()); mChannels.push_back(new LLIMHandler()); - mChatHandler = boost::shared_ptr(new LLFloaterIMNearbyChatHandler()); + mChatHandler = std::shared_ptr(new LLFloaterIMNearbyChatHandler()); } //-------------------------------------------------------------------------- diff --git a/indra/newview/llnotificationmanager.h b/indra/newview/llnotificationmanager.h index fc74eb7da8..744595dc6a 100644 --- a/indra/newview/llnotificationmanager.h +++ b/indra/newview/llnotificationmanager.h @@ -35,8 +35,6 @@ #include #include -#include - namespace LLNotificationsUI { class LLToast; @@ -60,10 +58,10 @@ public: void onChat(const LLChat& msg, const LLSD &args); // Getter for mChatHandler - boost::shared_ptr getChatHandler() const { return mChatHandler; } + std::shared_ptr getChatHandler() const { return mChatHandler; } private: - boost::shared_ptr mChatHandler; + std::shared_ptr mChatHandler; std::vector mChannels; }; diff --git a/indra/newview/lloutfitgallery.cpp b/indra/newview/lloutfitgallery.cpp index fa5187dce6..dfcfab5f1c 100644 --- a/indra/newview/lloutfitgallery.cpp +++ b/indra/newview/lloutfitgallery.cpp @@ -903,7 +903,7 @@ void LLOutfitGalleryContextMenu::onOutfitsRemovalConfirmation(const LLSD& notifi void LLOutfitGalleryContextMenu::onCreate(const LLSD& data) { - LLWearableType::EType type = LLWearableType::typeNameToType(data.asString()); + LLWearableType::EType type = LLWearableType::getInstance()->typeNameToType(data.asString()); if (type == LLWearableType::WT_NONE) { LL_WARNS() << "Invalid wearable type" << LL_ENDL; diff --git a/indra/newview/lloutfitslist.cpp b/indra/newview/lloutfitslist.cpp index bb43a61c45..e0c79b58eb 100644 --- a/indra/newview/lloutfitslist.cpp +++ b/indra/newview/lloutfitslist.cpp @@ -1350,7 +1350,7 @@ void LLOutfitListGearMenuBase::onRename() void LLOutfitListGearMenuBase::onCreate(const LLSD& data) { - LLWearableType::EType type = LLWearableType::typeNameToType(data.asString()); + LLWearableType::EType type = LLWearableType::getInstance()->typeNameToType(data.asString()); if (type == LLWearableType::WT_NONE) { LL_WARNS() << "Invalid wearable type" << LL_ENDL; diff --git a/indra/newview/llpaneleditwearable.cpp b/indra/newview/llpaneleditwearable.cpp index 29dfca4a63..f5bb006e3a 100644 --- a/indra/newview/llpaneleditwearable.cpp +++ b/indra/newview/llpaneleditwearable.cpp @@ -1403,7 +1403,7 @@ void LLPanelEditWearable::changeCamera(U8 subpart) { // Don't change the camera if this type doesn't have a camera switch. // Useful for wearables like physics that don't have an associated physical body part. - if (LLWearableType::getDisableCameraSwitch(mWearablePtr->getType())) + if (LLWearableType::getInstance()->getDisableCameraSwitch(mWearablePtr->getType())) { return; } diff --git a/indra/newview/llpanelexperiencepicker.cpp b/indra/newview/llpanelexperiencepicker.cpp index c58d83152f..5acd83c2f5 100644 --- a/indra/newview/llpanelexperiencepicker.cpp +++ b/indra/newview/llpanelexperiencepicker.cpp @@ -41,8 +41,8 @@ #include "llcombobox.h" #include "llviewercontrol.h" #include "llfloater.h" +#include "llregex.h" #include "lltrans.h" -#include #define BTN_FIND "find" #define BTN_OK "ok_btn" @@ -116,7 +116,7 @@ void LLPanelExperiencePicker::onBtnFind() boost::cmatch what; std::string text = getChild(TEXT_EDIT)->getValue().asString(); const boost::regex expression("secondlife:///app/experience/[\\da-f-]+/profile"); - if (boost::regex_match(text.c_str(), what, expression)) + if (ll_regex_match(text.c_str(), what, expression)) { LLURI uri(text); LLSD path_array = uri.pathArray(); diff --git a/indra/newview/llpanelface.cpp b/indra/newview/llpanelface.cpp index d00f4b4d1a..8c4562dd65 100644 --- a/indra/newview/llpanelface.cpp +++ b/indra/newview/llpanelface.cpp @@ -463,7 +463,8 @@ void LLPanelFace::sendBump(U32 bumpiness) // LLSelectedTEMaterial::setNormalID(this, current_normal_map); - LLSelectMgr::getInstance()->selectionSetBumpmap( bump ); + //LLSelectMgr::getInstance()->selectionSetBumpmap(bump, bumpytexture_ctrl->getImageItemID()); + LLSelectMgr::getInstance()->selectionSetBumpmap(bump, mBumpyTextureCtrl->getImageItemID()); } void LLPanelFace::sendTexGen() @@ -495,7 +496,8 @@ void LLPanelFace::sendShiny(U32 shininess) LLSelectedTEMaterial::setSpecularID(this, specmap); - LLSelectMgr::getInstance()->selectionSetShiny( shiny ); + //LLSelectMgr::getInstance()->selectionSetShiny(shiny, texture_ctrl->getImageItemID()); + LLSelectMgr::getInstance()->selectionSetShiny(shiny, mShinyTextureCtrl->getImageItemID()); updateShinyControls(!specmap.isNull(), true); diff --git a/indra/newview/llpanelgroupcreate.cpp b/indra/newview/llpanelgroupcreate.cpp index c47a827077..d1f9826931 100644 --- a/indra/newview/llpanelgroupcreate.cpp +++ b/indra/newview/llpanelgroupcreate.cpp @@ -138,6 +138,7 @@ void LLPanelGroupCreate::refreshCreatedGroup(const LLUUID& group_id) } // LLStatusBar::sendMoneyBalanceRequest(); + } void LLPanelGroupCreate::addMembershipRow(const std::string &name) diff --git a/indra/newview/llpanellandmarks.cpp b/indra/newview/llpanellandmarks.cpp index dca3c9072b..64952fad4f 100644 --- a/indra/newview/llpanellandmarks.cpp +++ b/indra/newview/llpanellandmarks.cpp @@ -57,6 +57,7 @@ #include "llviewerregion.h" #include "fsfloaterplacedetails.h" // [RLVa:KB] +#include "rlvactions.h" #include "rlvhandler.h" // [/RLVa:KB] @@ -753,7 +754,9 @@ bool LLLandmarksPanel::isActionEnabled(const LLSD& userdata) const if (asset_uuid.isNull()) return false; // Disable "Show on Map" if landmark loading is in progress. - return !gLandmarkList.isAssetInLoadedCallbackMap(asset_uuid); + // RLVa fix + //return !gLandmarkList.isAssetInLoadedCallbackMap(asset_uuid); + return !gLandmarkList.isAssetInLoadedCallbackMap(asset_uuid) && !gRlvHandler.hasBehaviour(RLV_BHVR_SHOWWORLDMAP); } else if ("rename" == command_name) { @@ -762,6 +765,12 @@ bool LLLandmarksPanel::isActionEnabled(const LLSD& userdata) const return canItemBeModified(command_name, selected_item); } + // RLVa fix + else if ("teleport" == command_name) + { + return !gRlvHandler.hasBehaviour(RLV_BHVR_TPLM); + } + // return true; } @@ -784,6 +793,13 @@ bool LLLandmarksPanel::isActionEnabled(const LLSD& userdata) const } else if ("add_landmark" == command_name) { +// [RLVa:KB] - Checked: 2012-02-08 (RLVa-1.4.5) | Added: RLVa-1.4.5 + if (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC)) + { + return false; + } +// [/RLVa:KB] + if (!is_single_selection) { return false; @@ -800,23 +816,24 @@ bool LLLandmarksPanel::isActionEnabled(const LLSD& userdata) const //already exists return false; } - // RLVa check - //return true; - return !gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC); - // + return true; } else if ("add_landmark_root" == command_name) { +// [RLVa:KB] - Checked: 2012-02-08 (RLVa-1.4.5) | Added: RLVa-1.4.5 + if (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC)) + { + return false; + } +// [/RLVa:KB] + LLViewerInventoryItem* landmark = LLLandmarkActions::findLandmarkForAgentPos(); if (landmark) { //already exists return false; } - // RLVa check - //return true; - return !gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC); - // + return true; } else if ("share" == command_name) { diff --git a/indra/newview/llpanelmaininventory.cpp b/indra/newview/llpanelmaininventory.cpp index 636efef275..66327eb7dc 100644 --- a/indra/newview/llpanelmaininventory.cpp +++ b/indra/newview/llpanelmaininventory.cpp @@ -71,15 +71,11 @@ bool LLPanelMainInventory::sSaveFilters = true; const std::string FILTERS_FILENAME("filters.xml"); -static LLPanelInjector t_inventory("panel_main_inventory"); +const std::string ALL_ITEMS("All Items"); +const std::string RECENT_ITEMS("Recent Items"); +const std::string WORN_ITEMS("Worn Items"); -void on_file_loaded_for_save(BOOL success, - LLViewerFetchedTexture *src_vi, - LLImageRaw* src, - LLImageRaw* aux_src, - S32 discard_level, - BOOL final, - void* userdata); +static LLPanelInjector t_inventory("panel_main_inventory"); ///---------------------------------------------------------------------------- /// LLFloaterInventoryFinder @@ -222,7 +218,7 @@ BOOL LLPanelMainInventory::postBuild() //panel->getFilter().markDefault(); // Set up the default inv. panel/filter settings. - mActivePanel = getChild("All Items"); + mActivePanel = getChild(ALL_ITEMS); if (mActivePanel) { // "All Items" is the previous only view, so it gets the InventorySortOrder @@ -232,7 +228,7 @@ BOOL LLPanelMainInventory::postBuild() mActivePanel->setSelectCallback(boost::bind(&LLPanelMainInventory::onSelectionChange, this, mActivePanel, _1, _2)); mResortActivePanel = true; } - LLInventoryPanel* recent_items_panel = getChild("Recent Items"); + LLInventoryPanel* recent_items_panel = getChild(RECENT_ITEMS); if (recent_items_panel) { // assign default values until we will be sure that we have setting to restore @@ -250,7 +246,7 @@ BOOL LLPanelMainInventory::postBuild() recent_items_panel->setSelectCallback(boost::bind(&LLPanelMainInventory::onSelectionChange, this, recent_items_panel, _1, _2)); } - LLInventoryPanel* mWornItemsPanel = getChild("Worn Items"); + mWornItemsPanel = getChild(WORN_ITEMS); if (mWornItemsPanel) { U32 filter_types = 0x0; @@ -376,7 +372,7 @@ LLPanelMainInventory::~LLPanelMainInventory( void ) // for example, LLParamSDParser doesn't know about U64, // so some FilterOps params should be revised. LLSD filterRoot; - LLInventoryPanel* all_items_panel = getChild("All Items"); + LLInventoryPanel* all_items_panel = getChild(ALL_ITEMS); if (all_items_panel) { LLSD filterState; @@ -390,7 +386,7 @@ LLPanelMainInventory::~LLPanelMainInventory( void ) } } - LLInventoryPanel* panel = findChild("Recent Items"); + LLInventoryPanel* panel = findChild(RECENT_ITEMS); if (panel) { LLSD filterState; @@ -428,7 +424,7 @@ LLPanelMainInventory::~LLPanelMainInventory( void ) LLInventoryPanel* LLPanelMainInventory::getAllItemsPanel() { - return getChild("All Items"); + return getChild(ALL_ITEMS); } void LLPanelMainInventory::selectAllItemsPanel() @@ -436,6 +432,11 @@ void LLPanelMainInventory::selectAllItemsPanel() mFilterTabs->selectFirstTab(); } +bool LLPanelMainInventory::isRecentItemsPanelSelected() +{ + return (RECENT_ITEMS == getActivePanel()->getName()); +} + void LLPanelMainInventory::startSearch() { // this forces focus to line editor portion of search editor @@ -623,7 +624,7 @@ void LLPanelMainInventory::setSortBy(const LLSD& userdata) getActivePanel()->setSortOrder(sort_order_mask); // Recent items panel should save sort order - //if ("Recent Items" == getActivePanel()->getName()) + //if (isRecentItemsPanelSelected()) //{ // gSavedSettings.setU32("RecentItemsSortOrder", sort_order_mask); //} @@ -1176,8 +1177,8 @@ void LLPanelMainInventory::toggleFindOptions() void LLPanelMainInventory::setSelectCallback(const LLFolderView::signal_t::slot_type& cb) { - getChild("All Items")->setSelectCallback(cb); - getChild("Recent Items")->setSelectCallback(cb); + getChild(ALL_ITEMS)->setSelectCallback(cb); + getChild(RECENT_ITEMS)->setSelectCallback(cb); getChild("Worn Items")->setSelectCallback(cb); } @@ -1647,11 +1648,11 @@ void LLPanelMainInventory::onAddButtonClick() { // Gray out the "New Folder" option when the Recent tab is active as new folders will not be displayed // unless "Always show folders" is checked in the filter options. - bool recent_active = ("Recent Items" == mActivePanel->getName()); + LLMenuGL* menu = (LLMenuGL*)mMenuAddHandle.get(); if (menu) { - menu->getChild("New Folder")->setEnabled(!recent_active); + menu->getChild("New Folder")->setEnabled(!isRecentItemsPanelSelected()); setUploadCostIfNeeded(); diff --git a/indra/newview/llpanelmaininventory.h b/indra/newview/llpanelmaininventory.h index ce264784c9..b51060233f 100644 --- a/indra/newview/llpanelmaininventory.h +++ b/indra/newview/llpanelmaininventory.h @@ -88,6 +88,8 @@ public: void showAllItemsPanel(); // + bool isRecentItemsPanelSelected(); + const std::string& getFilterText() const { return mFilterText; } void setSelectCallback(const LLFolderView::signal_t::slot_type& cb); diff --git a/indra/newview/llpanelobject.cpp b/indra/newview/llpanelobject.cpp index 157fa4e182..85760d5fe2 100644 --- a/indra/newview/llpanelobject.cpp +++ b/indra/newview/llpanelobject.cpp @@ -1142,7 +1142,7 @@ void LLPanelObject::getState( ) mSpinScaleY->setMaxValue(OBJECT_MAX_HOLE_SIZE_Y); break; default: - if (editable) + if (editable && single_volume) { // Make sure to use the correct values for the LL default types. These // should be handled by the explicit cases and the ones in this if-condition. diff --git a/indra/newview/llpaneloutfitedit.cpp b/indra/newview/llpaneloutfitedit.cpp index 57abb245c7..58a642f53e 100644 --- a/indra/newview/llpaneloutfitedit.cpp +++ b/indra/newview/llpaneloutfitedit.cpp @@ -102,7 +102,7 @@ std::string LLShopURLDispatcher::resolveURL(LLWearableType::EType wearable_type, { const std::string prefix = "MarketplaceURL"; const std::string sex_str = (sex == SEX_MALE) ? "Male" : "Female"; - const std::string type_str = LLWearableType::getTypeName(wearable_type); + const std::string type_str = LLWearableType::getInstance()->getTypeName(wearable_type); std::string setting_name = prefix; @@ -178,7 +178,7 @@ public: private: static void onCreate(const LLSD& param) { - LLWearableType::EType type = LLWearableType::typeNameToType(param.asString()); + LLWearableType::EType type = LLWearableType::getInstance()->typeNameToType(param.asString()); if (type == LLWearableType::WT_NONE) { LL_WARNS() << "Invalid wearable type" << LL_ENDL; @@ -193,19 +193,20 @@ private: { LLView* menu_clothes = gMenuHolder->getChildView("COF.Gear.New_Clothes", FALSE); LLView* menu_bp = gMenuHolder->getChildView("COF.Gear.New_Body_Parts", FALSE); + LLWearableType * wearable_type_inst = LLWearableType::getInstance(); for (U8 i = LLWearableType::WT_SHAPE; i != (U8) LLWearableType::WT_COUNT; ++i) { LLWearableType::EType type = (LLWearableType::EType) i; - const std::string& type_name = LLWearableType::getTypeName(type); + const std::string& type_name = wearable_type_inst->getTypeName(type); LLMenuItemCallGL::Params p; p.name = type_name; - p.label = LLTrans::getString(LLWearableType::getTypeDefaultNewName(type)); + p.label = LLTrans::getString(wearable_type_inst->getTypeDefaultNewName(type)); p.on_click.function_name = "Wearable.Create"; p.on_click.parameter = LLSD(type_name); - LLView* parent = LLWearableType::getAssetType(type) == LLAssetType::AT_CLOTHING ? menu_clothes : menu_bp; + LLView* parent = wearable_type_inst->getAssetType(type) == LLAssetType::AT_CLOTHING ? menu_clothes : menu_bp; LLUICtrlFactory::create(p, parent); } } diff --git a/indra/newview/llpanelpeople.cpp b/indra/newview/llpanelpeople.cpp index 17e0053309..1491282d4b 100644 --- a/indra/newview/llpanelpeople.cpp +++ b/indra/newview/llpanelpeople.cpp @@ -807,7 +807,7 @@ BOOL LLPanelPeople::postBuild() if (mContactSetList) { mContactSetList->setCommitCallback(boost::bind(&LLPanelPeople::updateButtons, this)); - mContactSetList->setDoubleClickCallback(boost::bind(&LLPanelPeople::onAvatarListDoubleClicked, this, _1)); + mContactSetList->setItemDoubleClickCallback(boost::bind(&LLPanelPeople::onAvatarListDoubleClicked, this, _1)); mContactSetList->setNoItemsCommentText(getString("empty_list")); mContactSetList->setContextMenu(&LLPanelPeopleMenus::gPeopleContextMenu); generateCurrentContactList(); diff --git a/indra/newview/llpanelplaces.cpp b/indra/newview/llpanelplaces.cpp index d7b07dc5f8..1ab1179361 100644 --- a/indra/newview/llpanelplaces.cpp +++ b/indra/newview/llpanelplaces.cpp @@ -79,6 +79,7 @@ #include "fsfloaterplacedetails.h" #include "fscommon.h" #include "rlvactions.h" +#include "rlvhandler.h" // Constants static const F32 PLACE_INFO_UPDATE_INTERVAL = 3.0; @@ -359,8 +360,9 @@ BOOL LLPanelPlaces::postBuild() mTabContainer->setCommitCallback(boost::bind(&LLPanelPlaces::onTabSelected, this)); } - mButtonsContainer = getChild("button_layout_panel"); - //mButtonsContainer->setVisible(FALSE); // FIRE-31033: Keep Teleport/Map/Profile buttons on places floater + // FIRE-31033: Keep Teleport/Map/Profile buttons on places floater + //mButtonsContainer = getChild("button_layout_panel"); + //mButtonsContainer->setVisible(FALSE); mFilterContainer = getChild("top_menu_panel"); mFilterEditor = getChild("Filter"); @@ -1127,7 +1129,8 @@ void LLPanelPlaces::togglePlaceInfoPanel(BOOL visible) return; mTabContainer->setVisible(!visible); - mButtonsContainer->setVisible(visible); + // FIRE-31033: Keep Teleport/Map/Profile buttons on places floater + //mButtonsContainer->setVisible(visible); mFilterContainer->setVisible(!visible); if (mPlaceInfoType == AGENT_INFO_TYPE || @@ -1395,6 +1398,7 @@ void LLPanelPlaces::updateVerbs() mCloseBtn->setVisible(is_create_landmark_visible && !isLandmarkEditModeOn); // FIRE-31033: Keep Teleport/Map/Profile buttons on places floater mPlaceInfoBtn->setVisible(!is_place_info_visible && !is_create_landmark_visible && !isLandmarkEditModeOn && !is_pick_panel_visible); + mShowOnMapBtn->setEnabled(!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWWORLDMAP)); bool show_options_btn = is_place_info_visible && !is_create_landmark_visible && !isLandmarkEditModeOn; mOverflowBtn->setVisible(show_options_btn); @@ -1417,13 +1421,18 @@ void LLPanelPlaces::updateVerbs() } // FIRE-9536: Teleport button disabled if standalone TP history & sidepanel TP history detail //else if (mPlaceInfoType == LANDMARK_INFO_TYPE || mPlaceInfoType == REMOTE_PLACE_INFO_TYPE) - else if (mPlaceInfoType == LANDMARK_INFO_TYPE || mPlaceInfoType == REMOTE_PLACE_INFO_TYPE || mPlaceInfoType == TELEPORT_HISTORY_INFO_TYPE) + //{ + // mTeleportBtn->setEnabled(have_3d_pos); + //} + else if (mPlaceInfoType == LANDMARK_INFO_TYPE) { - // FIRE-21863: TP restrictions can be circumvented via parcel SLURL - //mTeleportBtn->setEnabled(have_3d_pos); - mTeleportBtn->setEnabled(have_3d_pos && RlvActions::canTeleportToLocation()); - // + mTeleportBtn->setEnabled(have_3d_pos && !gRlvHandler.hasBehaviour(RLV_BHVR_TPLM)); } + else if (mPlaceInfoType == REMOTE_PLACE_INFO_TYPE || mPlaceInfoType == TELEPORT_HISTORY_INFO_TYPE) + { + mTeleportBtn->setEnabled(have_3d_pos && RlvActions::canTeleportToLocation()); + } + // } else { diff --git a/indra/newview/llpanelplaces.h b/indra/newview/llpanelplaces.h index 81f1c6d70e..f1e11bea9c 100644 --- a/indra/newview/llpanelplaces.h +++ b/indra/newview/llpanelplaces.h @@ -125,7 +125,7 @@ private: LLFilterEditor* mFilterEditor; LLPanelPlacesTab* mActivePanel; LLTabContainer* mTabContainer; - LLPanel* mButtonsContainer; + //LLPanel* mButtonsContainer; // FIRE-31033: Keep Teleport/Map/Profile buttons on places floater LLLayoutStack* mFilterContainer; LLPanelPlaceProfile* mPlaceProfile; LLPanelLandmarkInfo* mLandmarkInfo; diff --git a/indra/newview/llpanelsnapshotpostcard.cpp b/indra/newview/llpanelsnapshotpostcard.cpp index 072e367233..a883507ad6 100644 --- a/indra/newview/llpanelsnapshotpostcard.cpp +++ b/indra/newview/llpanelsnapshotpostcard.cpp @@ -38,13 +38,12 @@ #include "llfloatersnapshot.h" // FIXME: replace with a snapshot storage model #include "llpanelsnapshot.h" #include "llpostcard.h" +#include "llregex.h" #include "llsnapshotlivepreview.h" #include "llviewercontrol.h" // gSavedSettings #include "llviewerwindow.h" #include "llviewerregion.h" -#include - #include "llviewernetwork.h" /** @@ -268,14 +267,14 @@ void LLPanelSnapshotPostcard::onSend() boost::regex email_format("[A-Za-z0-9.%+-_]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}(,[ \t]*[A-Za-z0-9.%+-_]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,})*"); - if (to.empty() || !boost::regex_match(to, email_format)) + if (to.empty() || !ll_regex_match(to, email_format)) { LLNotificationsUtil::add("PromptRecipientEmail"); return; } // For OpenSim compatibility - if (!LLGridManager::instance().isInSecondLife() && (mAgentEmail.empty() || !boost::regex_match(mAgentEmail, email_format))) + if (!LLGridManager::instance().isInSecondLife() && (mAgentEmail.empty() || !ll_regex_match(mAgentEmail, email_format))) { LLNotificationsUtil::add("PromptSelfEmail"); return; diff --git a/indra/newview/llpanelteleporthistory.cpp b/indra/newview/llpanelteleporthistory.cpp index a5dbb5a212..f7426e93b2 100644 --- a/indra/newview/llpanelteleporthistory.cpp +++ b/indra/newview/llpanelteleporthistory.cpp @@ -50,6 +50,8 @@ #include // #include "llviewercontrol.h" +#include "rlvactions.h" +#include "rlvhandler.h" #include "fsfloaterplacedetails.h" @@ -673,9 +675,9 @@ void LLTeleportHistoryPanel::updateVerbs() LLTeleportHistoryFlatItem* itemp = dynamic_cast (mLastSelectedFlatlList->getSelectedItem()); - mTeleportBtn->setEnabled(NULL != itemp); + mTeleportBtn->setEnabled(NULL != itemp && RlvActions::canTeleportToLocation()); mShowProfile->setEnabled(NULL != itemp); - mShowOnMapBtn->setEnabled(NULL != itemp); + mShowOnMapBtn->setEnabled(NULL != itemp && !gRlvHandler.hasBehaviour(RLV_BHVR_SHOWWORLDMAP)); // } @@ -1318,6 +1320,17 @@ bool LLTeleportHistoryPanel::isActionEnabled(const LLSD& userdata) const return false; } LLTeleportHistoryFlatItem* itemp = dynamic_cast (mLastSelectedFlatlList->getSelectedItem()); + // RLVa fix + if ("teleport" == command_name) + { + return itemp && RlvActions::canTeleportToLocation(); + } + else if ("show_on_map" == command_name) + { + return itemp && !gRlvHandler.hasBehaviour(RLV_BHVR_SHOWWORLDMAP); + } + // + return itemp != NULL; } diff --git a/indra/newview/llpanelvolume.cpp b/indra/newview/llpanelvolume.cpp index 899e2417f0..2c2e5b7777 100644 --- a/indra/newview/llpanelvolume.cpp +++ b/indra/newview/llpanelvolume.cpp @@ -50,6 +50,7 @@ //#include "llfirstuse.h" #include "llfocusmgr.h" #include "llmanipscale.h" +#include "llinventorymodel.h" #include "llpreviewscript.h" #include "llresmgr.h" #include "llselectmgr.h" @@ -57,6 +58,7 @@ #include "lltextbox.h" #include "lltool.h" #include "lltoolcomp.h" +#include "lltooldraganddrop.h" #include "lltoolmgr.h" #include "lltrans.h" #include "llui.h" @@ -783,7 +785,7 @@ void LLPanelVolume::onLightCancelTexture(const LLSD& data) // selection of "None" texture. LLUUID tex_id = LightTextureCtrl->getImageAssetID(); bool is_spotlight = volobjp->isLightSpotlight(); - volobjp->setLightTextureID(tex_id); //updates spotlight + setLightTextureID(tex_id, LightTextureCtrl->getImageItemID(), volobjp); //updates spotlight if (!is_spotlight && tex_id.notNull()) { @@ -828,7 +830,7 @@ void LLPanelVolume::onLightSelectTexture(const LLSD& data) if(LightTextureCtrl) { LLUUID id = LightTextureCtrl->getImageAssetID(); - volobjp->setLightTextureID(id); + setLightTextureID(id, LightTextureCtrl->getImageItemID(), volobjp); } } @@ -891,11 +893,12 @@ void LLPanelVolume::onCommitLight( LLUICtrl* ctrl, void* userdata ) if(LightTextureCtrl) { LLUUID id = LightTextureCtrl->getImageAssetID(); + LLUUID item_id = LightTextureCtrl->getImageItemID(); if (id.notNull()) { if (!volobjp->isLightSpotlight()) { //this commit is making this a spot light, set UI to default params - volobjp->setLightTextureID(id); + setLightTextureID(id, item_id, volobjp); LLVector3 spot_params = volobjp->getSpotLightParams(); self->getChild("Light FOV")->setValue(spot_params.mV[0]); self->getChild("Light Focus")->setValue(spot_params.mV[1]); @@ -905,7 +908,7 @@ void LLPanelVolume::onCommitLight( LLUICtrl* ctrl, void* userdata ) { //modifying existing params, this time volobjp won't change params on its own. if (volobjp->getLightTextureID() != id) { - volobjp->setLightTextureID(id); + setLightTextureID(id, item_id, volobjp); } LLVector3 spot_params; @@ -917,7 +920,7 @@ void LLPanelVolume::onCommitLight( LLUICtrl* ctrl, void* userdata ) } else if (volobjp->isLightSpotlight()) { //no longer a spot light - volobjp->setLightTextureID(id); + setLightTextureID(id, item_id, volobjp); //self->getChildView("Light FOV")->setEnabled(FALSE); //self->getChildView("Light Focus")->setEnabled(FALSE); //self->getChildView("Light Ambiance")->setEnabled(FALSE); @@ -934,6 +937,19 @@ void LLPanelVolume::onCommitIsLight( LLUICtrl* ctrl, void* userdata ) self->sendIsLight(); } +// static +void LLPanelVolume::setLightTextureID(const LLUUID &asset_id, const LLUUID &item_id, LLVOVolume* volobjp) +{ + if (volobjp) + { + LLViewerInventoryItem* item = gInventory.getItem(item_id); + if (item && !item->getPermissions().allowOperationBy(PERM_COPY, gAgent.getID())) + { + LLToolDragAndDrop::handleDropTextureProtections(volobjp, item, LLToolDragAndDrop::SOURCE_AGENT, LLUUID::null); + } + volobjp->setLightTextureID(asset_id); + } +} //---------------------------------------------------------------------------- // static diff --git a/indra/newview/llpanelvolume.h b/indra/newview/llpanelvolume.h index 66117316cf..6e49ccb742 100644 --- a/indra/newview/llpanelvolume.h +++ b/indra/newview/llpanelvolume.h @@ -40,6 +40,7 @@ class LLButton; class LLViewerObject; class LLComboBox; class LLColorSwatchCtrl; +class LLVOVolume; class LLPanelVolume : public LLPanel { @@ -73,6 +74,8 @@ public: void onLightCancelTexture(const LLSD& data); void onLightSelectTexture(const LLSD& data); + static void setLightTextureID(const LLUUID &asset_id, const LLUUID &item_id, LLVOVolume* volobjp); + protected: void getState(); diff --git a/indra/newview/llpresetsmanager.cpp b/indra/newview/llpresetsmanager.cpp index d99466ec28..b25b79c5a2 100644 --- a/indra/newview/llpresetsmanager.cpp +++ b/indra/newview/llpresetsmanager.cpp @@ -42,6 +42,7 @@ #include "llagentcamera.h" #include "llfile.h" #include "quickprefs.h" +#include "fsperfstats.h" // avoid triggering reloads while autotuning LLPresetsManager::LLPresetsManager() // Graphic preset controls independent from XUI @@ -708,7 +709,9 @@ void LLPresetsManager::handleGraphicPresetControlChanged(LLControlVariablePtr co { LL_DEBUGS() << "Handling graphic preset control change: control = " << control->getName() << " - new = " << new_value << " - old = " << old_value << LL_ENDL; - if (!mIsLoadingPreset && (!mIsDrawDistanceSteppingActive || control->getName() != "RenderFarClip")) + if (!mIsLoadingPreset && + (!mIsDrawDistanceSteppingActive || control->getName() != "RenderFarClip") && + (!FSPerfStats::autoTune) ) { LL_DEBUGS() << "Trigger graphic preset control changed signal" << LL_ENDL; diff --git a/indra/newview/llpreviewtexture.cpp b/indra/newview/llpreviewtexture.cpp index 808d218e8e..dc6d5a7503 100644 --- a/indra/newview/llpreviewtexture.cpp +++ b/indra/newview/llpreviewtexture.cpp @@ -53,6 +53,7 @@ #include "llviewertexture.h" #include "llviewertexturelist.h" #include "lluictrlfactory.h" +#include "llviewercontrol.h" #include "llviewerwindow.h" #include "lllineeditor.h" #include "lltexteditor.h" @@ -468,6 +469,62 @@ void LLPreviewTexture::saveTextureToFile(const std::vector& filenam saveMultiple(remaining_ids); } + +void LLPreviewTexture::saveMultipleToFile(const std::string& file_name) +{ + std::string texture_location(gSavedSettings.getString("TextureSaveLocation")); + std::string texture_name = file_name.empty() ? getItem()->getName() : file_name; + + std::string filepath; + S32 i = 0; + S32 err = 0; + std::string extension(".png"); + // Allow to use user-defined default save format for textures + if (!gSavedSettings.getBOOL("FSTextureDefaultSaveAsFormat")) + { + extension = ".tga"; + } + // + do + { + filepath = texture_location; + filepath += gDirUtilp->getDirDelimiter(); + filepath += texture_name; + + if (i != 0) + { + filepath += llformat("_%.3d", i); + } + + filepath += extension; + + llstat stat_info; + err = LLFile::stat( filepath, &stat_info ); + i++; + } while (-1 != err); // Search until the file is not found (i.e., stat() gives an error). + + + mSaveFileName = filepath; + mLoadingFullImage = TRUE; + getWindow()->incBusyCount(); + + mImage->forceToSaveRawImage(0);//re-fetch the raw image if the old one is removed. + // Allow to use user-defined default save format for textures + //mImage->setLoadedCallback(LLPreviewTexture::onFileLoadedForSavePNG, + // 0, TRUE, FALSE, new LLUUID(mItemUUID), &mCallbackTextureList); + if (gSavedSettings.getBOOL("FSTextureDefaultSaveAsFormat")) + { + mImage->setLoadedCallback(LLPreviewTexture::onFileLoadedForSavePNG, + 0, TRUE, FALSE, new LLUUID(mItemUUID), &mCallbackTextureList); + } + else + { + mImage->setLoadedCallback(LLPreviewTexture::onFileLoadedForSaveTGA, + 0, TRUE, FALSE, new LLUUID(mItemUUID), &mCallbackTextureList); + } + // +} + // virtual void LLPreviewTexture::reshape(S32 width, S32 height, BOOL called_from_parent) { diff --git a/indra/newview/llpreviewtexture.h b/indra/newview/llpreviewtexture.h index 5b612bec89..297eac8b80 100644 --- a/indra/newview/llpreviewtexture.h +++ b/indra/newview/llpreviewtexture.h @@ -89,6 +89,7 @@ public: //void saveTextureToFile(const std::vector& filenames); void saveTextureToFile(const std::vector& filenames, EFileformatType format, loaded_callback_func callback, uuid_vec_t remaining_ids = uuid_vec_t()); // + void saveMultipleToFile(const std::string& file_name = ""); static void onSaveAsBtn(LLUICtrl* ctrl, void* data); diff --git a/indra/newview/llregioninfomodel.cpp b/indra/newview/llregioninfomodel.cpp index 7daaa7ef8e..6caec6ec4a 100644 --- a/indra/newview/llregioninfomodel.cpp +++ b/indra/newview/llregioninfomodel.cpp @@ -173,6 +173,29 @@ void LLRegionInfoModel::update(LLMessageSystem* msg) mRegionFlags = flags; } + if (msg->has(_PREHASH_RegionInfo5)) + { + F32 chat_whisper_range; + F32 chat_normal_range; + F32 chat_shout_range; + F32 chat_whisper_offset; + F32 chat_normal_offset; + F32 chat_shout_offset; + U32 chat_flags; + + msg->getF32Fast(_PREHASH_RegionInfo5, _PREHASH_ChatWhisperRange, chat_whisper_range); + msg->getF32Fast(_PREHASH_RegionInfo5, _PREHASH_ChatNormalRange, chat_normal_range); + msg->getF32Fast(_PREHASH_RegionInfo5, _PREHASH_ChatShoutRange, chat_shout_range); + msg->getF32Fast(_PREHASH_RegionInfo5, _PREHASH_ChatWhisperOffset, chat_whisper_offset); + msg->getF32Fast(_PREHASH_RegionInfo5, _PREHASH_ChatNormalOffset, chat_normal_offset); + msg->getF32Fast(_PREHASH_RegionInfo5, _PREHASH_ChatShoutOffset, chat_shout_offset); + msg->getU32Fast(_PREHASH_RegionInfo5, _PREHASH_ChatFlags, chat_flags); + + LL_INFOS() << "Whisper range: " << chat_whisper_range << " normal range: " << chat_normal_range << " shout range: " << chat_shout_range + << " whisper offset: " << chat_whisper_offset << " normal offset: " << chat_normal_offset << " shout offset: " << chat_shout_offset + << " chat flags: " << chat_flags << LL_ENDL; + } + // the only reasonable way to decide if we actually have any data is to // check to see if any of these fields have nonzero sizes if (msg->getSize(_PREHASH_RegionInfo2, _PREHASH_ProductSKU) > 0 || diff --git a/indra/newview/llsecapi.cpp b/indra/newview/llsecapi.cpp index 78c8aa1dcf..6de3f1e8fc 100644 --- a/indra/newview/llsecapi.cpp +++ b/indra/newview/llsecapi.cpp @@ -93,6 +93,12 @@ void initializeSecHandler() } } + +void clearSecHandler() +{ + gSecAPIHandler = NULL; + gHandlerMap.clear(); +} // start using a given security api handler. If the string is empty // the default is used LLPointer getSecHandler(const std::string& handler_type) diff --git a/indra/newview/llsecapi.h b/indra/newview/llsecapi.h index c2ccb8f779..95ad1e79ba 100644 --- a/indra/newview/llsecapi.h +++ b/indra/newview/llsecapi.h @@ -264,7 +264,9 @@ public: virtual void validate(int validation_policy, LLPointer cert_chain, const LLSD& validation_params) =0; - + + // Clear cache if any + virtual void clearSertCache()=0; }; @@ -452,7 +454,7 @@ public: virtual LLPointer getCertificate(X509* openssl_cert)=0; // instantiate a chain from an X509_STORE_CTX - virtual LLPointer getCertificateChain(const X509_STORE_CTX* chain)=0; + virtual LLPointer getCertificateChain(X509_STORE_CTX* chain)=0; // instantiate a cert store given it's id. if a persisted version // exists, it'll be loaded. If not, one will be created (but not @@ -535,6 +537,8 @@ public: }; void initializeSecHandler(); + +void clearSecHandler(); // retrieve a security api depending on the api type LLPointer getSecHandler(const std::string& handler_type); diff --git a/indra/newview/llsechandler_basic.cpp b/indra/newview/llsechandler_basic.cpp index 671e78db54..72c7c9cde2 100644 --- a/indra/newview/llsechandler_basic.cpp +++ b/indra/newview/llsechandler_basic.cpp @@ -95,7 +95,7 @@ LLBasicCertificate::LLBasicCertificate(const std::string& pem_cert, LLBasicCertificate::LLBasicCertificate(X509* pCert, const LLSD* validation_params) { - if (!pCert || !pCert->cert_info) + if (!pCert) { LLTHROW(LLInvalidCertificate(LLSD::emptyMap())); } @@ -355,8 +355,8 @@ LLSD cert_name_from_X509_NAME(X509_NAME* name) char buffer[32]; X509_NAME_ENTRY *entry = X509_NAME_get_entry(name, entry_index); - std::string name_value = std::string((const char*)M_ASN1_STRING_data(X509_NAME_ENTRY_get_data(entry)), - M_ASN1_STRING_length(X509_NAME_ENTRY_get_data(entry))); + std::string name_value = std::string((const char*)ASN1_STRING_get0_data(X509_NAME_ENTRY_get_data(entry)), + ASN1_STRING_length(X509_NAME_ENTRY_get_data(entry))); ASN1_OBJECT* name_obj = X509_NAME_ENTRY_get_object(entry); OBJ_obj2txt(buffer, sizeof(buffer), name_obj, 0); @@ -691,29 +691,29 @@ std::string LLBasicCertificateStore::storeId() const // LLBasicCertificateChain // This class represents a chain of certs, each cert being signed by the next cert // in the chain. Certs must be properly signed by the parent -LLBasicCertificateChain::LLBasicCertificateChain(const X509_STORE_CTX* store) +LLBasicCertificateChain::LLBasicCertificateChain(X509_STORE_CTX* store) { // we're passed in a context, which contains a cert, and a blob of untrusted // certificates which compose the chain. - if((store == NULL) || (store->cert == NULL)) + if((store == NULL) || X509_STORE_CTX_get0_cert(store) == NULL) { LL_WARNS("SECAPI") << "An invalid store context was passed in when trying to create a certificate chain" << LL_ENDL; return; } // grab the child cert - LLPointer current = new LLBasicCertificate(store->cert); + LLPointer current = new LLBasicCertificate(X509_STORE_CTX_get0_cert(store)); add(current); - if(store->untrusted != NULL) + if(X509_STORE_CTX_get0_untrusted(store) != NULL) { // if there are other certs in the chain, we build up a vector // of untrusted certs so we can search for the parents of each // consecutive cert. LLBasicCertificateVector untrusted_certs; - for(int i = 0; i < sk_X509_num(store->untrusted); i++) + for(int i = 0; i < sk_X509_num(X509_STORE_CTX_get0_untrusted(store)); i++) { - LLPointer cert = new LLBasicCertificate(sk_X509_value(store->untrusted, i)); + LLPointer cert = new LLBasicCertificate(sk_X509_value(X509_STORE_CTX_get0_untrusted(store), i)); untrusted_certs.add(cert); } @@ -1323,8 +1323,8 @@ LLSecAPIBasicHandler::~LLSecAPIBasicHandler() //_writeProtectedData(); } -void LLSecAPIBasicHandler::_readProtectedData() -{ +void LLSecAPIBasicHandler::_readProtectedData(unsigned char *unique_id, U32 id_len) +{ // attempt to load the file into our map LLPointer parser = new LLSDXMLParser(); llifstream protected_data_stream(mProtectedDataFilename.c_str(), @@ -1335,9 +1335,7 @@ void LLSecAPIBasicHandler::_readProtectedData() U8 buffer[BUFFER_READ_SIZE]; U8 decrypted_buffer[BUFFER_READ_SIZE]; int decrypted_length; - unsigned char unique_id[MAC_ADDRESS_BYTES]; - LLMachineID::getUniqueID(unique_id, sizeof(unique_id)); - LLXORCipher cipher(unique_id, sizeof(unique_id)); + LLXORCipher cipher(unique_id, id_len); // read in the salt and key protected_data_stream.read((char *)salt, STORE_SALT_SIZE); @@ -1361,9 +1359,10 @@ void LLSecAPIBasicHandler::_readProtectedData() // read in the rest of the file. - EVP_CIPHER_CTX ctx; - EVP_CIPHER_CTX_init(&ctx); - EVP_DecryptInit(&ctx, EVP_rc4(), salt, NULL); + EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new(); + // todo: ctx error handling + + EVP_DecryptInit(ctx, EVP_rc4(), salt, NULL); // allocate memory: std::string decrypted_data; @@ -1371,14 +1370,14 @@ void LLSecAPIBasicHandler::_readProtectedData() // read data as a block: protected_data_stream.read((char *)buffer, BUFFER_READ_SIZE); - EVP_DecryptUpdate(&ctx, decrypted_buffer, &decrypted_length, + EVP_DecryptUpdate(ctx, decrypted_buffer, &decrypted_length, buffer, protected_data_stream.gcount()); decrypted_data.append((const char *)decrypted_buffer, protected_data_stream.gcount()); } // RC4 is a stream cipher, so we don't bother to EVP_DecryptFinal, as there is // no block padding. - EVP_CIPHER_CTX_cleanup(&ctx); + EVP_CIPHER_CTX_free(ctx); std::istringstream parse_stream(decrypted_data); if (parser->parse(parse_stream, mProtectedDataMap, LLSDSerialize::SIZE_UNLIMITED) == LLSDParser::PARSE_FAILURE) @@ -1388,6 +1387,30 @@ void LLSecAPIBasicHandler::_readProtectedData() } } +void LLSecAPIBasicHandler::_readProtectedData() +{ + unsigned char unique_id[MAC_ADDRESS_BYTES]; + try + { + // try default id + LLMachineID::getUniqueID(unique_id, sizeof(unique_id)); + _readProtectedData(unique_id, sizeof(unique_id)); + } + catch(LLProtectedDataException&) + { + // try with legacy id, it will return false if it is identical to getUniqueID + // or if it is not assigned/not in use + if (LLMachineID::getLegacyID(unique_id, sizeof(unique_id))) + { + _readProtectedData(unique_id, sizeof(unique_id)); + } + else + { + throw; + } + } +} + void LLSecAPIBasicHandler::_writeProtectedData() { std::ostringstream formatted_data_ostream; @@ -1414,12 +1437,14 @@ void LLSecAPIBasicHandler::_writeProtectedData() llofstream protected_data_stream(tmp_filename.c_str(), std::ios_base::binary); + EVP_CIPHER_CTX *ctx = NULL; try { - EVP_CIPHER_CTX ctx; - EVP_CIPHER_CTX_init(&ctx); - EVP_EncryptInit(&ctx, EVP_rc4(), salt, NULL); + ctx = EVP_CIPHER_CTX_new(); + // todo: ctx error handling + + EVP_EncryptInit(ctx, EVP_rc4(), salt, NULL); unsigned char unique_id[MAC_ADDRESS_BYTES]; LLMachineID::getUniqueID(unique_id, sizeof(unique_id)); LLXORCipher cipher(unique_id, sizeof(unique_id)); @@ -1434,13 +1459,13 @@ void LLSecAPIBasicHandler::_writeProtectedData() break; } int encrypted_length; - EVP_EncryptUpdate(&ctx, encrypted_buffer, &encrypted_length, + EVP_EncryptUpdate(ctx, encrypted_buffer, &encrypted_length, buffer, formatted_data_istream.gcount()); protected_data_stream.write((const char *)encrypted_buffer, encrypted_length); } // no EVP_EncrypteFinal, as this is a stream cipher - EVP_CIPHER_CTX_cleanup(&ctx); + EVP_CIPHER_CTX_free(ctx); protected_data_stream.close(); } @@ -1452,6 +1477,11 @@ void LLSecAPIBasicHandler::_writeProtectedData() // it may be, however. LLFile::remove(tmp_filename); + if (ctx) + { + EVP_CIPHER_CTX_free(ctx); + } + // EXP-1825 crash in LLSecAPIBasicHandler::_writeProtectedData() // Decided throwing an exception here was overkill until we figure out why this happens //LLTHROW(LLProtectedDataException("Error writing Protected Data Store")); @@ -1504,7 +1534,7 @@ LLPointer LLSecAPIBasicHandler::getCertificate(X509* openssl_cert } // instantiate a chain from an X509_STORE_CTX -LLPointer LLSecAPIBasicHandler::getCertificateChain(const X509_STORE_CTX* chain) +LLPointer LLSecAPIBasicHandler::getCertificateChain(X509_STORE_CTX* chain) { LLPointer result = new LLBasicCertificateChain(chain); return result; diff --git a/indra/newview/llsechandler_basic.h b/indra/newview/llsechandler_basic.h index 59dc6f803a..df53e01524 100644 --- a/indra/newview/llsechandler_basic.h +++ b/indra/newview/llsechandler_basic.h @@ -177,7 +177,10 @@ public: virtual void validate(int validation_policy, LLPointer ca_chain, const LLSD& validation_params); - + + // Clears cache of certs validated agains store + virtual void clearSertCache() { mTrustedCertCache.clear(); } + protected: std::vector > mCerts; @@ -197,7 +200,7 @@ class LLBasicCertificateChain : virtual public LLBasicCertificateVector, public { public: - LLBasicCertificateChain(const X509_STORE_CTX * store); + LLBasicCertificateChain(X509_STORE_CTX * store); virtual ~LLBasicCertificateChain() {} @@ -241,7 +244,7 @@ public: virtual LLPointer getCertificate(X509* openssl_cert); // instantiate a chain from an X509_STORE_CTX - virtual LLPointer getCertificateChain(const X509_STORE_CTX* chain); + virtual LLPointer getCertificateChain(X509_STORE_CTX* chain); // instantiate a cert store given it's id. if a persisted version // exists, it'll be loaded. If not, one will be created (but not @@ -328,6 +331,7 @@ public: protected: + void _readProtectedData(unsigned char *unique_id, U32 id_len); void _readProtectedData(); void _writeProtectedData(); std::string _legacyLoadPassword(); diff --git a/indra/newview/llselectmgr.cpp b/indra/newview/llselectmgr.cpp index 36b64c04e9..473767ae3d 100644 --- a/indra/newview/llselectmgr.cpp +++ b/indra/newview/llselectmgr.cpp @@ -1454,8 +1454,7 @@ void LLSelectMgr::getGrid(LLVector3& origin, LLQuaternion &rotation, LLVector3 & } break; case SELECT_TYPE_HUD: - // use HUD-scaled grid - mGridScale = LLVector3(0.25f, 0.25f, 0.25f); + mGridScale = LLVector3(1.f, 1.f, 1.f) * llmin(gSavedSettings.getF32("GridResolution"), 0.5f); break; case SELECT_TYPE_WORLD: mGridScale = LLVector3(1.f, 1.f, 1.f) * gSavedSettings.getF32("GridResolution"); @@ -2025,7 +2024,7 @@ BOOL LLSelectMgr::selectionRevertTextures() return revert_successful; } -void LLSelectMgr::selectionSetBumpmap(U8 bumpmap) +void LLSelectMgr::selectionSetBumpmap(U8 bumpmap, const LLUUID &image_id) { struct f : public LLSelectedTEFunctor { @@ -2041,7 +2040,22 @@ void LLSelectMgr::selectionSetBumpmap(U8 bumpmap) return true; } } setfunc(bumpmap); - getSelection()->applyToTEs(&setfunc); + + LLViewerInventoryItem* item = gInventory.getItem(image_id); + if(item + && !item->getPermissions().allowOperationBy(PERM_COPY, gAgent.getID()) + && (mSelectedObjects->getNumNodes() > 1) ) + { + LL_WARNS() << "Attempted to apply no-copy texture to multiple objects" << LL_ENDL; + return; + } + if (item && !item->getPermissions().allowOperationBy(PERM_COPY, gAgent.getID())) + { + LLViewerObject *object = mSelectedObjects->getFirstRootObject(); + if (!object) return; + LLToolDragAndDrop::handleDropTextureProtections(object, item, LLToolDragAndDrop::SOURCE_AGENT, LLUUID::null); + } + getSelection()->applyToTEs(&setfunc); LLSelectMgrSendFunctor sendfunc; getSelection()->applyToObjects(&sendfunc); @@ -2070,7 +2084,7 @@ void LLSelectMgr::selectionSetTexGen(U8 texgen) } -void LLSelectMgr::selectionSetShiny(U8 shiny) +void LLSelectMgr::selectionSetShiny(U8 shiny, const LLUUID &image_id) { struct f : public LLSelectedTEFunctor { @@ -2086,7 +2100,22 @@ void LLSelectMgr::selectionSetShiny(U8 shiny) return true; } } setfunc(shiny); - getSelection()->applyToTEs(&setfunc); + + LLViewerInventoryItem* item = gInventory.getItem(image_id); + if(item + && !item->getPermissions().allowOperationBy(PERM_COPY, gAgent.getID()) + && (mSelectedObjects->getNumNodes() > 1) ) + { + LL_WARNS() << "Attempted to apply no-copy texture to multiple objects" << LL_ENDL; + return; + } + if (item && !item->getPermissions().allowOperationBy(PERM_COPY, gAgent.getID())) + { + LLViewerObject *object = mSelectedObjects->getFirstRootObject(); + if (!object) return; + LLToolDragAndDrop::handleDropTextureProtections(object, item, LLToolDragAndDrop::SOURCE_AGENT, LLUUID::null); + } + getSelection()->applyToTEs(&setfunc); LLSelectMgrSendFunctor sendfunc; getSelection()->applyToObjects(&sendfunc); diff --git a/indra/newview/llselectmgr.h b/indra/newview/llselectmgr.h index bb0080b5ff..6ec997770f 100644 --- a/indra/newview/llselectmgr.h +++ b/indra/newview/llselectmgr.h @@ -682,9 +682,9 @@ public: void selectionRevertColors(); void selectionRevertShinyColors(); BOOL selectionRevertTextures(); - void selectionSetBumpmap( U8 bumpmap ); + void selectionSetBumpmap( U8 bumpmap, const LLUUID &image_id ); void selectionSetTexGen( U8 texgen ); - void selectionSetShiny( U8 shiny ); + void selectionSetShiny( U8 shiny, const LLUUID &image_id ); void selectionSetFullbright( U8 fullbright ); void selectionSetMedia( U8 media_type, const LLSD &media_data ); void selectionSetClickAction(U8 action); diff --git a/indra/newview/llsetkeybinddialog.h b/indra/newview/llsetkeybinddialog.h index a34b952233..24dfa1dbfd 100644 --- a/indra/newview/llsetkeybinddialog.h +++ b/indra/newview/llsetkeybinddialog.h @@ -76,6 +76,8 @@ public: static void onDefault(void* user_data); static void onClickTimeout(void* user_data, MASK mask); + static bool isRecording() { return sRecordKeys; } + class Updater; private: diff --git a/indra/newview/llsidepanelappearance.cpp b/indra/newview/llsidepanelappearance.cpp index 2fc50132d2..8ed359fc0a 100644 --- a/indra/newview/llsidepanelappearance.cpp +++ b/indra/newview/llsidepanelappearance.cpp @@ -215,7 +215,7 @@ void LLSidepanelAppearance::updateToVisibility(const LLSD &new_visibility) // when editing its physics. if (!gAgentCamera.cameraCustomizeAvatar()) { - LLVOAvatarSelf::onCustomizeStart(LLWearableType::getDisableCameraSwitch(wearable_ptr->getType())); + LLVOAvatarSelf::onCustomizeStart(LLWearableType::getInstance()->getDisableCameraSwitch(wearable_ptr->getType())); } if (is_wearable_edit_visible) { diff --git a/indra/newview/llspatialpartition.cpp b/indra/newview/llspatialpartition.cpp index 2f0a78b1b2..83ac99e085 100644 --- a/indra/newview/llspatialpartition.cpp +++ b/indra/newview/llspatialpartition.cpp @@ -1130,6 +1130,7 @@ public: virtual S32 frustumCheck(const LLViewerOctreeGroup* group) { + FSZone; S32 res = AABBInFrustumNoFarClipGroupBounds(group); if (res != 0) { @@ -1140,6 +1141,7 @@ public: virtual S32 frustumCheckObjects(const LLViewerOctreeGroup* group) { + FSZone; S32 res = AABBInFrustumNoFarClipObjectBounds(group); if (res != 0) { @@ -1150,6 +1152,7 @@ public: virtual void processGroup(LLViewerOctreeGroup* base_group) { + FSZone; LLSpatialGroup* group = (LLSpatialGroup*)base_group; if (group->needsUpdate() || group->getVisible(LLViewerCamera::sCurCameraID) < LLDrawable::getCurrentFrame() - 1) diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index 9343e9b707..65fff0fb12 100644 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -211,7 +211,7 @@ #include "llenvironment.h" #include "llstacktrace.h" - +#include "fsperfstats.h" #if LL_WINDOWS #include "lldxhardware.h" #endif @@ -2158,6 +2158,10 @@ bool idle_startup() update_static_eyes(); // + // + gAgent.addRegionChangedCallback(boost::bind(&FSPerfStats::StatsRecorder::clearStats)); + // + // *Note: this is where gWorldMap used to be initialized. // register null callbacks for audio until the audio system is initialized @@ -3741,6 +3745,11 @@ void reset_login() } LLFloaterReg::hideVisibleInstances(); LLStartUp::setStartupState( STATE_BROWSER_INIT ); + + // Clear any verified certs and verify them again on next login + // to ensure cert matches server instead of just getting reused + LLPointer store = gSecAPIHandler->getCertificateStore(""); + store->clearSertCache(); } //--------------------------------------------------------------------------- @@ -4260,6 +4269,10 @@ bool process_login_success_response(U32 &first_sim_size_x, U32 &first_sim_size_y // unpack login data needed by the application text = response["agent_id"].asString(); if(!text.empty()) gAgentID.set(text); + // Performance floater initialisation + FSPerfStats::StatsRecorder::setEnabled(gSavedSettings.getBOOL("FSPerfStatsCaptureEnabled")); + FSPerfStats::StatsRecorder::setFocusAv(gAgentID); + // // gDebugInfo["AgentID"] = text; // [SL:KB] - Patch: Viewer-CrashReporting | Checked: 2010-11-16 (Catznip-2.6.0a) | Added: Catznip-2.4.0b if (gCrashSettings.getBOOL("CrashSubmitName")) diff --git a/indra/newview/llstatusbar.cpp b/indra/newview/llstatusbar.cpp index c1fdd85996..6641c03645 100644 --- a/indra/newview/llstatusbar.cpp +++ b/indra/newview/llstatusbar.cpp @@ -587,10 +587,10 @@ void LLStatusBar::refresh() // FIRE-14482: Show FPS in status bar static LLCachedControl fsStatusBarShowFPS(gSavedSettings, "FSStatusBarShowFPS"); - if (fsStatusBarShowFPS && mFPSUpdateTimer.getElapsedTimeF32() > 0.5f) + if (fsStatusBarShowFPS && mFPSUpdateTimer.getElapsedTimeF32() > 1.f) { mFPSUpdateTimer.reset(); - mFPSText->setText(llformat("%.1f", LLTrace::get_frame_recording().getPeriodMeanPerSec(LLStatViewer::FPS))); + mFPSText->setText(llformat("%.1f", LLTrace::get_frame_recording().getPeriodMedianPerSec(LLStatViewer::FPS))); } // diff --git a/indra/newview/lltoolcomp.cpp b/indra/newview/lltoolcomp.cpp index 9877800d79..08e26c7214 100644 --- a/indra/newview/lltoolcomp.cpp +++ b/indra/newview/lltoolcomp.cpp @@ -347,7 +347,9 @@ BOOL LLToolCompTranslate::handleDoubleClick(S32 x, S32 y, MASK mask) } // Nothing selected means the first mouse click was probably // bad, so try again. - return FALSE; + // This also consumes the event to prevent things like double-click + // teleport from triggering. + return handleMouseDown(x, y, mask); } diff --git a/indra/newview/lltoolpie.cpp b/indra/newview/lltoolpie.cpp index ac5a06b53b..321b3e9898 100644 --- a/indra/newview/lltoolpie.cpp +++ b/indra/newview/lltoolpie.cpp @@ -524,8 +524,9 @@ BOOL LLToolPie::useClickAction(MASK mask, && object && !object->isAttachment() && LLPrimitive::isPrimitive(object->getPCode()) - && (object->getClickAction() - || parent->getClickAction()); + // useClickAction does not handle Touch (0) or Disabled action + && ((object->getClickAction() && object->getClickAction() != CLICK_ACTION_DISABLED) + || (parent && parent->getClickAction() && parent->getClickAction() != CLICK_ACTION_DISABLED)); } @@ -536,18 +537,18 @@ U8 final_click_action(LLViewerObject* obj) U8 click_action = CLICK_ACTION_TOUCH; LLViewerObject* parent = obj->getRootEdit(); - if (obj->getClickAction() - || (parent && parent->getClickAction())) - { - if (obj->getClickAction()) - { - click_action = obj->getClickAction(); - } - else if (parent && parent->getClickAction()) - { - click_action = parent->getClickAction(); - } - } + U8 object_action = obj->getClickAction(); + U8 parent_action = parent ? parent->getClickAction() : CLICK_ACTION_TOUCH; + if (parent_action == CLICK_ACTION_DISABLED || object_action) + { + // CLICK_ACTION_DISABLED ("None" in UI) is intended for child action to + // override parent's action when assigned to parent or to child + click_action = object_action; + } + else if (parent_action) + { + click_action = parent_action; + } return click_action; } @@ -686,18 +687,21 @@ bool LLToolPie::walkToClickedLocation() mPick.mPosGlobal = gAgent.getPositionGlobal() + LLVector3d(LLViewerCamera::instance().getAtAxis()) * SELF_CLICK_WALK_DISTANCE; } - if ((mPick.mPickType == LLPickInfo::PICK_LAND && !mPick.mPosGlobal.isExactlyZero()) || - (mPick.mObjectID.notNull() && !mPick.mPosGlobal.isExactlyZero())) - { +// if ((mPick.mPickType == LLPickInfo::PICK_LAND && !mPick.mPosGlobal.isExactlyZero()) || +// (mPick.mObjectID.notNull() && !mPick.mPosGlobal.isExactlyZero())) // [RLVa:KB] - Checked: RLVa-2.0.0 - if (RlvActions::isRlvEnabled() && !RlvActions::canTeleportToLocal(mPick.mPosGlobal)) - { - RlvUtil::notifyBlocked(RlvStringKeys::Blocked::AutoPilot); - mPick = saved_pick; - return false; - } -// [/RLVa:KB] + bool fValidPick = ((mPick.mPickType == LLPickInfo::PICK_LAND && !mPick.mPosGlobal.isExactlyZero()) || + (mPick.mObjectID.notNull() && !mPick.mPosGlobal.isExactlyZero())); + if ( (fValidPick) && (RlvActions::isRlvEnabled()) && (!RlvActions::canTeleportToLocal(mPick.mPosGlobal)) ) + { + RlvUtil::notifyBlocked(RlvStringKeys::Blocked::AutoPilot); + fValidPick = false; + } + + if (fValidPick) +// [/RLVa:KB] + { // FIRE-31135 Do not reset camera position for "click to walk" // gAgentCamera.setFocusOnAvatar(TRUE, TRUE); static LLCachedControl sResetCameraOnMovement(gSavedSettings, "FSResetCameraOnMovement"); @@ -752,12 +756,13 @@ bool LLToolPie::teleportToClickedLocation() bool is_land = mHoverPick.mPickType == LLPickInfo::PICK_LAND; bool pos_non_zero = !mHoverPick.mPosGlobal.isExactlyZero(); bool has_touch_handler = (objp && objp->flagHandleTouch()) || (parentp && parentp->flagHandleTouch()); - bool has_click_action = final_click_action(objp); + U8 click_action = final_click_action(objp); // default action: 0 - touch + bool has_click_action = (click_action || has_touch_handler) && click_action != CLICK_ACTION_DISABLED; // FIRE-1765: Allow double-click walk/teleport to scripted objects - //if (pos_non_zero && (is_land || (is_in_world && !has_touch_handler && !has_click_action))) + //if (pos_non_zero && (is_land || (is_in_world && !has_click_action))) bool allowDoubleClickOnScriptedObjects = gSavedSettings.getBOOL("FSAllowDoubleClickOnScriptedObjects"); - if (pos_non_zero && (is_land || (is_in_world && ((allowDoubleClickOnScriptedObjects && objp->getClickAction() != CLICK_ACTION_SIT) || (!has_touch_handler && !has_click_action))))) + if (pos_non_zero && (is_land || (is_in_world && ((allowDoubleClickOnScriptedObjects && objp->getClickAction() != CLICK_ACTION_SIT) || !has_click_action)))) // { // [RLVa:KB] - Checked: RLVa-2.0.0 @@ -917,7 +922,8 @@ BOOL LLToolPie::handleHover(S32 x, S32 y, MASK mask) LL_DEBUGS("UserInput") << "hover handled by LLToolPie (inactive)" << LL_ENDL; } else if ((!object || !object->isAttachment() || object->getClickAction() != CLICK_ACTION_DISABLED) - && ((object && object->flagHandleTouch()) || (parent && parent->flagHandleTouch()))) + && ((object && object->flagHandleTouch()) || (parent && parent->flagHandleTouch())) + && (!object || !object->isAvatar())) { show_highlight = true; gViewerWindow->setCursor(UI_CURSOR_HAND); @@ -1460,35 +1466,25 @@ BOOL LLToolPie::handleTooltipObject( LLViewerObject* hover_object, std::string l // Display the PE weight for an object if mesh is enabled if (gMeshRepo.meshRezEnabled()) { - // Ansariel: What a bummer! PE is only available for - // objects in the same region as you! - if (hover_object->getRegion() && gAgent.getRegion() && - hover_object->getRegion()->getRegionID() == gAgent.getRegion()->getRegionID()) + S32 link_cost = LLSelectMgr::getInstance()->getHoverObjects()->getSelectedLinksetCost(); + if (link_cost > 0) { - S32 link_cost = LLSelectMgr::getInstance()->getHoverObjects()->getSelectedLinksetCost(); - if (link_cost > 0) - { - args.clear(); - args["PEWEIGHT"] = llformat("%d", link_cost); - tooltip_msg.append(LLTrans::getString("TooltipPrimEquivalent", args)); - } + args.clear(); + args["PEWEIGHT"] = llformat("%d", link_cost); + tooltip_msg.append(LLTrans::getString("TooltipPrimEquivalent", args)); + } /// Don't show loading on vanila OpenSim (some grids have it, not not vanilla) If they have it, it will /// show eventually #ifdef OPENSIM - else if (LLGridManager::getInstance()->isInOpenSim()) - { - // Do nothing at all. - } + else if (LLGridManager::getInstance()->isInOpenSim()) + { + // Do nothing at all. + } #endif // - else - { - tooltip_msg.append(LLTrans::getString("TooltipPrimEquivalentLoading")); - } - } else { - tooltip_msg.append(LLTrans::getString("TooltipPrimEquivalentUnavailable")); + tooltip_msg.append(LLTrans::getString("TooltipPrimEquivalentLoading")); } } diff --git a/indra/newview/lltranslate.cpp b/indra/newview/lltranslate.cpp index ae66c596ac..adee90cd28 100644 --- a/indra/newview/lltranslate.cpp +++ b/indra/newview/lltranslate.cpp @@ -197,6 +197,11 @@ void LLTranslationAPIHandler::translateMessageCoro(LanguagePair_t fromTo, std::s LLSD result = httpAdapter->getRawAndSuspend(httpRequest, url, httpOpts, httpHeaders); + if (LLApp::isQuitting()) + { + return; + } + LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); @@ -207,7 +212,22 @@ void LLTranslationAPIHandler::translateMessageCoro(LanguagePair_t fromTo, std::s const LLSD::Binary &rawBody = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS_RAW].asBinary(); std::string body(rawBody.begin(), rawBody.end()); - if (this->parseResponse(parseResult, body, translation, detected_lang, err_msg)) + bool res = false; + + try + { + res = this->parseResponse(parseResult, body, translation, detected_lang, err_msg); + } + catch (std::out_of_range&) + { + LL_WARNS() << "Out of range exception on string " << body << LL_ENDL; + } + catch (...) + { + LOG_UNHANDLED_EXCEPTION( "Exception on string " + body ); + } + + if (res) { // Fix up the response LLStringUtil::replaceString(translation, "<", "<"); diff --git a/indra/newview/llversioninfo.cpp b/indra/newview/llversioninfo.cpp index e8e2c5f8ac..adc7d8f960 100644 --- a/indra/newview/llversioninfo.cpp +++ b/indra/newview/llversioninfo.cpp @@ -28,9 +28,9 @@ #include "llviewerprecompiledheaders.h" #include "llevents.h" #include "lleventfilter.h" +#include "llregex.h" #include "llversioninfo.h" #include "stringize.h" -#include // Use configured file instead of compile time definitions to avoid // rebuilding the world with every Mercurial pull @@ -184,19 +184,19 @@ LLVersionInfo::ViewerMaturity LLVersionInfo::getViewerMaturity() static const boost::regex is_project_channel("\\bProject\\b"); static const boost::regex is_release_channel("\\bRelease\\b"); - if (boost::regex_search(channel, is_release_channel)) + if (ll_regex_search(channel, is_release_channel)) { maturity = RELEASE_VIEWER; } - else if (boost::regex_search(channel, is_beta_channel)) + else if (ll_regex_search(channel, is_beta_channel)) { maturity = BETA_VIEWER; } - else if (boost::regex_search(channel, is_project_channel)) + else if (ll_regex_search(channel, is_project_channel)) { maturity = PROJECT_VIEWER; } - else if (boost::regex_search(channel, is_test_channel)) + else if (ll_regex_search(channel, is_test_channel)) { maturity = TEST_VIEWER; } diff --git a/indra/newview/llviewerassetstorage.cpp b/indra/newview/llviewerassetstorage.cpp index a36c11db18..25a43f094b 100644 --- a/indra/newview/llviewerassetstorage.cpp +++ b/indra/newview/llviewerassetstorage.cpp @@ -303,10 +303,7 @@ void LLViewerAssetStorage::storeAssetData( legacy->mUpCallback = callback; legacy->mUserData = user_data; - // Fix broken asset upload - //LLFileSystem file(asset_id, asset_type, LLFileSystem::WRITE); LLFileSystem file(asset_id, asset_type, LLFileSystem::APPEND); - // const S32 buf_size = 65536; U8 copy_buf[buf_size]; @@ -516,6 +513,12 @@ void LLViewerAssetStorage::assetRequestCoro( boost::bind(&LLViewerAssetStorage::capsRecvForRegion, this, _1, capsRecv.getName())); llcoro::suspendUntilEventOn(capsRecv); + + if (LLApp::isExiting() || !gAssetStorage) + { + return; + } + LL_WARNS_ONCE("ViewerAsset") << "capsRecv got event" << LL_ENDL; LL_WARNS_ONCE("ViewerAsset") << "region " << gAgent.getRegion() << " mViewerAssetUrl " << mViewerAssetUrl << LL_ENDL; } diff --git a/indra/newview/llviewerassetupload.cpp b/indra/newview/llviewerassetupload.cpp index 57f1174701..8dec9193c0 100644 --- a/indra/newview/llviewerassetupload.cpp +++ b/indra/newview/llviewerassetupload.cpp @@ -498,10 +498,7 @@ LLSD LLNewFileResourceUploadInfo::exportTempFile() infile.open(filename, LL_APR_RB, NULL, &file_size); if (infile.getFileHandle()) { - // Fix broken asset upload - //LLFileSystem file(getAssetId(), assetType, LLFileSystem::WRITE); LLFileSystem file(getAssetId(), assetType, LLFileSystem::APPEND); - // const S32 buf_size = 65536; U8 copy_buf[buf_size]; @@ -846,7 +843,7 @@ void LLViewerAssetUpload::AssetInventoryUploadCoproc(LLCoreHttpUtil::HttpCorouti // // FIRE-22943: Don't switch away from the "Recent Items" tab. - //LLInventoryPanel::openInventoryPanelAndSetSelection(TRUE, serverInventoryItem, TRUE, TAKE_FOCUS_NO, (panel == NULL)); + //LLInventoryPanel::openInventoryPanelAndSetSelection(TRUE, serverInventoryItem, FALSE, TAKE_FOCUS_NO, (panel == NULL)); BOOL show_main_panel = (!panel || panel->getName() != "Recent Items"); LLInventoryPanel::openInventoryPanelAndSetSelection(TRUE, serverInventoryItem, show_main_panel, TAKE_FOCUS_NO, (panel == NULL)); // diff --git a/indra/newview/llvieweraudio.cpp b/indra/newview/llvieweraudio.cpp index f06a2592e7..3f89e8a174 100644 --- a/indra/newview/llvieweraudio.cpp +++ b/indra/newview/llvieweraudio.cpp @@ -83,7 +83,7 @@ void LLViewerAudio::registerIdleListener() } } -void LLViewerAudio::startInternetStreamWithAutoFade(std::string streamURI) +void LLViewerAudio::startInternetStreamWithAutoFade(const std::string &streamURI) { // Old and new stream are identical if (mNextStreamURI == streamURI) diff --git a/indra/newview/llvieweraudio.h b/indra/newview/llvieweraudio.h index 16f9b63113..782285ce36 100644 --- a/indra/newview/llvieweraudio.h +++ b/indra/newview/llvieweraudio.h @@ -55,7 +55,7 @@ public: FADE_OUT, }; - void startInternetStreamWithAutoFade(std::string streamURI); + void startInternetStreamWithAutoFade(const std::string &streamURI); void stopInternetStreamWithAutoFade(); bool onIdleUpdate(); @@ -65,7 +65,8 @@ public: F32 getFadeVolume(); bool getForcedTeleportFade() { return mForcedTeleportFade; }; void setForcedTeleportFade(bool fade) { mForcedTeleportFade = fade;} ; - void setNextStreamURI(std::string stream) { mNextStreamURI = stream; } ; + std::string getNextStreamURI() { return mNextStreamURI; }; + void setNextStreamURI(const std::string &stream) { mNextStreamURI = stream; } ; void setWasPlaying(bool playing) { mWasPlaying = playing;} ; private: diff --git a/indra/newview/llviewercontrol.cpp b/indra/newview/llviewercontrol.cpp index fe175bcaf2..a7227c7f58 100644 --- a/indra/newview/llviewercontrol.cpp +++ b/indra/newview/llviewercontrol.cpp @@ -107,7 +107,7 @@ #include "llviewerregion.h" #include "NACLantispam.h" #include "nd/ndlogthrottle.h" - +#include "fsperfstats.h" // Run Prio 0 default bento pose in the background to fix splayed hands, open mouths, etc. #include "llanimationstates.h" @@ -231,11 +231,36 @@ bool handleSetShaderChanged(const LLSD& newvalue) gBumpImageList.destroyGL(); gBumpImageList.restoreGL(); + if (gPipeline.isInit()) + { + // ALM depends onto atmospheric shaders, state might have changed + bool old_state = LLPipeline::sRenderDeferred; + LLPipeline::refreshCachedSettings(); + gPipeline.updateRenderDeferred(); + if (old_state != LLPipeline::sRenderDeferred) + { + gPipeline.releaseGLBuffers(); + gPipeline.createGLBuffers(); + gPipeline.resetVertexBuffers(); + } + } + // else, leave terrain detail as is LLViewerShaderMgr::instance()->setShaders(); return true; } +static bool handleAvatarVPChanged(const LLSD& newvalue) +{ + LLRenderTarget::sUseFBO = newvalue.asBoolean() + && gSavedSettings.getBOOL("RenderObjectBump") + && gSavedSettings.getBOOL("RenderTransparentWater") + && gSavedSettings.getBOOL("RenderDeferred"); + + handleSetShaderChanged(LLSD()); + return true; +} + static bool handleRenderPerfTestChanged(const LLSD& newvalue) { bool status = !newvalue.asBoolean(); @@ -275,7 +300,10 @@ static bool handleRenderPerfTestChanged(const LLSD& newvalue) bool handleRenderTransparentWaterChanged(const LLSD& newvalue) { - LLRenderTarget::sUseFBO = newvalue.asBoolean(); + LLRenderTarget::sUseFBO = newvalue.asBoolean() + && gSavedSettings.getBOOL("RenderObjectBump") + && gSavedSettings.getBOOL("RenderAvatarVP") + && gSavedSettings.getBOOL("RenderDeferred"); if (gPipeline.isInit()) { gPipeline.updateRenderTransparentWater(); @@ -547,7 +575,10 @@ static bool handleRenderDeferredChanged(const LLSD& newvalue) // static bool handleRenderBumpChanged(const LLSD& newval) { - LLRenderTarget::sUseFBO = newval.asBoolean(); + LLRenderTarget::sUseFBO = newval.asBoolean() + && gSavedSettings.getBOOL("RenderTransparentWater") + && gSavedSettings.getBOOL("RenderAvatarVP") + && gSavedSettings.getBOOL("RenderDeferred"); if (gPipeline.isInit()) { gPipeline.updateRenderBump(); @@ -1059,6 +1090,40 @@ void handleDiskCacheSizeChanged(const LLSD& newValue) } // +// perrf floater stuffs +void handleTargetFPSChanged(const LLSD& newValue) +{ + const auto targetFPS = gSavedSettings.getU32("FSTargetFPS"); + FSPerfStats::targetFPS = targetFPS; +} + +// perrf floater stuffs +void handleAutoTuneFPSChanged(const LLSD& newValue) +{ + const auto newval = gSavedSettings.getBOOL("FSAutoTuneFPS"); + FSPerfStats::autoTune = newval; + if(newval && FSPerfStats::renderAvatarMaxART_ns == 0) // If we've enabled autotune we override "unlimited" to max + { + gSavedSettings.setF32("FSRenderAvatarMaxART",log10(FSPerfStats::ART_UNLIMITED_NANOS-1000));//triggers callback to update static var + } +} + +void handleRenderAvatarMaxARTChanged(const LLSD& newValue) +{ + FSPerfStats::StatsRecorder::updateRenderCostLimitFromSettings(); +} +void handleFPSTuningStrategyChanged(const LLSD& newValue) +{ + const auto newval = gSavedSettings.getU32("FSTuningFPSStrategy"); + FSPerfStats::fpsTuningStrategy = newval; +} +void handlePerformanceStatsEnabledChanged(const LLSD& newValue) +{ + const auto newval = gSavedSettings.getBOOL("FSPerfStatsCaptureEnabled"); + FSPerfStats::StatsRecorder::setEnabled(newval); +} +// + //////////////////////////////////////////////////////////////////////////// void settings_setup_listeners() @@ -1073,7 +1138,7 @@ void settings_setup_listeners() gSavedSettings.getControl("OctreeAttachmentSizeFactor")->getSignal()->connect(boost::bind(&handleRepartition, _2)); gSavedSettings.getControl("RenderMaxTextureIndex")->getSignal()->connect(boost::bind(&handleSetShaderChanged, _2)); gSavedSettings.getControl("RenderUseTriStrips")->getSignal()->connect(boost::bind(&handleResetVertexBuffersChanged, _2)); - gSavedSettings.getControl("RenderAvatarVP")->getSignal()->connect(boost::bind(&handleSetShaderChanged, _2)); + gSavedSettings.getControl("RenderAvatarVP")->getSignal()->connect(boost::bind(&handleAvatarVPChanged, _2)); gSavedSettings.getControl("RenderUIBuffer")->getSignal()->connect(boost::bind(&handleWindowResized, _2)); gSavedSettings.getControl("RenderDepthOfField")->getSignal()->connect(boost::bind(&handleReleaseGLBufferChanged, _2)); gSavedSettings.getControl("RenderFSAASamples")->getSignal()->connect(boost::bind(&handleReleaseGLBufferChanged, _2)); @@ -1313,6 +1378,14 @@ void settings_setup_listeners() // Better asset cache size control gSavedSettings.getControl("FSDiskCacheSize")->getSignal()->connect(boost::bind(&handleDiskCacheSizeChanged, _2)); + + // perf floater controls + gSavedSettings.getControl("FSTargetFPS")->getSignal()->connect(boost::bind(&handleTargetFPSChanged, _2)); + gSavedSettings.getControl("FSAutoTuneFPS")->getSignal()->connect(boost::bind(&handleAutoTuneFPSChanged, _2)); + gSavedSettings.getControl("FSRenderAvatarMaxART")->getSignal()->connect(boost::bind(&handleRenderAvatarMaxARTChanged, _2)); + gSavedSettings.getControl("FSTuningFPSStrategy")->getSignal()->connect(boost::bind(&handleFPSTuningStrategyChanged, _2)); + gSavedSettings.getControl("FSPerfStatsCaptureEnabled")->getSignal()->connect(boost::bind(&handlePerformanceStatsEnabledChanged, _2)); + // } #if TEST_CACHED_CONTROL diff --git a/indra/newview/llviewerdisplay.cpp b/indra/newview/llviewerdisplay.cpp index e23d990184..fe78e0df51 100644 --- a/indra/newview/llviewerdisplay.cpp +++ b/indra/newview/llviewerdisplay.cpp @@ -85,6 +85,7 @@ // [/RLVa:KB] #include "llpresetsmanager.h" #include "fsdata.h" +#include "fsperfstats.h" // performance stats support extern LLPointer gStartTexture; extern bool gShiftFrame; @@ -280,6 +281,7 @@ static LLTrace::BlockTimerStatHandle FTM_EEP_UPDATE("Env Update"); // Paint the display! void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot) { + FSPerfStats::RecordSceneTime T (FSPerfStats::StatType_t::RENDER_DISPLAY); // render time capture - This is the main stat for overall rendering. LL_RECORD_BLOCK_TIME(FTM_RENDER); LLViewerCamera& camera = LLViewerCamera::instance(); // Factor out calls to getInstance @@ -1192,6 +1194,7 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot) void render_hud_attachments() { + FSPerfStats::RecordSceneTime T ( FSPerfStats::StatType_t::RENDER_HUDS); // render time capture - Primary contributor to HUDs (though these end up in render batches) gGL.matrixMode(LLRender::MM_PROJECTION); gGL.pushMatrix(); gGL.matrixMode(LLRender::MM_MODELVIEW); @@ -1399,6 +1402,7 @@ bool setup_hud_matrices(const LLRect& screen_region) void render_ui(F32 zoom_factor, int subfield) { + FSPerfStats::RecordSceneTime T ( FSPerfStats::StatType_t::RENDER_UI ); // render time capture - Primary UI stat can have HUD time overlap (TODO) LL_RECORD_BLOCK_TIME(FTM_RENDER_UI); LLGLState::checkStates(); @@ -1484,6 +1488,7 @@ static LLTrace::BlockTimerStatHandle FTM_SWAP("Swap"); void swap() { + FSPerfStats::RecordSceneTime T ( FSPerfStats::StatType_t::RENDER_SWAP ); // render time capture - Swap buffer time - can signify excessive data transfer to/from GPU LL_RECORD_BLOCK_TIME(FTM_SWAP); if (gDisplaySwapBuffers) diff --git a/indra/newview/llviewerfloaterreg.cpp b/indra/newview/llviewerfloaterreg.cpp index 393b62d61a..c1efbe9bc2 100644 --- a/indra/newview/llviewerfloaterreg.cpp +++ b/indra/newview/llviewerfloaterreg.cpp @@ -33,6 +33,7 @@ #include "llcommandhandler.h" #include "llcompilequeue.h" #include "llfasttimerview.h" +#include "llfloater360capture.h" #include "llfloaterabout.h" #include "llfloateraddpaymentmethod.h" #include "llfloaterauction.h" @@ -105,9 +106,12 @@ #include "llfloaterpathfindingconsole.h" #include "llfloaterpathfindinglinksets.h" #include "llfloaterpay.h" +// #include "llfloaterperformance.h" rename to fs as ll version no released +#include "fsfloaterperformance.h" #include "llfloaterperms.h" #include "llfloaterpostprocess.h" #include "llfloaterpreference.h" +#include "llfloaterpreferencesgraphicsadvanced.h" #include "llfloaterpreferenceviewadvanced.h" #include "llfloaterpreviewtrash.h" #include "llfloaterproperties.h" @@ -246,6 +250,7 @@ void LLViewerFloaterReg::registerFloaters() // *NOTE: Please keep these alphabetized for easier merges LLFloaterAboutUtil::registerFloater(); + LLFloaterReg::add("360capture", "floater_360capture.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); LLFloaterReg::add("block_timers", "floater_fast_timers.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); LLFloaterReg::add("about_land", "floater_about_land.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); LLFloaterReg::add("add_payment_method", "floater_add_payment_method.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); @@ -379,10 +384,11 @@ void LLViewerFloaterReg::registerFloaters() LLFloaterReg::add("pathfinding_linksets", "floater_pathfinding_linksets.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); LLFloaterReg::add("pathfinding_console", "floater_pathfinding_console.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); LLFloaterReg::add("people", "floater_people.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + //LLFloaterReg::add("performance", "floater_performance.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); LLFloaterReg::add("perms_default", "floater_perms_default.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); LLFloaterReg::add("places", "floater_places.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); LLFloaterReg::add("preferences", "floater_preferences.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); - LLFloaterReg::add("prefs_graphics_advanced", "floater_preferences_graphics_advanced.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + // LLFloaterReg::add("prefs_graphics_advanced", "floater_preferences_graphics_advanced.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); LLFloaterReg::add("prefs_view_advanced", "floater_preferences_view_advanced.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); LLFloaterReg::add("prefs_proxy", "floater_preferences_proxy.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); LLFloaterReg::add("prefs_spellchecker_import", "floater_spellcheck_import.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); @@ -500,6 +506,7 @@ void LLViewerFloaterReg::registerFloaters() LLFloaterReg::add("media_lists", "floater_media_lists.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); LLFloaterReg::add("money_tracker", "floater_fs_money_tracker.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); LLFloaterReg::add("particle_editor","floater_particle_editor.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + LLFloaterReg::add("performance", "floater_performance.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); LLFloaterReg::add(PHOTOTOOLS_FLOATER, "floater_phototools.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); LLFloaterReg::add("phototools_camera", "floater_phototools_camera.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); LLFloaterReg::add("publish_classified_fs", "floater_publish_classified.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); diff --git a/indra/newview/llviewerinput.cpp b/indra/newview/llviewerinput.cpp index 07a0bb302d..782cf21728 100644 --- a/indra/newview/llviewerinput.cpp +++ b/indra/newview/llviewerinput.cpp @@ -42,6 +42,7 @@ #include "llkeybind.h" // LLKeyData #include "llmorphview.h" #include "llmoveview.h" +#include "llsetkeybinddialog.h" #include "lltoolfocus.h" #include "lltoolpie.h" #include "llviewercontrol.h" @@ -67,8 +68,21 @@ const F32 ORBIT_NUDGE_RATE = 0.05f; // fraction of normal speed const LLKeyData agent_control_lbutton(CLICK_LEFT, KEY_NONE, MASK_NONE, true); +struct LLKeybindFunctionData +{ + LLKeybindFunctionData(boost::function function, bool global) + : + mFunction(function), + mIsGlobal(global) + { + } + boost::function mFunction; + // todo: might be good idea to make this into enum, like: global/inworld/menu + bool mIsGlobal; +}; + struct LLKeyboardActionRegistry -: public LLRegistrySingleton, LLKeyboardActionRegistry> +: public LLRegistrySingleton { LLSINGLETON_EMPTY_CTOR(LLKeyboardActionRegistry); }; @@ -722,22 +736,22 @@ bool run_forward(EKeystate s) } if (!gAgent.getRunning()) { +// [RLVa:KB] - @temprun + gAgent.setTempRun(); +// [/RLVa:KB] // gAgent.setRunning(); // gAgent.sendWalkRun(true); -// [RLVa:KB] - Checked: 2011-05-11 (RLVa-1.3.0i) | Added: RLVa-1.3.0i - gAgent.setTempRun(); -// [/RLVa:KB] } } else if(KEYSTATE_UP == s) { if (gAgent.mDoubleTapRunMode == LLAgent::DOUBLETAP_FORWARD) gAgent.mDoubleTapRunMode = LLAgent::DOUBLETAP_NONE; +// [RLVa:KB] - @temprun + gAgent.clearTempRun(); +// [/RLVa:KB] // gAgent.clearRunning(); // gAgent.sendWalkRun(false); -// [RLVa:KB] - Checked: 2011-05-11 (RLVa-1.3.0i) | Added: RLVa-1.3.0i - gAgent.clearTempRun(); -// [/RLVa:KB] } agent_push_forward(s); return true; @@ -753,22 +767,22 @@ bool run_backward(EKeystate s) } if (!gAgent.getRunning()) { +// [RLVa:KB] - @temprun + gAgent.setTempRun(); +// [/RLVa:KB] // gAgent.setRunning(); // gAgent.sendWalkRun(true); -// [RLVa:KB] - Checked: 2011-05-11 (RLVa-1.3.0i) | Added: RLVa-1.3.0i - gAgent.setTempRun(); -// [/RLVa:KB] } } else if (KEYSTATE_UP == s) { if (gAgent.mDoubleTapRunMode == LLAgent::DOUBLETAP_BACKWARD) gAgent.mDoubleTapRunMode = LLAgent::DOUBLETAP_NONE; +// [RLVa:KB] - @temprun + gAgent.clearTempRun(); +// [/RLVa:KB] // gAgent.clearRunning(); // gAgent.sendWalkRun(false); -// [RLVa:KB] - Checked: 2011-05-11 (RLVa-1.3.0i) | Added: RLVa-1.3.0i - gAgent.clearTempRun(); -// [/RLVa:KB] } agent_push_backward(s); return true; @@ -784,22 +798,22 @@ bool run_left(EKeystate s) } if (!gAgent.getRunning()) { +// [RLVa:KB] - @temprun + gAgent.setTempRun(); +// [/RLVa:KB] // gAgent.setRunning(); // gAgent.sendWalkRun(true); -// [RLVa:KB] - Checked: 2011-05-11 (RLVa-1.3.0i) | Added: RLVa-1.3.0i - gAgent.setTempRun(); -// [/RLVa:KB] } } else if (KEYSTATE_UP == s) { if (gAgent.mDoubleTapRunMode == LLAgent::DOUBLETAP_SLIDELEFT) gAgent.mDoubleTapRunMode = LLAgent::DOUBLETAP_NONE; +// [RLVa:KB] - @temprun + gAgent.clearTempRun(); +// [/RLVa:KB] // gAgent.clearRunning(); // gAgent.sendWalkRun(false); -// [RLVa:KB] - Checked: 2011-05-11 (RLVa-1.3.0i) | Added: RLVa-1.3.0i - gAgent.clearTempRun(); -// [/RLVa:KB] } agent_slide_left(s); return true; @@ -815,22 +829,22 @@ bool run_right(EKeystate s) } if (!gAgent.getRunning()) { +// [RLVa:KB] - @temprun + gAgent.setTempRun(); +// [/RLVa:KB] // gAgent.setRunning(); // gAgent.sendWalkRun(true); -// [RLVa:KB] - Checked: 2011-05-11 (RLVa-1.3.0i) | Added: RLVa-1.3.0i - gAgent.setTempRun(); -// [/RLVa:KB] } } else if (KEYSTATE_UP == s) { if (gAgent.mDoubleTapRunMode == LLAgent::DOUBLETAP_SLIDERIGHT) gAgent.mDoubleTapRunMode = LLAgent::DOUBLETAP_NONE; +// [RLVa:KB] - @temprun + gAgent.clearTempRun(); +// [/RLVa:KB] // gAgent.clearRunning(); // gAgent.sendWalkRun(false); -// [RLVa:KB] - Checked: 2011-05-11 (RLVa-1.3.0i) | Added: RLVa-1.3.0i - gAgent.clearTempRun(); -// [/RLVa:KB] } agent_slide_right(s); return true; @@ -842,19 +856,21 @@ bool toggle_run(EKeystate s) bool run = gAgent.getAlwaysRun(); if (run) { - gAgent.clearAlwaysRun(); -// [RLVa:KB] - Checked: 2011-05-11 (RLVa-1.3.0i) | Added: RLVa-1.3.0i -// gAgent.clearRunning(); +// [RLVa:KB] - @alwaysrun + gAgent.clearAlwaysRun(); // [/RLVa:KB] +// gAgent.clearAlwaysRun(); +// gAgent.clearRunning(); } else { - gAgent.setAlwaysRun(); -// [RLVa:KB] - Checked: 2011-05-11 (RLVa-1.3.0i) | Added: RLVa-1.3.0i -// gAgent.setRunning(); +// [RLVa:KB] - @alwaysrun + gAgent.setAlwaysRun(); // [/RLVa:KB] +// gAgent.setAlwaysRun(); +// gAgent.setRunning(); } -// [RLVa:KB] - Checked: 2011-05-11 (RLVa-1.3.0i) | Added: RLVa-1.3.0i +// gAgent.sendWalkRun(!run); // gAgent.sendWalkRun(!run); // [/RLVa:KB] return true; @@ -942,7 +958,10 @@ bool agen_control_lbutton_handle(EKeystate s) return true; } -#define REGISTER_KEYBOARD_ACTION(KEY, ACTION) LLREGISTER_STATIC(LLKeyboardActionRegistry, KEY, ACTION); +// In-world keybindings, like walking or camera +#define REGISTER_KEYBOARD_ACTION(KEY, ACTION) LLREGISTER_STATIC(LLKeyboardActionRegistry, KEY, LLKeybindFunctionData(ACTION, false)); +// Global keybindings that should work even with floaters focused, like voice +#define REGISTER_KEYBOARD_GLOBAL_ACTION(KEY, ACTION) LLREGISTER_STATIC(LLKeyboardActionRegistry, KEY, LLKeybindFunctionData(ACTION, true)); REGISTER_KEYBOARD_ACTION("jump", agent_jump); REGISTER_KEYBOARD_ACTION("push_down", agent_push_down); REGISTER_KEYBOARD_ACTION("push_forward", agent_push_forward); @@ -993,8 +1012,8 @@ REGISTER_KEYBOARD_ACTION("toggle_pause_media", toggle_pause_media); REGISTER_KEYBOARD_ACTION("toggle_enable_media", toggle_enable_media); REGISTER_KEYBOARD_ACTION("teleport_to", teleport_to); REGISTER_KEYBOARD_ACTION("walk_to", walk_to); -REGISTER_KEYBOARD_ACTION("toggle_voice", toggle_voice); -REGISTER_KEYBOARD_ACTION("voice_follow_key", voice_follow_key); +REGISTER_KEYBOARD_GLOBAL_ACTION("toggle_voice", toggle_voice); +REGISTER_KEYBOARD_GLOBAL_ACTION("voice_follow_key", voice_follow_key); #undef REGISTER_KEYBOARD_ACTION LLViewerInput::LLViewerInput() @@ -1125,6 +1144,53 @@ BOOL LLViewerInput::handleKeyUp(KEY translated_key, MASK translated_mask) return gViewerWindow->handleKeyUp(translated_key, translated_mask); } +bool LLViewerInput::handleGlobalBindsKeyDown(KEY key, MASK mask) +{ + if (LLSetKeyBindDialog::isRecording()) + { + // handleGlobalBindsKeyDown happens before view handling, so can't + // be interupted by LLSetKeyBindDialog, check manually + return false; + } + S32 mode = getMode(); + return scanKey(mGlobalKeyBindings[mode], mGlobalKeyBindings[mode].size(), key, mask, TRUE, FALSE, FALSE, FALSE); +} + +bool LLViewerInput::handleGlobalBindsKeyUp(KEY key, MASK mask) +{ + if (LLSetKeyBindDialog::isRecording()) + { + // handleGlobalBindsKeyUp happens before view handling, so can't + // be interupted by LLSetKeyBindDialog, check manually + return false; + } + + S32 mode = getMode(); + return scanKey(mGlobalKeyBindings[mode], mGlobalKeyBindings[mode].size(), key, mask, FALSE, TRUE, FALSE, FALSE); +} + +bool LLViewerInput::handleGlobalBindsMouse(EMouseClickType clicktype, MASK mask, bool down) +{ + if (LLSetKeyBindDialog::isRecording()) + { + // handleGlobalBindsMouse happens before view handling, so can't + // be interupted by LLSetKeyBindDialog, check manually + return false; + } + + bool res = false; + S32 mode = getMode(); + if (down) + { + res = scanMouse(mGlobalMouseBindings[mode], mGlobalMouseBindings[mode].size(), clicktype, mask, MOUSE_STATE_DOWN, true); + } + else + { + res = scanMouse(mGlobalMouseBindings[mode], mGlobalMouseBindings[mode].size(), clicktype, mask, MOUSE_STATE_UP, true); + } + return res; +} + BOOL LLViewerInput::bindKey(const S32 mode, const KEY key, const MASK mask, const std::string& function_name) { S32 index; @@ -1152,39 +1218,64 @@ BOOL LLViewerInput::bindKey(const S32 mode, const KEY key, const MASK mask, cons } // Not remapped, look for a function - - function_t* result = LLKeyboardActionRegistry::getValue(function_name); + + LLKeybindFunctionData* result = LLKeyboardActionRegistry::getValue(function_name); if (result) { - function = *result; + function = result->mFunction; } if (!function) { - LL_ERRS() << "Can't bind key to function " << function_name << ", no function with this name found" << LL_ENDL; + LL_WARNS_ONCE() << "Can't bind key to function " << function_name << ", no function with this name found" << LL_ENDL; return FALSE; } - // check for duplicate first and overwrite - S32 size = mKeyBindings[mode].size(); - for (index = 0; index < size; index++) + if (mode >= MODE_COUNT) { - if (key == mKeyBindings[mode][index].mKey && mask == mKeyBindings[mode][index].mMask) - break; + LL_ERRS() << "LLKeyboard::bindKey() - unknown mode passed" << mode << LL_ENDL; + return FALSE; } - if (mode >= MODE_COUNT) - { - LL_ERRS() << "LLKeyboard::bindKey() - unknown mode passed" << mode << LL_ENDL; - return FALSE; - } + // check for duplicate first and overwrite + if (result->mIsGlobal) + { + S32 size = mGlobalKeyBindings[mode].size(); + for (index = 0; index < size; index++) + { + if (key == mGlobalKeyBindings[mode][index].mKey && mask == mGlobalKeyBindings[mode][index].mMask) + { + mGlobalKeyBindings[mode][index].mFunction = function; + return TRUE; + } + } + } + else + { + S32 size = mKeyBindings[mode].size(); + for (index = 0; index < size; index++) + { + if (key == mKeyBindings[mode][index].mKey && mask == mKeyBindings[mode][index].mMask) + { + mKeyBindings[mode][index].mFunction = function; + return TRUE; + } + } + } LLKeyboardBinding bind; bind.mKey = key; bind.mMask = mask; bind.mFunction = function; - mKeyBindings[mode].push_back(bind); + if (result->mIsGlobal) + { + mGlobalKeyBindings[mode].push_back(bind); + } + else + { + mKeyBindings[mode].push_back(bind); + } return TRUE; } @@ -1195,38 +1286,63 @@ BOOL LLViewerInput::bindMouse(const S32 mode, const EMouseClickType mouse, const typedef boost::function function_t; function_t function = NULL; - function_t* result = LLKeyboardActionRegistry::getValue(function_name); + LLKeybindFunctionData* result = LLKeyboardActionRegistry::getValue(function_name); if (result) { - function = *result; + function = result->mFunction; } if (!function) { - LL_ERRS() << "Can't bind key to function " << function_name << ", no function with this name found" << LL_ENDL; + LL_WARNS_ONCE() << "Can't bind mouse key to function " << function_name << ", no function with this name found" << LL_ENDL; return FALSE; } - // check for duplicate first and overwrite - S32 size = mMouseBindings[mode].size(); - for (index = 0; index < size; index++) - { - if (mouse == mMouseBindings[mode][index].mMouse && mask == mMouseBindings[mode][index].mMask) - break; - } - if (mode >= MODE_COUNT) { LL_ERRS() << "LLKeyboard::bindKey() - unknown mode passed" << mode << LL_ENDL; return FALSE; } + // check for duplicate first and overwrite + if (result->mIsGlobal) + { + S32 size = mGlobalMouseBindings[mode].size(); + for (index = 0; index < size; index++) + { + if (mouse == mGlobalMouseBindings[mode][index].mMouse && mask == mGlobalMouseBindings[mode][index].mMask) + { + mGlobalMouseBindings[mode][index].mFunction = function; + return true; + } + } + } + else + { + S32 size = mMouseBindings[mode].size(); + for (index = 0; index < size; index++) + { + if (mouse == mMouseBindings[mode][index].mMouse && mask == mMouseBindings[mode][index].mMask) + { + mMouseBindings[mode][index].mFunction = function; + return true; + } + } + } + LLMouseBinding bind; bind.mMouse = mouse; bind.mMask = mask; bind.mFunction = function; - mMouseBindings[mode].push_back(bind); + if (result->mIsGlobal) + { + mGlobalMouseBindings[mode].push_back(bind); + } + else + { + mMouseBindings[mode].push_back(bind); + } return TRUE; } @@ -1253,6 +1369,8 @@ void LLViewerInput::resetBindings() { for (S32 i = 0; i < MODE_COUNT; i++) { + mGlobalKeyBindings[i].clear(); + mGlobalMouseBindings[i].clear(); mKeyBindings[i].clear(); mMouseBindings[i].clear(); } @@ -1530,11 +1648,18 @@ BOOL LLViewerInput::handleMouse(LLWindow *window_impl, LLCoordGL pos, MASK mask, return handled; } -bool LLViewerInput::scanMouse(const std::vector &binding, S32 binding_count, EMouseClickType mouse, MASK mask, EMouseState state) const +bool LLViewerInput::scanMouse( + const std::vector &binding, + S32 binding_count, + EMouseClickType mouse, + MASK mask, + EMouseState state, + bool ignore_additional_masks +) const { for (S32 i = 0; i < binding_count; i++) { - if (binding[i].mMouse == mouse && (binding[i].mMask & mask) == binding[i].mMask) + if (binding[i].mMouse == mouse && (ignore_additional_masks ? (binding[i].mMask & mask) == binding[i].mMask : binding[i].mMask == mask)) { bool res = false; switch (state) @@ -1571,7 +1696,11 @@ bool LLViewerInput::scanMouse(EMouseClickType click, EMouseState state) const bool res = false; S32 mode = getMode(); MASK mask = gKeyboard->currentMask(TRUE); - res = scanMouse(mMouseBindings[mode], mMouseBindings[mode].size(), click, mask, state); + + // By default mouse clicks require exact mask + // Todo: support for mIgnoreMasks because some functions like teleports + // expect to be canceled, but for voice it's prefered to ignore mask. + res = scanMouse(mMouseBindings[mode], mMouseBindings[mode].size(), click, mask, state, false); // no user defined actions found or those actions can't handle the key/button, handle control if nessesary if (!res && agent_control_lbutton.canHandle(click, KEY_NONE, mask)) { @@ -1627,5 +1756,11 @@ bool LLViewerInput::isMouseBindUsed(const EMouseClickType mouse, const MASK mask if (mouse == mMouseBindings[mode][index].mMouse && mask == mMouseBindings[mode][index].mMask) return true; } + size = mGlobalMouseBindings[mode].size(); + for (S32 index = 0; index < size; index++) + { + if (mouse == mGlobalMouseBindings[mode][index].mMouse && mask == mGlobalMouseBindings[mode][index].mMask) + return true; + } return false; } diff --git a/indra/newview/llviewerinput.h b/indra/newview/llviewerinput.h index 8461e0cd9b..2efb5c95ba 100644 --- a/indra/newview/llviewerinput.h +++ b/indra/newview/llviewerinput.h @@ -109,6 +109,13 @@ public: BOOL handleKey(KEY key, MASK mask, BOOL repeated); BOOL handleKeyUp(KEY key, MASK mask); + // Handle 'global' keybindings that do not consume event, + // yet need to be processed early + // Example: we want voice to toggle even if some floater is focused + bool handleGlobalBindsKeyDown(KEY key, MASK mask); + bool handleGlobalBindsKeyUp(KEY key, MASK mask); + bool handleGlobalBindsMouse(EMouseClickType clicktype, MASK mask, bool down); + S32 loadBindingsXML(const std::string& filename); // returns number bound, 0 on error EKeyboardMode getMode() const; @@ -149,7 +156,8 @@ private: S32 binding_count, EMouseClickType mouse, MASK mask, - EMouseState state) const; + EMouseState state, + bool ignore_additional_masks) const; S32 loadBindingMode(const LLViewerInput::KeyMode& keymode, S32 mode); BOOL bindKey(const S32 mode, const KEY key, const MASK mask, const std::string& function_name); @@ -164,6 +172,10 @@ private: std::vector mKeyBindings[MODE_COUNT]; std::vector mMouseBindings[MODE_COUNT]; + // keybindings that do not consume event and are handled earlier, before floaters + std::vector mGlobalKeyBindings[MODE_COUNT]; + std::vector mGlobalMouseBindings[MODE_COUNT]; + typedef std::map key_remap_t; key_remap_t mRemapKeys[MODE_COUNT]; std::set mKeysSkippedByUI; diff --git a/indra/newview/llviewerinventory.cpp b/indra/newview/llviewerinventory.cpp index 34c3b7c5ee..3cdf8bb86d 100644 --- a/indra/newview/llviewerinventory.cpp +++ b/indra/newview/llviewerinventory.cpp @@ -2126,7 +2126,7 @@ void menu_create_inventory_item(LLInventoryPanel* panel, LLFolderBridge *bridge, else { // Use for all clothing and body parts. Adding new wearable types requires updating LLWearableDictionary. - LLWearableType::EType wearable_type = LLWearableType::typeNameToType(type_name); + LLWearableType::EType wearable_type = LLWearableType::getInstance()->typeNameToType(type_name); if (wearable_type >= LLWearableType::WT_SHAPE && wearable_type < LLWearableType::WT_COUNT) { const LLUUID parent_id = bridge ? bridge->getUUID() : LLUUID::null; diff --git a/indra/newview/llviewerjointmesh.cpp b/indra/newview/llviewerjointmesh.cpp index d2cfe2cf98..e873057191 100644 --- a/indra/newview/llviewerjointmesh.cpp +++ b/indra/newview/llviewerjointmesh.cpp @@ -55,6 +55,7 @@ #include "m3math.h" #include "m4math.h" #include "llmatrix4a.h" +#include "fsperfstats.h" // performance stats support #if !LL_DARWIN && !LL_LINUX extern PFNGLWEIGHTPOINTERARBPROC glWeightPointerARB; @@ -222,6 +223,7 @@ int compare_int(const void *a, const void *b) //-------------------------------------------------------------------- U32 LLViewerJointMesh::drawShape( F32 pixelArea, BOOL first_pass, BOOL is_dummy) { + FSZone; if (!mValid || !mMesh || !mFace || !mVisible || !mFace->getVertexBuffer() || mMesh->getNumFaces() == 0 || @@ -230,6 +232,15 @@ U32 LLViewerJointMesh::drawShape( F32 pixelArea, BOOL first_pass, BOOL is_dummy) return 0; } + // render time capture + // TODO(Beq) This path does not appear to have attachments. Prove this then remove. + std::unique_ptr ratPtr{}; + auto vobj = mFace->getViewerObject(); + if( vobj && vobj->isAttachment() ) + { + trackAttachments( vobj, mFace->isState(LLFace::RIGGED), &ratPtr ); + } +// U32 triangle_count = 0; S32 diffuse_channel = LLDrawPoolAvatar::sDiffuseChannel; diff --git a/indra/newview/llviewermedia.cpp b/indra/newview/llviewermedia.cpp index 997e64a131..ba8801bbce 100644 --- a/indra/newview/llviewermedia.cpp +++ b/indra/newview/llviewermedia.cpp @@ -1314,7 +1314,13 @@ void LLViewerMedia::getOpenIDCookieCoro(std::string url) // down. std::string cefUrl(std::string(inst->mOpenIDURL.mURI) + "://" + std::string(inst->mOpenIDURL.mAuthority)); - media_instance->getMediaPlugin()->setCookie(cefUrl, cookie_name, cookie_value, cookie_host, cookie_path, httponly, secure); + media_instance->getMediaPlugin()->setCookie(cefUrl, cookie_name, cookie_value, cookie_host, + cookie_path, httponly, secure); + + // Now that we have parsed the raw cookie, we must store it so that each new media instance + // can also get a copy and faciliate logging into internal SL sites. + media_instance->getMediaPlugin()->storeOpenIDCookie(cefUrl, cookie_name, cookie_value, + cookie_host, cookie_path, httponly, secure); } } } @@ -1787,8 +1793,16 @@ LLPluginClassMedia* LLViewerMediaImpl::newSourceFromMediaType(std::string media_ media_source->cookies_enabled( cookies_enabled || clean_browser); // collect 'javascript enabled' setting from prefs and send to embedded browser - bool javascript_enabled = gSavedSettings.getBOOL( "BrowserJavascriptEnabled" ); - media_source->setJavascriptEnabled( javascript_enabled || clean_browser); + bool javascript_enabled = gSavedSettings.getBOOL("BrowserJavascriptEnabled"); + media_source->setJavascriptEnabled(javascript_enabled || clean_browser); + + // collect 'web security disabled' (see Chrome --web-security-disabled) setting from prefs and send to embedded browser + bool web_security_disabled = gSavedSettings.getBOOL("BrowserWebSecurityDisabled"); + media_source->setWebSecurityDisabled(web_security_disabled || clean_browser); + + // collect setting indicates if local file access from file URLs is allowed from prefs and send to embedded browser + bool file_access_from_file_urls = gSavedSettings.getBOOL("BrowserFileAccessFromFileUrls"); + media_source->setFileAccessFromFileUrlsEnabled(file_access_from_file_urls || clean_browser); // As of SL-15559 PDF files do not load in CEF v91 we enable plugins // but explicitly disable Flash (PDF support in CEF is now treated as a plugin) @@ -1866,6 +1880,7 @@ bool LLViewerMediaImpl::initializePlugin(const std::string& media_type) if (media_source) { + media_source->injectOpenIDCookie(); media_source->setDisableTimeout(gSavedSettings.getBOOL("DebugPluginDisableTimeout")); media_source->setLoop(mMediaLoop); media_source->setAutoScale(mMediaAutoScale); @@ -1948,6 +1963,15 @@ void LLViewerMediaImpl::loadURI() } } +////////////////////////////////////////////////////////////////////////////////////////// +void LLViewerMediaImpl::executeJavaScript(const std::string& code) +{ + if (mMediaSource) + { + mMediaSource->executeJavaScript(code); + } +} + ////////////////////////////////////////////////////////////////////////////////////////// void LLViewerMediaImpl::setSize(int width, int height) { @@ -3276,8 +3300,19 @@ void LLViewerMediaImpl::handleMediaEvent(LLPluginClassMedia* plugin, LLPluginCla case LLViewerMediaObserver::MEDIA_EVENT_FILE_DOWNLOAD: { - //llinfos << "Media event - file download requested - filename is " << self->getFileDownloadFilename() << llendl; - LLNotificationsUtil::add("MediaFileDownloadUnsupported"); + LL_DEBUGS("Media") << "Media event - file download requested - filename is " << plugin->getFileDownloadFilename() << LL_ENDL; + // pick a file from SAVE FILE dialog + + // need a better algorithm that this or else, pass in type of save type + // from event that initiated it - this is okay for now - only thing + // that saves is 360s + std::string suggested_filename = plugin->getFileDownloadFilename(); + LLFilePicker::ESaveFilter filter = LLFilePicker::FFSAVE_ALL; + if (suggested_filename.find(".jpg") != std::string::npos || suggested_filename.find(".jpeg") != std::string::npos) + filter = LLFilePicker::FFSAVE_JPEG; + if (suggested_filename.find(".png") != std::string::npos) + filter = LLFilePicker::FFSAVE_PNG; + init_threaded_picker_save_dialog(plugin, filter, suggested_filename); } break; diff --git a/indra/newview/llviewermedia.h b/indra/newview/llviewermedia.h index 8bf1ad2441..71cec5125d 100644 --- a/indra/newview/llviewermedia.h +++ b/indra/newview/llviewermedia.h @@ -207,6 +207,7 @@ public: bool initializeMedia(const std::string& mime_type); bool initializePlugin(const std::string& media_type); void loadURI(); + void executeJavaScript(const std::string& code); LLPluginClassMedia* getMediaPlugin() { return mMediaSource.get(); } void setSize(int width, int height); diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index a39cdf709e..dd9c8a4ba3 100644 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -423,26 +423,36 @@ LLMenuParcelObserver::~LLMenuParcelObserver() void LLMenuParcelObserver::changed() { LLParcel *parcel = LLViewerParcelMgr::getInstance()->getParcelSelection()->getParcel(); - // FIRE-4454: Cache controls because of performance reasons - //gMenuHolder->childSetEnabled("Land Buy Pass", LLPanelLandGeneral::enableBuyPass(NULL) && !(parcel->getOwnerID()== gAgent.getID())); - // - //BOOL buyable = enable_buy_land(NULL); - //gMenuHolder->childSetEnabled("Land Buy", buyable); - //gMenuHolder->childSetEnabled("Buy Land...", buyable); + if (gMenuLand && parcel) + { + // FIRE-4454: Cache controls because of performance reasons + //LLView* child = gMenuLand->findChild("Land Buy Pass"); + //if (child) + //{ + // child->setEnabled(LLPanelLandGeneral::enableBuyPass(NULL) && !(parcel->getOwnerID() == gAgent.getID())); + //} + // + //child = gMenuLand->findChild("Land Buy"); + //if (child) + //{ + // BOOL buyable = enable_buy_land(NULL); + // child->setEnabled(buyable); + //} - static LLView* land_buy_pass = gMenuHolder->getChildView("Land Buy Pass"); - static LLView* land_buy_pass_pie = gMenuHolder->getChildView("Land Buy Pass Pie"); - static LLView* land_buy = gMenuHolder->getChildView("Land Buy"); - static LLView* land_buy_pie = gMenuHolder->getChildView("Land Buy Pie"); + static LLView* land_buy_pass = gMenuHolder->getChildView("Land Buy Pass"); + static LLView* land_buy_pass_pie = gMenuHolder->getChildView("Land Buy Pass Pie"); + static LLView* land_buy = gMenuHolder->getChildView("Land Buy"); + static LLView* land_buy_pie = gMenuHolder->getChildView("Land Buy Pie"); - BOOL pass_buyable = LLPanelLandGeneral::enableBuyPass(NULL) && parcel->getOwnerID() != gAgentID; - land_buy_pass->setEnabled(pass_buyable); - land_buy_pass_pie->setEnabled(pass_buyable); + BOOL pass_buyable = LLPanelLandGeneral::enableBuyPass(NULL) && parcel->getOwnerID() != gAgentID; + land_buy_pass->setEnabled(pass_buyable); + land_buy_pass_pie->setEnabled(pass_buyable); - BOOL buyable = enable_buy_land(NULL); - land_buy->setEnabled(buyable); - land_buy_pie->setEnabled(buyable); - // FIRE-4454: Cache controls because of performance reasons + BOOL buyable = enable_buy_land(NULL); + land_buy->setEnabled(buyable); + land_buy_pie->setEnabled(buyable); + // FIRE-4454: Cache controls because of performance reasons + } } @@ -1450,12 +1460,55 @@ class LLAdvancedDumpScriptedCamera : public view_listener_t class LLAdvancedDumpRegionObjectCache : public view_listener_t { bool handleEvent(const LLSD& userdata) -{ + { handle_dump_region_object_cache(NULL); return true; } }; +class LLAdvancedInterestListFullUpdate : public view_listener_t +{ + bool handleEvent(const LLSD& userdata) + { + LLSD request; + LLSD body; + static bool using_360 = false; + + if (using_360) + { + body["mode"] = LLSD::String("default"); + } + else + { + body["mode"] = LLSD::String("360"); + } + using_360 = !using_360; + + if (gAgent.requestPostCapability("InterestList", body, [](const LLSD& response) + { + LL_INFOS("360Capture") << + "InterestList capability responded: \n" << + ll_pretty_print_sd(response) << + LL_ENDL; + })) + { + LL_INFOS("360Capture") << + "Successfully posted an InterestList capability request with payload: \n" << + ll_pretty_print_sd(body) << + LL_ENDL; + return true; + } + else + { + LL_INFOS("360Capture") << + "Unable to post an InterestList capability request with payload: \n" << + ll_pretty_print_sd(body) << + LL_ENDL; + return false; + } + } +}; + class LLAdvancedBuyCurrencyTest : public view_listener_t { bool handleEvent(const LLSD& userdata) @@ -2619,11 +2672,10 @@ class LLAdvancedLeaveAdminStatus : public view_listener_t // Advanced > Debugging // ////////////////////////// - class LLAdvancedForceErrorBreakpoint : public view_listener_t { bool handleEvent(const LLSD& userdata) - { + { force_error_breakpoint(NULL); return true; } @@ -3854,20 +3906,17 @@ bool check_avatar_render_mode(U32 mode) switch (mode) { case 0: -// [RLVa:KB] - Checked: RLVa-2.2 (@setcam_avdist) return FSAvatarRenderPersistence::instance().getAvatarRenderSettings(avatar->getID()) == LLVOAvatar::AV_RENDER_NORMALLY; -// [/RLVa:KB] // return (avatar->getVisualMuteSettings() == LLVOAvatar::AV_RENDER_NORMALLY); case 1: -// [RLVa:KB] - Checked: RLVa-2.2 (@setcam_avdist) return FSAvatarRenderPersistence::instance().getAvatarRenderSettings(avatar->getID()) == LLVOAvatar::AV_DO_NOT_RENDER; -// [/RLVa:KB] // return (avatar->getVisualMuteSettings() == LLVOAvatar::AV_DO_NOT_RENDER); case 2: -// [RLVa:KB] - Checked: RLVa-2.2 (@setcam_avdist) return FSAvatarRenderPersistence::instance().getAvatarRenderSettings(avatar->getID()) == LLVOAvatar::AV_ALWAYS_RENDER; -// [/RLVa:KB] // return (avatar->getVisualMuteSettings() == LLVOAvatar::AV_ALWAYS_RENDER); + case 4: + return FSAvatarRenderPersistence::instance().getAvatarRenderSettings(avatar->getID()) != LLVOAvatar::AV_RENDER_NORMALLY; + // return FSAvatarRenderPersistence::instance().getAvatarRenderSettings(avatar->getID()) == LLVOAvatar::AV_RENDER_NORMALLY; default: return false; } @@ -3895,6 +3944,8 @@ class LLAvatarCheckImpostorMode : public view_listener_t // return (avatar->getVisualMuteSettings() == LLVOAvatar::AV_DO_NOT_RENDER); // case 2: // return (avatar->getVisualMuteSettings() == LLVOAvatar::AV_ALWAYS_RENDER); + // case 4: + // return (avatar->getVisualMuteSettings() != LLVOAvatar::AV_RENDER_NORMALLY); // default: // return false; //} @@ -9029,7 +9080,7 @@ namespace }; } -void queue_actions(LLFloaterScriptQueue* q, const std::string& msg) +bool queue_actions(LLFloaterScriptQueue* q, const std::string& msg) { QueueObjects func(q); LLSelectMgr *mgr = LLSelectMgr::getInstance(); @@ -9051,6 +9102,7 @@ void queue_actions(LLFloaterScriptQueue* q, const std::string& msg) { LL_ERRS() << "Bad logic." << LL_ENDL; } + q->closeFloater(); } else { @@ -9059,6 +9111,7 @@ void queue_actions(LLFloaterScriptQueue* q, const std::string& msg) LL_WARNS() << "Unexpected script compile failure." << LL_ENDL; } } + return !fail; } class LLToolsSelectedScriptAction : public view_listener_t @@ -9107,8 +9160,10 @@ class LLToolsSelectedScriptAction : public view_listener_t //if (queue) //{ // queue->setMono(mono); - // queue_actions(queue, msg); - // queue->setTitle(title); + // if (queue_actions(queue, msg)) + // { + // queue->setTitle(title); + // } //} //else //{ @@ -9182,8 +9237,10 @@ void handle_selected_script_action(const std::string& action) if (queue) { queue->setMono(mono); - queue_actions(queue, msg); - queue->setTitle(title); + if (queue_actions(queue, msg)) + { + queue->setTitle(title); + } } else { @@ -10853,7 +10910,7 @@ class LLEditEnableTakeOff : public view_listener_t bool handleEvent(const LLSD& userdata) { std::string clothing = userdata.asString(); - LLWearableType::EType type = LLWearableType::typeNameToType(clothing); + LLWearableType::EType type = LLWearableType::getInstance()->typeNameToType(clothing); // if (type >= LLWearableType::WT_SHAPE && type < LLWearableType::WT_COUNT) // [RLVa:KB] - Checked: 2010-03-20 (RLVa-1.2.0c) | Modified: RLVa-1.2.0a // NOTE: see below - enable if there is at least one wearable on this type that can be removed @@ -10887,7 +10944,7 @@ class LLEditTakeOff : public view_listener_t LLAppearanceMgr::instance().removeAllClothesFromAvatar(); else { - LLWearableType::EType type = LLWearableType::typeNameToType(clothing); + LLWearableType::EType type = LLWearableType::getInstance()->typeNameToType(clothing); if (type >= LLWearableType::WT_SHAPE && type < LLWearableType::WT_COUNT && (gAgentWearables.getWearableCount(type) > 0)) @@ -11829,6 +11886,7 @@ void initialize_menus() // Advanced > World view_listener_t::addMenu(new LLAdvancedDumpScriptedCamera(), "Advanced.DumpScriptedCamera"); view_listener_t::addMenu(new LLAdvancedDumpRegionObjectCache(), "Advanced.DumpRegionObjectCache"); + view_listener_t::addMenu(new LLAdvancedInterestListFullUpdate(), "Advanced.InterestListFullUpdate"); // Advanced > UI commit.add("Advanced.WebBrowserTest", boost::bind(&handle_web_browser_test, _2)); // sigh! this one opens the MEDIA browser diff --git a/indra/newview/llviewermenufile.cpp b/indra/newview/llviewermenufile.cpp index d8dd0cea82..9cc8e46187 100644 --- a/indra/newview/llviewermenufile.cpp +++ b/indra/newview/llviewermenufile.cpp @@ -683,6 +683,47 @@ class LLFileCloseWindow : public view_listener_t } }; +// FIRE-24125: Add option to close all floaters of a group +class FSFileEnableCloseWindowGroup : public view_listener_t +{ + bool handleEvent(const LLSD& userdata) + { + bool frontmost_fl_exists = (NULL != gFloaterView->getFrontmostClosableFloater()); + bool frontmost_snapshot_fl_exists = (NULL != gSnapshotFloaterView->getFrontmostClosableFloater()); + + return !LLNotificationsUI::LLToast::isAlertToastShown() && (frontmost_fl_exists || frontmost_snapshot_fl_exists); + } +}; + +class FSFileCloseWindowGroup : public view_listener_t +{ + bool handleEvent(const LLSD& userdata) + { + bool frontmost_fl_exists = (NULL != gFloaterView->getFrontmostClosableFloater()); + LLFloater* snapshot_floater = gSnapshotFloaterView->getFrontmostClosableFloater(); + + if (snapshot_floater && (!frontmost_fl_exists || snapshot_floater->hasFocus())) + { + snapshot_floater->closeFloater(); + if (gFocusMgr.getKeyboardFocus() == NULL) + { + gFloaterView->focusFrontFloater(); + } + } + else + { + auto floaterlist = LLFloaterReg::getAllFloatersInGroup(gFloaterView->getFrontmostClosableFloater()); + for (auto floater : floaterlist) + { + floater->closeFloater(); + } + } + if (gMenuHolder) gMenuHolder->hideMenus(); + return true; + } +}; +// + class LLFileEnableCloseAllWindows : public view_listener_t { bool handleEvent(const LLSD& userdata) @@ -1153,5 +1194,10 @@ void init_menu_file() view_listener_t::addEnable(new FSFileEnableImportWindlightBulk(), "File.EnableImportWindlightBulk"); // + // FIRE-24125: Add option to close all floaters of a group + view_listener_t::addCommit(new FSFileCloseWindowGroup(), "File.CloseWindowGroup"); + view_listener_t::addEnable(new FSFileEnableCloseWindowGroup(), "File.EnableCloseWindowGroup"); + // + // "File.SaveTexture" moved to llpanelmaininventory so that it can be properly handled. } diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp index 52540d59b0..37e21bc0ac 100644 --- a/indra/newview/llviewermessage.cpp +++ b/indra/newview/llviewermessage.cpp @@ -38,6 +38,7 @@ #include "llfollowcamparams.h" #include "llinventorydefines.h" #include "lllslconstants.h" +#include "llmaterialtable.h" #include "llregionhandle.h" #include "llsd.h" #include "llsdserialize.h" @@ -4696,6 +4697,7 @@ void process_kill_object(LLMessageSystem *mesgsys, void **user_data) { LLColor4 color(0.f,1.f,0.f,1.f); gPipeline.addDebugBlip(objectp->getPositionAgent(), color); + LL_DEBUGS("MessageBlip") << "Kill blip for local " << local_id << " at " << objectp->getPositionAgent() << LL_ENDL; } // Do the kill @@ -4827,11 +4829,11 @@ void process_sound_trigger(LLMessageSystem *msg, void **) // // NaCl - Antispam Registry - static LLCachedControl _NACL_AntiSpamSoundMulti(gSavedSettings, "_NACL_AntiSpamSoundMulti"); - static LLCachedControl FSPlayCollisionSounds(gSavedSettings, "FSPlayCollisionSounds"); - if (NACLAntiSpamRegistry::instance().isCollisionSound(sound_id)) + static LLCachedControl _NACL_AntiSpamSoundMulti(gSavedSettings, "_NACL_AntiSpamSoundMulti"); + static LLCachedControl EnableCollisionSounds(gSavedSettings, "EnableCollisionSounds"); + if (LLMaterialTable::basic.isCollisionSound(sound_id)) { - if (!FSPlayCollisionSounds) + if (!EnableCollisionSounds) { return; } @@ -4880,28 +4882,32 @@ void process_sound_trigger(LLMessageSystem *msg, void **) { return; } - - // AO: Hack for legacy radar script interface compatibility. Interpret certain + + // Hack for legacy radar script interface compatibility. Interpret certain // sound assets as a request for a full radar update to a channel - if ((owner_id == gAgent.getID()) && (sound_id.asString() == gSavedSettings.getString("RadarLegacyChannelAlertRefreshUUID"))) + if ((owner_id == gAgentID) && (sound_id.asString() == gSavedSettings.getString("RadarLegacyChannelAlertRefreshUUID"))) { - FSRadar* radar = FSRadar::getInstance(); - if (radar) - { - radar->requestRadarChannelAlertSync(); - } + FSRadar::getInstance()->requestRadarChannelAlertSync(); return; } - + // + // Don't play sounds from gestures if they are not enabled. // ...TS: Unless they're your own. if ((!gSavedSettings.getBOOL("EnableGestureSounds")) && (owner_id != gAgent.getID()) && (owner_id == object_id)) return; - // NaCl - Sound Explorer + // NaCl - Antispam Registry + //if (LLMaterialTable::basic.isCollisionSound(sound_id) && !gSavedSettings.getBOOL("EnableCollisionSounds")) + //{ + // return; + //} + // NaCl End + + // NaCl - Sound Explorer gAudiop->triggerSound(sound_id, owner_id, gain, LLAudioEngine::AUDIO_TYPE_SFX, pos_global, object_id); - // NaCl End + // NaCl End } void process_preload_sound(LLMessageSystem *msg, void **user_data) @@ -8133,17 +8139,20 @@ void process_user_info_reply(LLMessageSystem* msg, void**) << "wrong agent id." << LL_ENDL; } - BOOL im_via_email; - msg->getBOOLFast(_PREHASH_UserData, _PREHASH_IMViaEMail, im_via_email); + // Keep this for OpenSim + BOOL im_via_email = FALSE; + if (!LLGridManager::instance().isInSecondLife()) + msg->getBOOLFast(_PREHASH_UserData, _PREHASH_IMViaEMail, im_via_email); + // std::string email; msg->getStringFast(_PREHASH_UserData, _PREHASH_EMail, email); std::string dir_visibility; msg->getString( "UserData", "DirectoryVisibility", dir_visibility); // For Message based user info information the is_verified is assumed to be false. - // Show email address in preferences (FIRE-1071) - //LLFloaterPreference::updateUserInfo(dir_visibility, im_via_email, false); - LLFloaterPreference::updateUserInfo(dir_visibility, im_via_email, !LLGridManager::instance().isInSecondLife(), email); // Assume verified in OpenSim + // Show email address in preferences (FIRE-1071) and keep it for OpenSim + //LLFloaterPreference::updateUserInfo(dir_visibility); + LLFloaterPreference::updateUserInfo(dir_visibility, im_via_email, email); // Assume verified in OpenSim // Show email address in preferences (FIRE-1071) LLFloaterSnapshot::setAgentEmail(email); } diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp index fd388b1435..9da25ecbc2 100644 --- a/indra/newview/llviewerobject.cpp +++ b/indra/newview/llviewerobject.cpp @@ -2489,6 +2489,7 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, color.setVec(1.f, 0.f, 0.f, 1.f); } gPipeline.addDebugBlip(getPositionAgent(), color); + LL_DEBUGS("MessageBlip") << "Update type " << (S32)update_type << " blip for local " << mLocalID << " at " << getPositionAgent() << LL_ENDL; } const F32 MAG_CUTOFF = F_APPROXIMATELY_ZERO; diff --git a/indra/newview/llviewerobject.h b/indra/newview/llviewerobject.h index 6b2d4ed877..2ad2762eed 100644 --- a/indra/newview/llviewerobject.h +++ b/indra/newview/llviewerobject.h @@ -933,6 +933,8 @@ public: LLViewerPartSourceScript* getPartSourceScript() { return mPartSourcep.get(); } bool getPhysicsShapeUnknown () { return mPhysicsShapeUnknown; } // + + bool mCheckRigOnHUD = true; // Warn the user when they wear a rigged item on a HUD attachment point }; /////////////////// diff --git a/indra/newview/llviewerobjectlist.cpp b/indra/newview/llviewerobjectlist.cpp index 0a45c71c97..733fb3c7df 100644 --- a/indra/newview/llviewerobjectlist.cpp +++ b/indra/newview/llviewerobjectlist.cpp @@ -1152,23 +1152,63 @@ void LLViewerObjectList::fetchObjectCosts() // issue http request for stale object physics costs if (!mStaleObjectCost.empty()) { - LLViewerRegion* regionp = gAgent.getRegion(); + // FIRE-5496: Missing LI for objects outside agent's region + //LLViewerRegion* regionp = gAgent.getRegion(); - if (regionp) + //if (regionp) + //{ + // std::string url = regionp->getCapability("GetObjectCost"); + + // if (!url.empty()) + // { + // LLCoros::instance().launch("LLViewerObjectList::fetchObjectCostsCoro", + // boost::bind(&LLViewerObjectList::fetchObjectCostsCoro, this, url)); + // } + // else + // { + // mStaleObjectCost.clear(); + // mPendingObjectCost.clear(); + // } + //} + + std::map regionObjectMap{}; + + // Swap it for thread safety since we're going to iterate over it + uuid_set_t staleObjectCostIds{}; + staleObjectCostIds.swap(mStaleObjectCost); + + for (const auto& staleObjectId : staleObjectCostIds) { - std::string url = regionp->getCapability("GetObjectCost"); + LLViewerObject* staleObject = findObject(staleObjectId); + if (staleObject && staleObject->getRegion()) + { + if (regionObjectMap.find(staleObject->getRegion()) == regionObjectMap.end()) + { + regionObjectMap.insert(std::make_pair(staleObject->getRegion(), uuid_set_t())); + } + + regionObjectMap[staleObject->getRegion()].insert(staleObjectId); + } + } + + for (auto region : regionObjectMap) + { + std::string url = region.first->getCapability("GetObjectCost"); if (!url.empty()) { - LLCoros::instance().launch("LLViewerObjectList::fetchObjectCostsCoro", - boost::bind(&LLViewerObjectList::fetchObjectCostsCoro, this, url)); + LLCoros::instance().launch("LLViewerObjectList::fetchObjectCostsCoro", + boost::bind(&LLViewerObjectList::fetchObjectCostsCoro, this, url, region.second)); } else { - mStaleObjectCost.clear(); - mPendingObjectCost.clear(); + for (const auto& objectId : region.second) + { + mPendingObjectCost.erase(objectId); + } } } + // } } @@ -1183,7 +1223,9 @@ void LLViewerObjectList::reportObjectCostFailure(LLSD &objectList) } -void LLViewerObjectList::fetchObjectCostsCoro(std::string url) +// FIRE-5496: Missing LI for objects outside agent's region +//void LLViewerObjectList::fetchObjectCostsCoro(std::string url) +void LLViewerObjectList::fetchObjectCostsCoro(std::string url, uuid_set_t staleObjects) { LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t @@ -1194,11 +1236,16 @@ void LLViewerObjectList::fetchObjectCostsCoro(std::string url) uuid_set_t diff; - std::set_difference(mStaleObjectCost.begin(), mStaleObjectCost.end(), - mPendingObjectCost.begin(), mPendingObjectCost.end(), - std::inserter(diff, diff.begin())); + // FIRE-5496: Missing LI for objects outside agent's region + //std::set_difference(mStaleObjectCost.begin(), mStaleObjectCost.end(), + // mPendingObjectCost.begin(), mPendingObjectCost.end(), + // std::inserter(diff, diff.begin())); - mStaleObjectCost.clear(); + //mStaleObjectCost.clear(); + std::set_difference(staleObjects.begin(), staleObjects.end(), + mPendingObjectCost.begin(), mPendingObjectCost.end(), + std::inserter(diff, diff.begin())); + // if (diff.empty()) { @@ -1265,7 +1312,7 @@ void LLViewerObjectList::fetchObjectCostsCoro(std::string url) // area search // Update area search to have current information. - FSAreaSearch* area_search_floater = LLFloaterReg::getTypedInstance("area_search"); + FSAreaSearch* area_search_floater = LLFloaterReg::findTypedInstance("area_search"); if (area_search_floater) { area_search_floater->updateObjectCosts(objectId, objectCost, linkCost, physicsCost, linkPhysicsCost); diff --git a/indra/newview/llviewerobjectlist.h b/indra/newview/llviewerobjectlist.h index e295639cbb..7429497363 100644 --- a/indra/newview/llviewerobjectlist.h +++ b/indra/newview/llviewerobjectlist.h @@ -253,7 +253,9 @@ protected: private: static void reportObjectCostFailure(LLSD &objectList); - void fetchObjectCostsCoro(std::string url); + // FIRE-5496: Missing LI for objects outside agent's region + //void fetchObjectCostsCoro(std::string url); + void fetchObjectCostsCoro(std::string url, uuid_set_t staleObjects); static void reportPhysicsFlagFailure(LLSD &obejectList); void fetchPhisicsFlagsCoro(std::string url); diff --git a/indra/newview/llvieweroctree.cpp b/indra/newview/llvieweroctree.cpp index cdfd7c2f04..1dde124a9c 100644 --- a/indra/newview/llvieweroctree.cpp +++ b/indra/newview/llvieweroctree.cpp @@ -1361,6 +1361,7 @@ bool LLViewerOctreeCull::earlyFail(LLViewerOctreeGroup* group) //virtual void LLViewerOctreeCull::traverse(const OctreeNode* n) { + FSZone; LLViewerOctreeGroup* group = (LLViewerOctreeGroup*) n->getListener(0); if (earlyFail(group)) @@ -1371,14 +1372,17 @@ void LLViewerOctreeCull::traverse(const OctreeNode* n) if (mRes == 2 || (mRes && group->hasState(LLViewerOctreeGroup::SKIP_FRUSTUM_CHECK))) { //fully in, just add everything + FSZoneN("AllInside"); OctreeTraveler::traverse(n); } else { + FSZoneN("Check inside?"); mRes = frustumCheck(group); if (mRes) { //at least partially in, run on down + FSZoneN("PartiallyIn"); OctreeTraveler::traverse(n); } diff --git a/indra/newview/llviewerparcelmgr.cpp b/indra/newview/llviewerparcelmgr.cpp index 3423ac0837..125db174f6 100644 --- a/indra/newview/llviewerparcelmgr.cpp +++ b/indra/newview/llviewerparcelmgr.cpp @@ -1973,7 +1973,8 @@ void LLViewerParcelMgr::processParcelProperties(LLMessageSystem *msg, void **use if (parcel) { // Only update stream if parcel changed (recreated) or music is playing (enabled) - if (!agent_parcel_update || gSavedSettings.getBOOL("MediaTentativeAutoPlay")) + static LLCachedControl already_playing(gSavedSettings, "MediaTentativeAutoPlay", true); + if (!agent_parcel_update || already_playing) { LLViewerParcelAskPlay::getInstance()->cancelNotification(); std::string music_url_raw = parcel->getMusicURL(); @@ -1991,7 +1992,7 @@ void LLViewerParcelMgr::processParcelProperties(LLMessageSystem *msg, void **use LLViewerRegion *region = LLWorld::getInstance()->getRegion(msg->getSender()); if (region) { - optionally_start_music(music_url, parcel->mLocalID, region->getRegionID()); + optionallyStartMusic(music_url, parcel->mLocalID, region->getRegionID(), !agent_parcel_update); } } else @@ -2029,9 +2030,13 @@ void LLViewerParcelMgr::onStartMusicResponse(const LLUUID ®ion_id, const S32 LL_INFOS("ParcelMgr") << "Starting parcel music " << url << LL_ENDL; LLViewerAudio::getInstance()->startInternetStreamWithAutoFade(url); } + else + { + LLViewerAudio::getInstance()->startInternetStreamWithAutoFade(LLStringUtil::null); + } } -void LLViewerParcelMgr::optionally_start_music(const std::string &music_url, const S32 &local_id, const LLUUID ®ion_id) +void LLViewerParcelMgr::optionallyStartMusic(const std::string &music_url, const S32 &local_id, const LLUUID ®ion_id, bool switched_parcel) { static LLCachedControl streaming_music(gSavedSettings, "AudioStreamingMusic", true); if (streaming_music) @@ -2042,25 +2047,35 @@ void LLViewerParcelMgr::optionally_start_music(const std::string &music_url, con // was not *explicitly* stopped by the user. (part of SL-4878) // Media/Stream separation //LLPanelNearByMedia* nearby_media_panel = gStatusBar->getNearbyMediaPanel(); + LLViewerAudio* viewer_audio = LLViewerAudio::getInstance(); - //// ask mode //todo constants + // ask mode //todo constants //if (autoplay_mode == 2) //{ - // // stop previous stream - // LLViewerAudio::getInstance()->startInternetStreamWithAutoFade(LLStringUtil::null); - // // if user set media to play - ask // if ((nearby_media_panel && nearby_media_panel->getParcelAudioAutoStart()) // || (!nearby_media_panel && tentative_autoplay)) // { - // LLViewerParcelAskPlay::getInstance()->askToPlay(region_id, - // local_id, - // music_url, - // onStartMusicResponse); + // // user did not stop audio + // if (switched_parcel || music_url != viewer_audio->getNextStreamURI()) + // { + // viewer_audio->startInternetStreamWithAutoFade(LLStringUtil::null); + + // LLViewerParcelAskPlay::getInstance()->askToPlay(region_id, + // local_id, + // music_url, + // onStartMusicResponse); + // } + // // else do nothing: + // // Parcel properties changed, but not url. + // // We are already playing this url and asked about it when agent entered parcel + // // or user started audio manually at some point // } // else // { + // // stopped by the user, do not autoplay // LLViewerParcelAskPlay::getInstance()->cancelNotification(); + // viewer_audio->startInternetStreamWithAutoFade(LLStringUtil::null); // } //} // autoplay @@ -2082,12 +2097,13 @@ void LLViewerParcelMgr::optionally_start_music(const std::string &music_url, con else { LL_INFOS("ParcelMgr") << "Starting parcel music " << music_url << LL_ENDL; - LLViewerAudio::getInstance()->startInternetStreamWithAutoFade(music_url); + viewer_audio->startInternetStreamWithAutoFade(music_url); } } - else + // autoplay off + else if(switched_parcel || music_url != viewer_audio->getNextStreamURI()) { - LLViewerAudio::getInstance()->startInternetStreamWithAutoFade(LLStringUtil::null); + viewer_audio->startInternetStreamWithAutoFade(LLStringUtil::null); } } } diff --git a/indra/newview/llviewerparcelmgr.h b/indra/newview/llviewerparcelmgr.h index 8d58930ef5..aef09cfa96 100644 --- a/indra/newview/llviewerparcelmgr.h +++ b/indra/newview/llviewerparcelmgr.h @@ -285,7 +285,7 @@ public: //void makeLandmarkAtSelection(); static void onStartMusicResponse(const LLUUID ®ion_id, const S32 &parcel_id, const std::string &url, const bool &play); - static void optionally_start_music(const std::string &music_url, const S32 &local_id, const LLUUID ®ion_id); + static void optionallyStartMusic(const std::string &music_url, const S32 &local_id, const LLUUID ®ion_id, bool switched_parcel); static void processParcelOverlay(LLMessageSystem *msg, void **user_data); static void processParcelProperties(LLMessageSystem *msg, void **user_data); diff --git a/indra/newview/llviewerregion.cpp b/indra/newview/llviewerregion.cpp index 77cece4577..00ad76fc31 100644 --- a/indra/newview/llviewerregion.cpp +++ b/indra/newview/llviewerregion.cpp @@ -194,7 +194,7 @@ public: mLandp(NULL) {} - void buildCapabilityNames(LLSD& capabilityNames); + static void buildCapabilityNames(LLSD& capabilityNames); // The surfaces and other layers LLSurface* mLandp; @@ -267,6 +267,12 @@ void LLViewerRegionImpl::requestBaseCapabilitiesCoro(U64 regionHandle) // This loop is used for retrying a capabilities request. do { + if (STATE_WORLD_INIT > LLStartUp::getStartupState()) + { + LL_INFOS("AppInit", "Capabilities") << "Aborting capabilities request, reason: returned to login screen" << LL_ENDL; + return; + } + regionp = LLWorld::getInstance()->getRegionFromHandle(regionHandle); if (!regionp) //region was removed { @@ -315,14 +321,20 @@ void LLViewerRegionImpl::requestBaseCapabilitiesCoro(U64 regionHandle) regionp = NULL; result = httpAdapter->postAndSuspend(httpRequest, url, capabilityNames); - // Fix seed cap retry count - //++mSeedCapAttempts; + if (STATE_WORLD_INIT > LLStartUp::getStartupState()) + { + LL_INFOS("AppInit", "Capabilities") << "Aborting capabilities request, reason: returned to login screen" << LL_ENDL; + return; + } - if (LLApp::isExiting()) + if (LLApp::isExiting() || gDisconnected) { return; } + // Fix seed cap retry count + //++mSeedCapAttempts; + regionp = LLWorld::getInstance()->getRegionFromHandle(regionHandle); if (!regionp) //region was removed { @@ -440,7 +452,7 @@ void LLViewerRegionImpl::requestBaseCapabilitiesCompleteCoro(U64 regionHandle) break; // no retry } - if (LLApp::isExiting()) + if (LLApp::isExiting() || gDisconnected) { break; } @@ -548,7 +560,7 @@ void LLViewerRegionImpl::requestSimulatorFeatureCoro(std::string url, U64 region continue; } - if (LLApp::isExiting()) + if (LLApp::isExiting() || gDisconnected) { break; } @@ -3030,7 +3042,6 @@ void LLViewerRegion::unpackRegionHandshake() mProductName = productName; } - mCentralBakeVersion = region_protocols & 1; // was (S32)gSavedSettings.getBOOL("UseServerTextureBaking"); LLVLComposition *compp = getComposition(); if (compp) @@ -3139,6 +3150,7 @@ void LLViewerRegion::unpackRegionHandshake() mRegionTimer.reset(); //reset region timer. } +// static void LLViewerRegionImpl::buildCapabilityNames(LLSD& capabilityNames) { capabilityNames.append("AbuseCategories"); @@ -3177,6 +3189,8 @@ void LLViewerRegionImpl::buildCapabilityNames(LLSD& capabilityNames) AISAPI::getCapNames(capabilityNames); } // + capabilityNames.append("InterestList"); + capabilityNames.append("GetDisplayNames"); capabilityNames.append("GetExperiences"); capabilityNames.append("AgentExperiences"); diff --git a/indra/newview/llviewershadermgr.cpp b/indra/newview/llviewershadermgr.cpp index 525387af51..6741d75743 100644 --- a/indra/newview/llviewershadermgr.cpp +++ b/indra/newview/llviewershadermgr.cpp @@ -473,8 +473,8 @@ void LLViewerShaderMgr::setShaders() bool canRenderDeferred = LLFeatureManager::getInstance()->isFeatureAvailable("RenderDeferred"); bool hasWindLightShaders = LLFeatureManager::getInstance()->isFeatureAvailable("WindLightUseAtmosShaders"); S32 shadow_detail = gSavedSettings.getS32("RenderShadowDetail"); - bool useRenderDeferred = canRenderDeferred && gSavedSettings.getBOOL("RenderDeferred") && gSavedSettings.getBOOL("RenderAvatarVP"); bool doingWindLight = hasWindLightShaders && gSavedSettings.getBOOL("WindLightUseAtmosShaders"); + bool useRenderDeferred = doingWindLight && canRenderDeferred && gSavedSettings.getBOOL("RenderDeferred") && gSavedSettings.getBOOL("RenderAvatarVP"); //using shaders, disable fixed function LLGLSLShader::sNoFixedFunction = true; diff --git a/indra/newview/llviewertexture.cpp b/indra/newview/llviewertexture.cpp index 9ae5579698..5d0378eb57 100644 --- a/indra/newview/llviewertexture.cpp +++ b/indra/newview/llviewertexture.cpp @@ -3680,11 +3680,22 @@ BOOL LLViewerMediaTexture::findFaces() for(; iter != obj_list->end(); ++iter) { LLVOVolume* obj = *iter; - if(obj->mDrawable.isNull()) - { - ret = FALSE; - continue; - } + if (obj->isDead()) + { + // Isn't supposed to happen, objects are supposed to detach + // themselves on markDead() + // If this happens, viewer is likely to crash + llassert(0); + LL_WARNS() << "Dead object in mMediaImplp's object list" << LL_ENDL; + ret = FALSE; + continue; + } + + if (obj->mDrawable.isNull() || obj->mDrawable->isDead()) + { + ret = FALSE; + continue; + } S32 face_id = -1; S32 num_faces = obj->mDrawable->getNumFaces(); diff --git a/indra/newview/llviewerwearable.cpp b/indra/newview/llviewerwearable.cpp index dfca234f28..b64e251649 100644 --- a/indra/newview/llviewerwearable.cpp +++ b/indra/newview/llviewerwearable.cpp @@ -586,7 +586,7 @@ void LLViewerWearable::saveNewAsset() const void LLViewerWearable::onSaveNewAssetComplete(const LLUUID& new_asset_id, void* userdata, S32 status, LLExtStat ext_status) // StoreAssetData callback (fixed) { LLWearableSaveData* data = (LLWearableSaveData*)userdata; - const std::string& type_name = LLWearableType::getTypeName(data->mType); + const std::string& type_name = LLWearableType::getInstance()->getTypeName(data->mType); if(0 == status) { // Success @@ -612,7 +612,7 @@ void LLViewerWearable::onSaveNewAssetComplete(const LLUUID& new_asset_id, void* std::ostream& operator<<(std::ostream &s, const LLViewerWearable &w) { - s << "wearable " << LLWearableType::getTypeName(w.mType) << "\n"; + s << "wearable " << LLWearableType::getInstance()->getTypeName(w.mType) << "\n"; s << " Name: " << w.mName << "\n"; s << " Desc: " << w.mDescription << "\n"; //w.mPermissions diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp index dab506d650..74506414c9 100644 --- a/indra/newview/llviewerwindow.cpp +++ b/indra/newview/llviewerwindow.cpp @@ -59,7 +59,6 @@ #include "llslurl.h" #include "llrender.h" -#include "llvoiceclient.h" // for push-to-talk button handling #include "stringize.h" // @@ -1158,6 +1157,9 @@ BOOL LLViewerWindow::handleAnyMouseClick(LLWindow *window, LLCoordGL pos, MASK m x = ll_round((F32)x / mDisplayScale.mV[VX]); y = ll_round((F32)y / mDisplayScale.mV[VY]); + // Handle non-consuming global keybindings, like voice + gViewerInput.handleGlobalBindsMouse(clicktype, mask, down); + // only send mouse clicks to UI if UI is visible if(gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI)) { @@ -1678,6 +1680,10 @@ void LLViewerWindow::handleFocusLost(LLWindow *window) BOOL LLViewerWindow::handleTranslatedKeyDown(KEY key, MASK mask, BOOL repeated) { + // Handle non-consuming global keybindings, like voice + // Never affects event processing. + gViewerInput.handleGlobalBindsKeyDown(key, mask); + if (gAwayTimer.getElapsedTimeF32() > LLAgent::MIN_AFK_TIME) { gAgent.clearAFK(); @@ -1702,6 +1708,10 @@ BOOL LLViewerWindow::handleTranslatedKeyDown(KEY key, MASK mask, BOOL repeated) BOOL LLViewerWindow::handleTranslatedKeyUp(KEY key, MASK mask) { + // Handle non-consuming global keybindings, like voice + // Never affects event processing. + gViewerInput.handleGlobalBindsKeyUp(key, mask); + // Let the inspect tool code check for ALT key to set LLToolSelectRect active instead LLToolCamera LLToolCompInspect * tool_inspectp = LLToolCompInspect::getInstance(); if (LLToolMgr::getInstance()->getCurrentTool() == tool_inspectp) @@ -3332,7 +3342,8 @@ BOOL LLViewerWindow::handleKey(KEY key, MASK mask) // ToUnicodeEx changes buffer state on OS below Win10, which is undesirable, // but since we already did a TranslateMessage() in gatherInput(), this // should have no negative effect - int res = ToUnicodeEx(key, 0, keyboard_state, chars, char_count, 1 << 2 /*do not modify buffer flag*/, layout); + // ToUnicodeEx works with virtual key codes + int res = ToUnicodeEx(raw_key, 0, keyboard_state, chars, char_count, 1 << 2 /*do not modify buffer flag*/, layout); if (res == 1 && chars[0] >= 0x20) { // Let it fall through to character handler and get a WM_CHAR. @@ -3809,13 +3820,13 @@ void append_xui_tooltip(LLView* viewp, LLToolTip::Params& params) } } -static LLTrace::BlockTimerStatHandle ftm("Update UI"); +static LLTrace::BlockTimerStatHandle FTM_UPDATE_UI("Update UI"); // rename to sensible symbol // Update UI based on stored mouse position from mouse-move // event processing. void LLViewerWindow::updateUI() { - LL_RECORD_BLOCK_TIME(ftm); + LL_RECORD_BLOCK_TIME(FTM_UPDATE_UI); // rename to sensible symbol static std::string last_handle_msg; @@ -6404,6 +6415,104 @@ BOOL LLViewerWindow::rawSnapshot(LLImageRaw *raw, S32 image_width, S32 image_hei return ret; } +BOOL LLViewerWindow::simpleSnapshot(LLImageRaw* raw, S32 image_width, S32 image_height, const int num_render_passes) +{ + gDisplaySwapBuffers = FALSE; + + glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); + setCursor(UI_CURSOR_WAIT); + + BOOL prev_draw_ui = gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI) ? TRUE : FALSE; + if (prev_draw_ui != false) + { + LLPipeline::toggleRenderDebugFeature(LLPipeline::RENDER_DEBUG_FEATURE_UI); + } + + LLPipeline::sShowHUDAttachments = FALSE; + LLRect window_rect = getWorldViewRectRaw(); + + S32 original_width = LLPipeline::sRenderDeferred ? gPipeline.mDeferredScreen.getWidth() : gViewerWindow->getWorldViewWidthRaw(); + S32 original_height = LLPipeline::sRenderDeferred ? gPipeline.mDeferredScreen.getHeight() : gViewerWindow->getWorldViewHeightRaw(); + + LLRenderTarget scratch_space; + U32 color_fmt = GL_RGBA; + const bool use_depth_buffer = true; + const bool use_stencil_buffer = true; + if (scratch_space.allocate(image_width, image_height, color_fmt, use_depth_buffer, use_stencil_buffer)) + { + if (gPipeline.allocateScreenBuffer(image_width, image_height)) + { + mWorldViewRectRaw.set(0, image_height, image_width, 0); + + scratch_space.bindTarget(); + } + else + { + scratch_space.release(); + gPipeline.allocateScreenBuffer(original_width, original_height); + } + } + + // we render the scene more than once since this helps + // greatly with the objects not being drawn in the + // snapshot when they are drawn in the scene. This is + // evident when you set this value via the debug setting + // called 360CaptureNumRenderPasses to 1. The theory is + // that the missing objects are caused by the sUseOcclusion + // property in pipeline but that the use in pipeline.cpp + // lags by a frame or two so rendering more than once + // appears to help a lot. + for (int i = 0; i < num_render_passes; ++i) + { + // turning this flag off here prohibits the screen swap + // to present the new page to the viewer - this stops + // the black flash in between captures when the number + // of render passes is more than 1. We need to also + // set it here because code in LLViewerDisplay resets + // it to TRUE each time. + gDisplaySwapBuffers = FALSE; + + // actually render the scene + const U32 subfield = 0; + const bool do_rebuild = true; + const F32 zoom = 1.0; + const bool for_snapshot = TRUE; + display(do_rebuild, zoom, subfield, for_snapshot); + } + + glReadPixels( + 0, 0, + image_width, + image_height, + GL_RGB, GL_UNSIGNED_BYTE, + raw->getData() + ); + stop_glerror(); + + gDisplaySwapBuffers = FALSE; + gDepthDirty = TRUE; + + if (!gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI)) + { + if (prev_draw_ui != false) + { + LLPipeline::toggleRenderDebugFeature(LLPipeline::RENDER_DEBUG_FEATURE_UI); + } + } + + LLPipeline::sShowHUDAttachments = TRUE; + + setCursor(UI_CURSOR_ARROW); + + gPipeline.resetDrawOrders(); + mWorldViewRectRaw = window_rect; + scratch_space.flush(); + scratch_space.release(); + gPipeline.allocateScreenBuffer(original_width, original_height); + + return true; +} + void LLViewerWindow::destroyWindow() { if (mWindow) diff --git a/indra/newview/llviewerwindow.h b/indra/newview/llviewerwindow.h index b5e0ed73bb..b63bb55abf 100644 --- a/indra/newview/llviewerwindow.h +++ b/indra/newview/llviewerwindow.h @@ -358,7 +358,10 @@ public: BOOL saveSnapshot(const std::string& filename, S32 image_width, S32 image_height, BOOL show_ui = TRUE, BOOL show_hud = TRUE, BOOL do_rebuild = FALSE, LLSnapshotModel::ESnapshotLayerType type = LLSnapshotModel::SNAPSHOT_TYPE_COLOR, LLSnapshotModel::ESnapshotFormat format = LLSnapshotModel::SNAPSHOT_FORMAT_BMP); BOOL rawSnapshot(LLImageRaw *raw, S32 image_width, S32 image_height, BOOL keep_window_aspect = TRUE, BOOL is_texture = FALSE, BOOL show_ui = TRUE, BOOL show_hud = TRUE, BOOL do_rebuild = FALSE, LLSnapshotModel::ESnapshotLayerType type = LLSnapshotModel::SNAPSHOT_TYPE_COLOR, S32 max_size = MAX_SNAPSHOT_IMAGE_SIZE); - BOOL thumbnailSnapshot(LLImageRaw *raw, S32 preview_width, S32 preview_height, BOOL show_ui, BOOL show_hud, BOOL do_rebuild, LLSnapshotModel::ESnapshotLayerType type); + + BOOL simpleSnapshot(LLImageRaw *raw, S32 image_width, S32 image_height, const int num_render_passes); + + BOOL thumbnailSnapshot(LLImageRaw *raw, S32 preview_width, S32 preview_height, BOOL show_ui, BOOL show_hud, BOOL do_rebuild, LLSnapshotModel::ESnapshotLayerType type); BOOL isSnapshotLocSet() const; void resetSnapshotLoc() const; diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp index f930646d63..6883bdc364 100644 --- a/indra/newview/llvoavatar.cpp +++ b/indra/newview/llvoavatar.cpp @@ -134,6 +134,7 @@ #include "fslslbridge.h" // Movelock position refresh #include "fsdiscordconnect.h" // tapping a place that happens on landing in world to start up discord +#include "fsperfstats.h" // performance stats support extern F32 SPEED_ADJUST_MAX; extern F32 SPEED_ADJUST_MAX_SEC; @@ -601,7 +602,6 @@ bool LLVOAvatar::sLimitNonImpostors = false; // True unless RenderAvatarMaxNonIm F32 LLVOAvatar::sRenderDistance = 256.f; S32 LLVOAvatar::sNumVisibleAvatars = 0; S32 LLVOAvatar::sNumLODChangesThisFrame = 0; - // const LLUUID LLVOAvatar::sStepSoundOnLand("e8af4a28-aa83-4310-a7c4-c047e15ea0df"); - Commented out for FIRE-3169: Option to change the default footsteps sound const LLUUID LLVOAvatar::sStepSounds[LL_MCODE_END] = { @@ -2696,7 +2696,10 @@ void LLVOAvatar::idleUpdate(LLAgent &agent, const F64 &time) LL_INFOS() << "Warning! Idle on dead avatar" << LL_ENDL; return; } - + // record time and refresh "tooSlow" status + FSPerfStats::RecordAvatarTime T(getID(), FSPerfStats::StatType_t::RENDER_IDLE); // per avatar "idle" time. + updateTooSlow(); + // ; // Use LLCachedControl static LLCachedControl disable_all_render_types(gSavedSettings, "DisableAllRenderTypes"); if (!(gPipeline.hasRenderType(mIsControlAvatar ? LLPipeline::RENDER_TYPE_CONTROL_AV : LLPipeline::RENDER_TYPE_AVATAR)) @@ -2704,7 +2707,11 @@ void LLVOAvatar::idleUpdate(LLAgent &agent, const F64 &time) && !(disable_all_render_types) && !isSelf()) // { - return; + if (!mIsControlAvatar) + { + idleUpdateNameTag( mLastRootPos ); + } + return; } // Update should be happening max once per frame. @@ -2736,7 +2743,7 @@ void LLVOAvatar::idleUpdate(LLAgent &agent, const F64 &time) // } - LLScopedContextString str("avatar_idle_update " + getFullname()); + // LLScopedContextString str("avatar_idle_update " + getFullname()); // remove unused scoped string checkTextureLoading() ; @@ -3399,14 +3406,12 @@ void LLVOAvatar::idleUpdateNameTag(const LLVector3& root_pos_last) fRlvShowAvName = (fRlvShowAvTag) && (RlvActions::canShowName(RlvActions::SNC_DEFAULT, getID())); } // [/RLVa:KB] - BOOL visible_avatar = isVisible() || mNeedsAnimUpdate; BOOL visible_chat = useChatBubbles && (mChats.size() || mTyping); BOOL visible_typing = useTypingBubbles && mTyping; BOOL render_name = visible_chat || visible_typing || - (visible_avatar && // [RLVa:KB] - Checked: RLVa-2.0.1 - (fRlvShowAvTag) && + ((fRlvShowAvTag) && // [/RLVa:KB] ((sRenderName == RENDER_NAME_ALWAYS) || (sRenderName == RENDER_NAME_FADE && time_visible < NAME_SHOW_TIME))); @@ -4209,6 +4214,7 @@ void LLVOAvatar::slamPosition() bool LLVOAvatar::isVisuallyMuted() { + FSZone; // Tracy accounting for imposter testing. bool muted = false; // FIRE-11783: Always visually mute avatars that are muted @@ -4225,7 +4231,14 @@ bool LLVOAvatar::isVisuallyMuted() // * check against the render cost and attachment limits if (!isSelf()) { - if (mVisuallyMuteSetting == AV_ALWAYS_RENDER) +// [RLVa:KB] - Checked: RLVa-2.2 (@setcam_avdist) + if (isRlvSilhouette()) + { + muted = true; + } + else if (mVisuallyMuteSetting == AV_ALWAYS_RENDER) +// [/RLVa:KB] +// if (mVisuallyMuteSetting == AV_ALWAYS_RENDER) { muted = false; } @@ -4244,12 +4257,6 @@ bool LLVOAvatar::isVisuallyMuted() // muted = true; //} // -// [RLVa:KB] - Checked: RLVa-2.2 (@setcam_avdist) - else if (isRlvSilhouette()) - { - muted = true; - } -// [/RLVa:KB] else { muted = isTooComplex(); @@ -4261,6 +4268,7 @@ bool LLVOAvatar::isVisuallyMuted() bool LLVOAvatar::isInMuteList() const { + FSZone; // Tracy accounting for imposter testing. bool muted = false; F64 now = LLFrameTimer::getTotalSeconds(); if (now < mCachedMuteListUpdateTime) @@ -4279,9 +4287,9 @@ bool LLVOAvatar::isInMuteList() const } // [RLVa:KB] - Checked: RLVa-2.2 (@setcam_avdist) -bool LLVOAvatar::isRlvSilhouette() +bool LLVOAvatar::isRlvSilhouette() const { - if (!gRlvHandler.hasBehaviour(RLV_BHVR_SETCAM_AVDIST)) + if (!RlvActions::hasBehaviour(RLV_BHVR_SETCAM_AVDIST)) return false; static RlvCachedBehaviourModifier s_nSetCamAvDist(RLV_MODIFIER_SETCAM_AVDIST); @@ -4289,14 +4297,14 @@ bool LLVOAvatar::isRlvSilhouette() const F64 now = LLFrameTimer::getTotalSeconds(); if (now >= mCachedRlvSilhouetteUpdateTime) { - const F64 SECONDS_BETWEEN_NEARBY_UPDATES = .5f; + const F64 SECONDS_BETWEEN_SILHOUETTE_UPDATES = .5f; bool fIsRlvSilhouette = dist_vec_squared(gAgent.getPositionGlobal(), getPositionGlobal()) > s_nSetCamAvDist() * s_nSetCamAvDist(); if (fIsRlvSilhouette != mCachedIsRlvSilhouette) { mCachedIsRlvSilhouette = fIsRlvSilhouette; mNeedsImpostorUpdate = TRUE; } - mCachedRlvSilhouetteUpdateTime = now + SECONDS_BETWEEN_NEARBY_UPDATES; + mCachedRlvSilhouetteUpdateTime = now + SECONDS_BETWEEN_SILHOUETTE_UPDATES; } return mCachedIsRlvSilhouette; } @@ -4694,11 +4702,12 @@ void LLVOAvatar::updateFootstepSounds() void LLVOAvatar::computeUpdatePeriod() { bool visually_muted = isVisuallyMuted(); + bool slow = isTooSlowWithoutShadows();// the geometry alone is forcing this to be slow so we must imposter if (mDrawable.notNull() && isVisible() && (!isSelf() || visually_muted) && !isUIAvatar() - && (sLimitNonImpostors || visually_muted) + && (sLimitNonImpostors || visually_muted || slow) // imposter slow avatars irrespective of nonimposter setting. && !mNeedsAnimUpdate && !sFreezeCounter) { @@ -4710,8 +4719,11 @@ void LLVOAvatar::computeUpdatePeriod() const S32 UPDATE_RATE_SLOW = 64; const S32 UPDATE_RATE_MED = 48; const S32 UPDATE_RATE_FAST = 32; - - if (visually_muted) + if(slow) + { + mUpdatePeriod = UPDATE_RATE_FAST; + } + else if (visually_muted) { // visually muted avatars update at lowest rate mUpdatePeriod = UPDATE_RATE_SLOW; } @@ -5569,6 +5581,7 @@ bool LLVOAvatar::shouldAlphaMask() //----------------------------------------------------------------------------- U32 LLVOAvatar::renderSkinned() { + FSZone; // Tracy accounting for imposter testing. U32 num_indices = 0; if (!mIsBuilt) @@ -5805,6 +5818,7 @@ U32 LLVOAvatar::renderSkinned() U32 LLVOAvatar::renderTransparent(BOOL first_pass) { + FSZone; // Tracy accounting for render tracking U32 num_indices = 0; if( isWearingWearableType( LLWearableType::WT_SKIRT ) && (isUIAvatar() || isTextureVisible(TEX_SKIRT_BAKED)) ) { @@ -5857,6 +5871,7 @@ U32 LLVOAvatar::renderTransparent(BOOL first_pass) //----------------------------------------------------------------------------- U32 LLVOAvatar::renderRigid() { + FSZone; // Tracy accounting for render tracking U32 num_indices = 0; if (!mIsBuilt) @@ -5906,6 +5921,7 @@ U32 LLVOAvatar::renderRigid() U32 LLVOAvatar::renderImpostor(LLColor4U color, S32 diffuse_channel) { + FSZone; // Tracy accounting for render tracking if (!mImpostor.isComplete()) { return 0; @@ -6921,6 +6937,7 @@ const LLUUID& LLVOAvatar::getID() const LLJoint *LLVOAvatar::getJoint( const JointKey &name ) // { + FSZone; // Query by JointKey rather than just a string, the key can be a U32 index for faster lookup //joint_map_t::iterator iter = mJointMap.find( name ); @@ -9116,6 +9133,95 @@ BOOL LLVOAvatar::isFullyLoaded() const // return (mRenderUnloadedAvatar || mFullyLoaded); } +// use Avatar Render Time as complexity metric +// markARTStale - Mark stale and set the frameupdate to now so that we can wait at least one frame to get a revised number. +void LLVOAvatar::markARTStale() +{ + mARTStale=true; + mLastARTUpdateFrame = LLFrameTimer::getFrameCount(); +} + +// Udpate Avatar state based on render time +void LLVOAvatar::updateTooSlow() +{ + FSZone; + static LLCachedControl alwaysRenderFriends(gSavedSettings, "AlwaysRenderFriends"); + static LLCachedControl allowSelfImpostor(gSavedSettings, "FSAllowSelfImpostor"); + const auto id = getID(); + + // mTooSlow - Is the avatar flagged as being slow (includes shadow time) + // mTooSlowWithoutShadows - Is the avatar flagged as being slow even with shadows removed. + // mARTStale - the rendertime we have is stale because of an update. We need to force a re-render to re-assess slowness + + if( mARTStale ) + { + if ( LLFrameTimer::getFrameCount() - mLastARTUpdateFrame < 5 ) + { + // LL_INFOS() << this->getFullname() << " marked stale " << LL_ENDL; + // we've not had a chance to update yet (allow a few to be certain a full frame has passed) + return; + } + + mARTStale = false; + mTooSlow = false; + mTooSlowWithoutShadows = false; + // LL_INFOS() << this->getFullname() << " refreshed ART combined = " << mRenderTime << " @ " << mLastARTUpdateFrame << LL_ENDL; + } + + // Either we're not stale or we've updated. + + U64 render_time_raw; + U64 render_geom_time_raw; + + if( !mTooSlow ) + { + // we are fully rendered, so we use the live values + std::lock_guard lock{FSPerfStats::bufferToggleLock}; + render_time_raw = FSPerfStats::StatsRecorder::get(FSPerfStats::ObjType_t::OT_AVATAR, id, FSPerfStats::StatType_t::RENDER_COMBINED); + render_geom_time_raw = FSPerfStats::StatsRecorder::get(FSPerfStats::ObjType_t::OT_AVATAR, id, FSPerfStats::StatType_t::RENDER_GEOMETRY); + } + else + { + // use the cached values. + render_time_raw = mRenderTime; + render_geom_time_raw = mGeomTime; + } + if( (FSPerfStats::renderAvatarMaxART_ns > 0) && + (FSPerfStats::raw_to_ns(render_time_raw) >= FSPerfStats::renderAvatarMaxART_ns) ) + { + if( !mTooSlow ) // if we were previously not slow (with or without shadows.) + { + // if we weren't capped, we are now + mLastARTUpdateFrame = LLFrameTimer::getFrameCount(); + mRenderTime = render_time_raw; + mGeomTime = render_geom_time_raw; + mARTStale = false; + mTooSlow = true; + } + if(!mTooSlowWithoutShadows) // if we were not previously above the full impostor cap + { + bool render_friend_or_exception = ( alwaysRenderFriends && LLAvatarTracker::instance().isBuddy( id ) ) || + ( getVisualMuteSettings() == LLVOAvatar::AV_ALWAYS_RENDER ); + if( (!isSelf() || allowSelfImpostor) && !render_friend_or_exception ) + { + // Note: slow rendering Friends still get their shadows zapped. + mTooSlowWithoutShadows = (FSPerfStats::raw_to_ns(render_geom_time_raw) >= FSPerfStats::renderAvatarMaxART_ns); + } + } + } + else + { + // LL_INFOS() << this->getFullname() << " ("<< (combined?"combined":"geometry") << ") good render time = " << FSPerfStats::raw_to_ns(render_time_raw) << " vs ("<< LLVOAvatar::sRenderTimeCap_ns << " set @ " << mLastARTUpdateFrame << LL_ENDL; + mTooSlow = false; + mTooSlowWithoutShadows = false; + } + if(mTooSlow) + { + FSPerfStats::tunedAvatars++; // increment the number of avatars that have been tweaked. + } +} +// + bool LLVOAvatar::isTooComplex() const { bool too_complex; @@ -9918,7 +10024,7 @@ void dump_visual_param(LLAPRFile::tFiletype* file, LLVisualParam* viewer_param, S32 u8_value = F32_to_U8(value,viewer_param->getMinWeight(),viewer_param->getMaxWeight()); apr_file_printf(file, "\t\t\n", viewer_param->getID(), viewer_param->getName().c_str(), viewer_param->getDisplayName().c_str(), value, u8_value, type_string.c_str(), - LLWearableType::getTypeName(LLWearableType::EType(wtype)).c_str(), + LLWearableType::getInstance()->getTypeName(LLWearableType::EType(wtype)).c_str(), viewer_param->getGroup()); } @@ -10130,7 +10236,6 @@ void LLVOAvatar::processAvatarAppearance( LLMessageSystem* mesgsys ) //bool enable_verbose_dumps = gSavedSettings.getBOOL("DebugAvatarAppearanceMessage"); static LLCachedControl enable_verbose_dumps(gSavedSettings, "DebugAvatarAppearanceMessage"); // - std::string dump_prefix = getFullname() + "_" + (isSelf()?"s":"o") + "_"; if (gSavedSettings.getBOOL("BlockAvatarAppearanceMessages")) { LL_WARNS() << "Blocking AvatarAppearance message" << LL_ENDL; @@ -10143,6 +10248,7 @@ void LLVOAvatar::processAvatarAppearance( LLMessageSystem* mesgsys ) parseAppearanceMessage(mesgsys, *contents); if (enable_verbose_dumps) { + std::string dump_prefix = getFullname() + "_" + (isSelf()?"s":"o") + "_"; dumpAppearanceMsgParams(dump_prefix + "appearance_msg", *contents); } @@ -10257,13 +10363,13 @@ void LLVOAvatar::applyParsedAppearanceMessage(LLAppearanceMessageContents& conte { //Wolfspirit: Read the UUID, system and Texturecolor const LLTEContents& tec = contents.mTEContents; - const LLUUID tag_uuid = ((LLUUID*)tec.image_data)[TEX_HEAD_BODYPAINT]; + const LLUUID tag_uuid = tec.image_data[TEX_HEAD_BODYPAINT]; bool new_system = (tec.glow[TEX_HEAD_BODYPAINT]); //WS: Write them into an LLSD map mClientTagData["uuid"] = tag_uuid.asString(); mClientTagData["id_based"] = new_system; - mClientTagData["tex_color"] = LLColor4U(tec.colors).getValue(); + mClientTagData["tex_color"] = tec.colors[TEX_HEAD_BODYPAINT].getValue(); //WS: Clear mNameString to force a rebuild mNameIsSet = false; @@ -10424,7 +10530,6 @@ void LLVOAvatar::applyParsedAppearanceMessage(LLAppearanceMessageContents& conte updateMeshTextures(); updateMeshVisibility(); - } LLViewerTexture* LLVOAvatar::getBakedTexture(const U8 te) @@ -10782,6 +10887,7 @@ void LLVOAvatar::dumpArchetypeXMLCallback(const std::vector& filena { // LLAPRFile outfile; + LLWearableType *wr_inst = LLWearableType::getInstance(); // FIRE-8893 - Dump archetype xml to user defined location //std::string fullpath = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,outfilename); std::string fullpath = filenames[0]; @@ -10805,7 +10911,7 @@ void LLVOAvatar::dumpArchetypeXMLCallback(const std::vector& filena { for (S32 type = LLWearableType::WT_SHAPE; type < LLWearableType::WT_COUNT; type++) { - const std::string& wearable_name = LLWearableType::getTypeName((LLWearableType::EType)type); + const std::string& wearable_name = wr_inst->getTypeName((LLWearableType::EType)type); apr_file_printf( file, "\n\t\t\n", wearable_name.c_str() ); for (LLVisualParam* param = getFirstVisualParam(); param; param = getNextVisualParam()) @@ -11407,7 +11513,14 @@ void LLVOAvatar::updateImpostors() // virtual BOOL LLVOAvatar::isImpostor() { - return isVisuallyMuted() || (sLimitNonImpostors && (mUpdatePeriod > 1)); +// render time handling using tooSlow() +// return isVisuallyMuted() || (sLimitNonImpostors && (mUpdatePeriod > 1)); + return ( + isVisuallyMuted() || + isTooSlowWithoutShadows() || + (sLimitNonImpostors && (mUpdatePeriod > 1) ) + ); +// } BOOL LLVOAvatar::shouldImpostor(const F32 rank_factor) @@ -11420,6 +11533,15 @@ BOOL LLVOAvatar::shouldImpostor(const F32 rank_factor) { return true; } +// render time handling using tooSlow() + // return sLimitNonImpostors && (mVisibilityRank > sMaxNonImpostors * rank_factor); + // static LLCachedControl render_jellys_As_imposters(gSavedSettings, "RenderJellyDollsAsImpostors"); + + if (isTooSlowWithoutShadows()) + { + return true; + } +// return sLimitNonImpostors && (mVisibilityRank > sMaxNonImpostors * rank_factor); } @@ -11595,6 +11717,7 @@ void LLVOAvatar::updateVisualComplexity() LL_DEBUGS("AvatarRender") << "avatar " << getID() << " appearance changed" << LL_ENDL; // Set the cache time to in the past so it's updated ASAP mVisualComplexityStale = true; + markARTStale(); } // Account for the complexity of a single top-level object associated @@ -11606,6 +11729,7 @@ void LLVOAvatar::accountRenderComplexityForObject( LLVOVolume::texture_cost_t& textures, U32& cost, hud_complexity_list_t& hud_complexity_list, + object_complexity_list_t& object_complexity_list, // Show per-item complexity in COF std::map& item_complexity, std::map& temp_item_complexity) @@ -11628,12 +11752,12 @@ void LLVOAvatar::accountRenderComplexityForObject( F32 attachment_volume_cost = 0; F32 attachment_texture_cost = 0; F32 attachment_children_cost = 0; - const F32 animated_object_attachment_surcharge = 1000; + const F32 animated_object_attachment_surcharge = 1000; - if (attached_object->isAnimatedObject()) - { - attachment_volume_cost += animated_object_attachment_surcharge; - } + if (attached_object->isAnimatedObject()) + { + attachment_volume_cost += animated_object_attachment_surcharge; + } attachment_volume_cost += volume->getRenderCost(textures); const_child_list_t children = volume->getChildren(); @@ -11668,6 +11792,15 @@ void LLVOAvatar::accountRenderComplexityForObject( // Limit attachment complexity to avoid signed integer flipping of the wearer's ACI cost += (U32)llclamp(attachment_total_cost, MIN_ATTACHMENT_COMPLEXITY, max_attachment_complexity); + if (isSelf()) + { + LLObjectComplexity object_complexity; + object_complexity.objectName = attached_object->getAttachmentItemName(); + object_complexity.objectId = attached_object->getAttachmentItemID(); + object_complexity.objectCost = attachment_total_cost; + object_complexity_list.push_back(object_complexity); + } + // Show per-item complexity in COF if (isSelf()) { @@ -11679,8 +11812,8 @@ void LLVOAvatar::accountRenderComplexityForObject( { temp_item_complexity.insert(std::make_pair(attached_object->getID(), (U32)attachment_total_cost)); } - } // + } } } } @@ -11775,6 +11908,8 @@ void LLVOAvatar::calculateUpdateRenderComplexity() U32 cost = VISUAL_COMPLEXITY_UNKNOWN; LLVOVolume::texture_cost_t textures; hud_complexity_list_t hud_complexity_list; + object_complexity_list_t object_complexity_list; + // BOM constrain number of bake requests when BOM not supported // for (U8 baked_index = 0; baked_index < BAKED_NUM_INDICES; baked_index++) for (U8 baked_index = 0; baked_index < getNumBakes(); baked_index++) @@ -11822,8 +11957,8 @@ void LLVOAvatar::calculateUpdateRenderComplexity() { accountRenderComplexityForObject(volp, max_attachment_complexity, // Show per-item complexity in COF - //textures, cost, hud_complexity_list); - textures, cost, hud_complexity_list, item_complexity, temp_item_complexity); + //textures, cost, hud_complexity_list, object_complexity_list); + textures, cost, hud_complexity_list, object_complexity_list, item_complexity, temp_item_complexity); // } } @@ -11849,9 +11984,61 @@ void LLVOAvatar::calculateUpdateRenderComplexity() const LLViewerObject* attached_object = attachment_iter->get(); accountRenderComplexityForObject(attached_object, max_attachment_complexity, // Show per-item complexity in COF - //textures, cost, hud_complexity_list); - textures, cost, hud_complexity_list, item_complexity, temp_item_complexity); + //textures, cost, hud_complexity_list, object_complexity_list); + textures, cost, hud_complexity_list, object_complexity_list, item_complexity, temp_item_complexity); // + + // FIRE-31330: Check if this attachment is on the HUD and contains rigged mesh. + // No need for isSelf() as HUD attachments always are owned by us. + // NOTE: This function should be revised once we have better information + // about pending/loaded rigging data and moved to a more appropriate + // place in the code. For now, this is a good spot as the complexity calculation + // gets updated when rigging data arrives, so we can reliably identify rigged + // attachments where the skinning information took a while to load. + if (attached_object->isHUDAttachment() && attached_object->mCheckRigOnHUD) + { + // check if the root object is rigged + bool is_rigged = attached_object->isRiggedMesh(); + + // if not, check if any of its children is rigged + if (!is_rigged) + { + LLViewerObject::const_child_list_t& child_list = attached_object->getChildren(); + for (auto childp : child_list) + { + if (childp && childp->isRiggedMesh()) + { + is_rigged = true; + break; + } + } + } + + // if it is rigged, display the warning dialog once per object + if (is_rigged) + { + // can't use attached_object as it is const, so grab it from the iterator instead + attachment_iter->get()->mCheckRigOnHUD = false; + + LLSD args; + + LLViewerInventoryItem* inv_object = gInventory.getItem(attached_object->getAttachmentItemID()); + + if (inv_object) + { + args["NAME"] = inv_object->getName(); + } + else + { + args["NAME"] = LLTrans::getString("Unknown"); + } + + // can't use attached_object as it is const, so grab it from the iterator instead + args["HUD_POINT"] = LLTrans::getString(getTargetAttachmentPoint(attachment_iter->get())->getName()); + LLNotificationsUtil::add("AttachedRiggedObjectToHUD", args); + } + } + // } } @@ -11912,13 +12099,13 @@ void LLVOAvatar::calculateUpdateRenderComplexity() mVisualComplexity = cost; mVisualComplexityStale = false; - static LLCachedControl show_my_complexity_changes(gSavedSettings, "ShowMyComplexityChanges", 20); - - if (isSelf() && show_my_complexity_changes) + if (isSelf()) { // Avatar complexity LLAvatarRenderNotifier::getInstance()->updateNotificationAgent(mVisualComplexity); + LLAvatarRenderNotifier::getInstance()->setObjectComplexityList(object_complexity_list); + // HUD complexity LLHUDRenderNotifier::getInstance()->updateNotificationHUD(hud_complexity_list); } @@ -11937,6 +12124,7 @@ void LLVOAvatar::setVisualMuteSettings(VisualMuteSettings set) mVisuallyMuteSetting = set; mNeedsImpostorUpdate = TRUE; mLastImpostorUpdateReason = 7; + markARTStale();// Force a refresh of the ART to take into account new setting. // [FS Persisted Avatar Render Settings] //LLRenderMuteList::getInstance()->saveVisualMuteSetting(getID(), S32(set)); @@ -12089,7 +12277,7 @@ LLVOAvatar::AvatarOverallAppearance LLVOAvatar::getOverallAppearance() const } else // !isSelf() { - if (isInMuteList()) + if (isInMuteList()) { result = AOA_INVISIBLE; } @@ -12116,23 +12304,19 @@ void LLVOAvatar::calcMutedAVColor() std::string change_msg; LLUUID av_id(getID()); - if (getVisualMuteSettings() == AV_DO_NOT_RENDER) +// [RLVa:KB] - Checked: RLVa-2.2 (@setcam_avdist) + if (isRlvSilhouette()) + { + new_color = LLColor4::silhouette; + change_msg = " not rendered: color is silhouette"; + } + else if (getVisualMuteSettings() == AV_DO_NOT_RENDER) +// [/RLVa:KB] +// if (getVisualMuteSettings() == AV_DO_NOT_RENDER) { -// [RLVa:KB] - Checked: RLVa-2.2 (@setcam_avdist) - if (isRlvSilhouette()) - { - new_color = LLColor4::silhouette; - change_msg = " not rendered: color is silhouette"; - } - else - { -// [/RLVa:KB] - // explicitly not-rendered avatars are light grey - new_color = LLColor4::grey4; - change_msg = " not rendered: color is grey4"; -// [RLVa:KB] - Checked: RLVa-2.2 (@setcam_avdist) - } -// [/RLVa:KB] + // explicitly not-rendered avatars are light grey + new_color = LLColor4::grey4; + change_msg = " not rendered: color is grey4"; } else if (LLMuteList::getInstance()->isMuted(av_id)) // the user blocked them { @@ -12146,14 +12330,8 @@ void LLVOAvatar::calcMutedAVColor() change_msg = " simple imposter "; } #ifdef COLORIZE_JELLYDOLLS -// else if ( mMutedAVColor == LLColor4::white || mMutedAVColor == LLColor4::grey3 || mMutedAVColor == LLColor4::grey4 ) -// [RLVa:KB] - Checked: RLVa-2.2 (@setcam_avdist) - else if ( mMutedAVColor == LLColor4::white || mMutedAVColor == LLColor4::grey3 || mMutedAVColor == LLColor4::grey4 || mMutedAVColor == LLColor4::silhouette) -#else - else if (mMutedAVColor == LLColor4::silhouette) -#endif -// [/RLVa:KB] - { + else if ( mMutedAVColor == LLColor4::white || mMutedAVColor == LLColor4::grey3 || mMutedAVColor == LLColor4::grey4 ) + { // select a color based on the first byte of the agents uuid so any muted agent is always the same color F32 color_value = (F32) (av_id.mData[0]); F32 spectrum = (color_value / 256.0); // spectrum is between 0 and 1.f @@ -12172,8 +12350,7 @@ void LLVOAvatar::calcMutedAVColor() new_color.normalize(); new_color *= 0.28f; // Tone it down } -// RLVa fix -//#endif +#endif else { new_color = LLColor4::grey4; diff --git a/indra/newview/llvoavatar.h b/indra/newview/llvoavatar.h index 078473be92..ccbd1eb7c6 100644 --- a/indra/newview/llvoavatar.h +++ b/indra/newview/llvoavatar.h @@ -311,6 +311,7 @@ public: LLVOVolume::texture_cost_t& textures, U32& cost, hud_complexity_list_t& hud_complexity_list, + object_complexity_list_t& object_complexity_list, // Show per-item complexity in COF std::map& item_complexity, std::map& temp_item_complexity); @@ -354,6 +355,7 @@ public: static F32 sPhysicsLODFactor; // user-settable physics LOD factor static BOOL sJointDebug; // output total number of joints being touched for each avatar static BOOL sDebugAvatarRotation; + static U64 sRenderTimeLimit_ns; // nanosecond time limit for avatar rendering 0 is unlimited. static LLPartSysData sCloud; //-------------------------------------------------------------------- @@ -367,6 +369,17 @@ public: //-------------------------------------------------------------------- public: BOOL isFullyLoaded() const; + // check and return current state relative to limits + // default will test only the geometry (combined=false). + // this allows us to disable shadows separately on complex avatars. + inline bool isTooSlowWithShadows() const {return mTooSlow;}; + inline bool isTooSlowWithoutShadows() const {return mTooSlowWithoutShadows;}; + inline bool isTooSlow(bool combined = false) const + { + return(combined?mTooSlow:mTooSlowWithoutShadows); + } + void updateTooSlow(); + // virtual bool isTooComplex() const; // FIRE-29012: Standalone animesh avatars get affected by complexity limit; changed to virtual bool visualParamWeightsAreDefault(); virtual bool getIsCloud() const; @@ -388,6 +401,7 @@ public: void logMetricsTimerRecord(const std::string& phase_name, F32 elapsed, bool completed); void calcMutedAVColor(); + void markARTStale(); protected: LLViewerStats::PhaseMap& getPhases() { return mPhases; } @@ -405,6 +419,15 @@ private: LLColor4 mMutedAVColor; LLFrameTimer mFullyLoadedTimer; LLFrameTimer mRuthTimer; + U32 mLastARTUpdateFrame{0}; + U64 mRenderTime{0}; + U64 mGeomTime{0}; + bool mARTStale{true}; + bool mARTCapped{false}; + // variables to hold "slowness" status + bool mTooSlow{false}; + bool mTooSlowWithoutShadows{false}; + // private: LLViewerStats::PhaseMap mPhases; @@ -456,7 +479,7 @@ public: bool isVisuallyMuted(); bool isInMuteList() const; // [RLVa:KB] - Checked: RLVa-2.2 (@setcam_avdist) - bool isRlvSilhouette(); + bool isRlvSilhouette() const; // [/RLVa:KB] void forceUpdateVisualMuteSettings(); @@ -472,10 +495,7 @@ public: void setVisualMuteSettings(VisualMuteSettings set); protected: // If you think you need to access this outside LLVOAvatar, you probably want getOverallAppearance() -// [RLVa:KB] - Checked: RLVa-2.2 (@setcam_avdist) - VisualMuteSettings getVisualMuteSettings() { return (!isRlvSilhouette()) ? mVisuallyMuteSetting : AV_DO_NOT_RENDER; }; -// [/RLVa:KB] -// VisualMuteSettings getVisualMuteSettings() { return mVisuallyMuteSetting; }; + VisualMuteSettings getVisualMuteSettings() { return mVisuallyMuteSetting; }; public: @@ -535,8 +555,8 @@ private: mutable bool mCachedInMuteList; mutable F64 mCachedMuteListUpdateTime; // [RLVa:KB] - Checked: RLVa-2.2 (@setcam_avdist) - mutable bool mCachedIsRlvSilhouette = false; - mutable F64 mCachedRlvSilhouetteUpdateTime = 0.f; + mutable bool mCachedIsRlvSilhouette = false; + mutable F64 mCachedRlvSilhouetteUpdateTime = 0.f; // [/RLVa:KB] VisualMuteSettings mVisuallyMuteSetting; // Always or never visually mute this AV @@ -600,7 +620,10 @@ public: static void resetImpostors(); static void updateImpostors(); LLRenderTarget mImpostor; - BOOL mNeedsImpostorUpdate; +// [RLVa:KB] - Checked: RLVa-2.4 (@setcam_avdist) + mutable BOOL mNeedsImpostorUpdate; +// [/RLVa:KB] +// BOOL mNeedsImpostorUpdate; S32 mLastImpostorUpdateReason; F32SecondsImplicit mLastImpostorUpdateFrameTime; const LLVector3* getLastAnimExtents() const { return mLastAnimExtents; } @@ -1188,6 +1211,8 @@ public: // COF version of last appearance message received for this av. S32 mLastUpdateReceivedCOFVersion; + U64 getLastART() const { return mRenderTime; } + /** Diagnostics ** ** *******************************************************************************/ diff --git a/indra/newview/llvoavatarself.cpp b/indra/newview/llvoavatarself.cpp index 113e6a053d..422f130057 100644 --- a/indra/newview/llvoavatarself.cpp +++ b/indra/newview/llvoavatarself.cpp @@ -2603,6 +2603,7 @@ void LLVOAvatarSelf::debugBakedTextureUpload(EBakedTextureIndex index, BOOL fini const std::string LLVOAvatarSelf::verboseDebugDumpLocalTextureDataInfo(const LLViewerTexLayerSet* layerset) const { std::ostringstream outbuf; + LLWearableType *wr_inst = LLWearableType::getInstance(); for (LLAvatarAppearanceDictionary::BakedTextures::const_iterator baked_iter = sAvatarDictionary->getBakedTextures().begin(); baked_iter != sAvatarDictionary->getBakedTextures().end(); @@ -2626,7 +2627,7 @@ const std::string LLVOAvatarSelf::verboseDebugDumpLocalTextureDataInfo(const LLV { for (U32 wearable_index = 0; wearable_index < wearable_count; wearable_index++) { - outbuf << " " << LLWearableType::getTypeName(wearable_type) << " " << wearable_index << ":"; + outbuf << " " << wr_inst->getTypeName(wearable_type) << " " << wearable_index << ":"; const LLLocalTextureObject *local_tex_obj = getLocalTextureObject(tex_index, wearable_index); if (local_tex_obj) { @@ -2681,6 +2682,7 @@ void LLVOAvatarSelf::dumpAllTextures() const const std::string LLVOAvatarSelf::debugDumpLocalTextureDataInfo(const LLViewerTexLayerSet* layerset) const { std::string text=""; + LLWearableType *wr_inst = LLWearableType::getInstance(); text = llformat("[Final:%d Avail:%d] ",isLocalTextureDataFinal(layerset), isLocalTextureDataAvailable(layerset)); @@ -2704,7 +2706,7 @@ const std::string LLVOAvatarSelf::debugDumpLocalTextureDataInfo(const LLViewerTe const U32 wearable_count = gAgentWearables.getWearableCount(wearable_type); if (wearable_count > 0) { - text += LLWearableType::getTypeName(wearable_type) + ":"; + text += wr_inst->getTypeName(wearable_type) + ":"; for (U32 wearable_index = 0; wearable_index < wearable_count; wearable_index++) { const U32 discard_level = getLocalDiscardLevel(tex_index, wearable_index); @@ -3471,9 +3473,10 @@ void LLVOAvatarSelf::dumpWearableInfo(LLAPRFile& outfile) apr_file_printf( file, "\n\n" ); LLWearableData *wd = getWearableData(); + LLWearableType *wr_inst = LLWearableType::getInstance(); for (S32 type = 0; type < LLWearableType::WT_COUNT; type++) { - const std::string& type_name = LLWearableType::getTypeName((LLWearableType::EType)type); + const std::string& type_name = wr_inst->getTypeName((LLWearableType::EType)type); for (U32 j=0; j< wd->getWearableCount((LLWearableType::EType)type); j++) { LLViewerWearable *wearable = gAgentWearables.getViewerWearable((LLWearableType::EType)type,j); diff --git a/indra/newview/llvoicevivox.cpp b/indra/newview/llvoicevivox.cpp index 746ddfdb02..0591fd898d 100644 --- a/indra/newview/llvoicevivox.cpp +++ b/indra/newview/llvoicevivox.cpp @@ -401,6 +401,11 @@ void LLVivoxVoiceClient::init(LLPumpIO *pump) void LLVivoxVoiceClient::terminate() { + if (sShuttingDown) + { + return; + } + // needs to be done manually here since we will not get another pass in // coroutines... that mechanism is long since gone. if (mIsLoggedIn) @@ -520,20 +525,29 @@ bool LLVivoxVoiceClient::writeString(const std::string &str) // On Linux the viewer can run SLVoice.exe through wine (https://www.winehq.org/) // Vivox does not support Linux anymore and the SDK SLVoice for Linux uses is old and according to LL // will stop working 'soon' (as of 2016-07-17). See also FIRE-19663 -bool viewerUsesWineForVoice() + +enum class EWineMode{ eNoWine, e32Bit, e64Bit }; +EWineMode viewerUsesWineForVoice() { #ifndef LL_LINUX - return false; + return EWineMode::eNoWine; #else - static LLCachedControl sEnableVoiceChat(gSavedSettings, "FSLinuxEnableWin32VoiceProxy" ); + static LLCachedControl sEnable32BitVoiceChat(gSavedSettings, "FSLinuxEnableWin32VoiceProxy" ); + static LLCachedControl sEnable64BitVoiceChat(gSavedSettings, "FSLinuxEnableWin64VoiceProxy" ); - return sEnableVoiceChat; + if( sEnable64BitVoiceChat ) + return EWineMode::e64Bit; + if( sEnable32BitVoiceChat ) + return EWineMode::e32Bit; + + + return EWineMode::eNoWine; #endif } bool viewerChoosesConnectionHandles() { - return viewerUsesWineForVoice(); + return viewerUsesWineForVoice() != EWineMode::eNoWine; } // @@ -709,7 +723,47 @@ void LLVivoxVoiceClient::idle(void* user_data) // of a coroutine. // // + +typedef enum e_voice_control_coro_state +{ + VOICE_STATE_ERROR = -1, + VOICE_STATE_DONE = 0, + VOICE_STATE_TP_WAIT, // entry point + VOICE_STATE_START_DAEMON, + VOICE_STATE_PROVISION_ACCOUNT, + VOICE_STATE_START_SESSION, + VOICE_STATE_SESSION_RETRY, + VOICE_STATE_SESSION_ESTABLISHED, + VOICE_STATE_WAIT_FOR_CHANNEL, + VOICE_STATE_DISCONNECT, + VOICE_STATE_WAIT_FOR_EXIT, +} EVoiceControlCoroState; + void LLVivoxVoiceClient::voiceControlCoro() +{ + int state = 0; + try + { + // state is passed as a reference instead of being + // a member due to unresolved issues with coroutine + // surviving longer than LLVivoxVoiceClient + voiceControlStateMachine(state); + } + catch (const LLContinueError&) + { + LOG_UNHANDLED_EXCEPTION("LLVivoxVoiceClient"); + } + catch (...) + { + // Ideally for Windows need to log SEH exception instead or to set SEH + // handlers but bugsplat shows local variables for windows, which should + // be enough + LL_WARNS("Voice") << "voiceControlStateMachine crashed in state " << state << LL_ENDL; + throw; + } +} + +void LLVivoxVoiceClient::voiceControlStateMachine(S32 &coro_state) { LL_DEBUGS("Voice") << "starting" << LL_ENDL; mIsCoroutineActive = true; @@ -717,114 +771,159 @@ void LLVivoxVoiceClient::voiceControlCoro() U32 retry = 0; - while (gAgent.getTeleportState() != LLAgent::TELEPORT_NONE && !sShuttingDown) - { - LL_DEBUGS("Voice") << "Suspending voiceControlCoro() momentarily for teleport. Tuning: " << mTuningMode << ". Relog: " << mRelogRequested << LL_ENDL; - llcoro::suspendUntilTimeout(1.0); - } - - if (sShuttingDown) - { - mIsCoroutineActive = false; - return; - } + coro_state = VOICE_STATE_TP_WAIT; do { - bool success = startAndConnectSession(); - if (success) + if (sShuttingDown) { - // enable/disable the automatic VAD and explicitly set the initial values of - // the VAD variables ourselves when it is off - see SL-15072 for more details - // note: we set the other parameters too even if the auto VAD is on which is ok - unsigned int vad_auto = gSavedSettings.getU32("VivoxVadAuto"); - unsigned int vad_hangover = gSavedSettings.getU32("VivoxVadHangover"); - unsigned int vad_noise_floor = gSavedSettings.getU32("VivoxVadNoiseFloor"); - unsigned int vad_sensitivity = gSavedSettings.getU32("VivoxVadSensitivity"); - setupVADParams(vad_auto, vad_hangover, vad_noise_floor, vad_sensitivity); - - // watch for changes to the VAD settings via Debug Settings UI and act on them accordingly - gSavedSettings.getControl("VivoxVadAuto")->getSignal()->connect(boost::bind(&LLVivoxVoiceClient::onVADSettingsChange, this)); - gSavedSettings.getControl("VivoxVadHangover")->getSignal()->connect(boost::bind(&LLVivoxVoiceClient::onVADSettingsChange, this)); - gSavedSettings.getControl("VivoxVadNoiseFloor")->getSignal()->connect(boost::bind(&LLVivoxVoiceClient::onVADSettingsChange, this)); - gSavedSettings.getControl("VivoxVadSensitivity")->getSignal()->connect(boost::bind(&LLVivoxVoiceClient::onVADSettingsChange, this)); - - if (mTuningMode && !sShuttingDown) - { - performMicTuning(); - } - - if (!sShuttingDown) - { - waitForChannel(); // this doesn't normally return unless relog is needed or shutting down - } - - LL_DEBUGS("Voice") << "lost channel RelogRequested=" << mRelogRequested << LL_ENDL; - endAndDisconnectSession(); - retry = 0; + // Vivox singleton performed the exit, logged out, + // cleaned sockets, gateway and no longer cares + // about state of coroutine, so just stop + return; } - - // if we hit this and mRelogRequested is true, that indicates - // that we attempted to relog into Vivox and were rejected. - // Rather than just quit out of voice, we will tear it down (above) - // and then reconstruct the voice connecion from scratch. - LL_DEBUGS("Voice") - << "disconnected" - << " RelogRequested=" << mRelogRequested - << LL_ENDL; - if (mRelogRequested && !sShuttingDown) + + switch (coro_state) { - if (!success) + case VOICE_STATE_TP_WAIT: + // starting point for voice + if (gAgent.getTeleportState() != LLAgent::TELEPORT_NONE) { - // We failed to connect, give it a bit time before retrying. - retry++; - F32 delay = llmin(5.f * (F32)retry, 60.f); - llcoro::suspendUntilTimeout(delay); - LL_INFOS("Voice") << "Voice failed to establish session after " << retry << " tries. Will attempt to reconnect." << LL_ENDL; + LL_DEBUGS("Voice") << "Suspending voiceControlCoro() momentarily for teleport. Tuning: " << mTuningMode << ". Relog: " << mRelogRequested << LL_ENDL; + llcoro::suspendUntilTimeout(1.0); } else { - LL_INFOS("Voice") << "will attempt to reconnect to voice" << LL_ENDL; + coro_state = VOICE_STATE_START_DAEMON; } + break; - while (isGatewayRunning() || (gAgent.getTeleportState() != LLAgent::TELEPORT_NONE && !sShuttingDown)) + case VOICE_STATE_START_DAEMON: + LL_DEBUGS("Voice") << "Launching daemon" << LL_ENDL; + LLVoiceVivoxStats::getInstance()->reset(); + if (startAndLaunchDaemon()) + { + coro_state = VOICE_STATE_PROVISION_ACCOUNT; + } + else + { + coro_state = VOICE_STATE_SESSION_RETRY; + } + break; + + case VOICE_STATE_PROVISION_ACCOUNT: + if (provisionVoiceAccount()) + { + coro_state = VOICE_STATE_START_SESSION; + } + else + { + coro_state = VOICE_STATE_SESSION_RETRY; + } + break; + + case VOICE_STATE_START_SESSION: + if (establishVoiceConnection()) + { + coro_state = VOICE_STATE_SESSION_ESTABLISHED; + } + else + { + coro_state = VOICE_STATE_SESSION_RETRY; + } + break; + + case VOICE_STATE_SESSION_RETRY: + giveUp(); // cleans sockets and session + if (mRelogRequested) + { + // We failed to connect, give it a bit time before retrying. + retry++; + F32 full_delay = llmin(5.f * (F32)retry, 60.f); + F32 current_delay = 0.f; + LL_INFOS("Voice") << "Voice failed to establish session after " << retry + << " tries. Will attempt to reconnect in " << full_delay + << " seconds" << LL_ENDL; + while (current_delay < full_delay && !sShuttingDown) + { + // Assuming that a second has passed is not accurate, + // but we don't need accurancy here, just to make sure + // that some time passed and not to outlive voice itself + current_delay++; + llcoro::suspendUntilTimeout(1.f); + } + coro_state = VOICE_STATE_WAIT_FOR_EXIT; + } + else + { + coro_state = VOICE_STATE_DONE; + } + break; + + case VOICE_STATE_SESSION_ESTABLISHED: + { + // enable/disable the automatic VAD and explicitly set the initial values of + // the VAD variables ourselves when it is off - see SL-15072 for more details + // note: we set the other parameters too even if the auto VAD is on which is ok + unsigned int vad_auto = gSavedSettings.getU32("VivoxVadAuto"); + unsigned int vad_hangover = gSavedSettings.getU32("VivoxVadHangover"); + unsigned int vad_noise_floor = gSavedSettings.getU32("VivoxVadNoiseFloor"); + unsigned int vad_sensitivity = gSavedSettings.getU32("VivoxVadSensitivity"); + setupVADParams(vad_auto, vad_hangover, vad_noise_floor, vad_sensitivity); + + // watch for changes to the VAD settings via Debug Settings UI and act on them accordingly + gSavedSettings.getControl("VivoxVadAuto")->getSignal()->connect(boost::bind(&LLVivoxVoiceClient::onVADSettingsChange, this)); + gSavedSettings.getControl("VivoxVadHangover")->getSignal()->connect(boost::bind(&LLVivoxVoiceClient::onVADSettingsChange, this)); + gSavedSettings.getControl("VivoxVadNoiseFloor")->getSignal()->connect(boost::bind(&LLVivoxVoiceClient::onVADSettingsChange, this)); + gSavedSettings.getControl("VivoxVadSensitivity")->getSignal()->connect(boost::bind(&LLVivoxVoiceClient::onVADSettingsChange, this)); + + if (mTuningMode) + { + performMicTuning(); + } + + coro_state = VOICE_STATE_WAIT_FOR_CHANNEL; + } + break; + + case VOICE_STATE_WAIT_FOR_CHANNEL: + waitForChannel(); // todo: split into more states like login/fonts + coro_state = VOICE_STATE_DISCONNECT; + break; + + case VOICE_STATE_DISCONNECT: + LL_DEBUGS("Voice") << "lost channel RelogRequested=" << mRelogRequested << LL_ENDL; + endAndDisconnectSession(); + retry = 0; // Connected without issues + coro_state = VOICE_STATE_WAIT_FOR_EXIT; + break; + + case VOICE_STATE_WAIT_FOR_EXIT: + if (isGatewayRunning()) { LL_INFOS("Voice") << "waiting for SLVoice to exit" << LL_ENDL; llcoro::suspendUntilTimeout(1.0); } + else if (mRelogRequested && mVoiceEnabled) + { + LL_INFOS("Voice") << "will attempt to reconnect to voice" << LL_ENDL; + coro_state = VOICE_STATE_TP_WAIT; + } + else + { + coro_state = VOICE_STATE_DONE; + } + break; + + case VOICE_STATE_DONE: + break; } - } - while (mVoiceEnabled && mRelogRequested && !sShuttingDown); + } while (coro_state > 0); + mIsCoroutineActive = false; LL_INFOS("Voice") << "exiting" << LL_ENDL; } -bool LLVivoxVoiceClient::startAndConnectSession() -{ - bool ok = false; - LL_DEBUGS("Voice") << LL_ENDL; - - LLVoiceVivoxStats::getInstance()->reset(); - - if (startAndLaunchDaemon()) - { - if (provisionVoiceAccount()) - { - if (establishVoiceConnection()) - { - ok = true; - } - } - } - - if (!ok) - { - giveUp(); - } - - return ok; -} - bool LLVivoxVoiceClient::endAndDisconnectSession() { LL_DEBUGS("Voice") << LL_ENDL; @@ -881,10 +980,18 @@ bool LLVivoxVoiceClient::startAndLaunchDaemon() std::string exe_path = gDirUtilp->getExecutableDir(); // On Linux the viewer can run SLVoice.exe through wine (https://www.winehq.org/) //gDirUtilp->append(exe_path, "SLVoice"); - if( !viewerUsesWineForVoice() ) - gDirUtilp->append(exe_path, "SLVoice"); // native version - else - gDirUtilp->append(exe_path, "win32/SLVoice.exe"); // use bundled win32 version + switch( viewerUsesWineForVoice() ) + { + case EWineMode::eNoWine: + gDirUtilp->append(exe_path, "SLVoice"); // native version + break; + case EWineMode::e32Bit: + gDirUtilp->append(exe_path, "win32/SLVoice.exe"); // use bundled win32 version + break; + case EWineMode::e64Bit: + gDirUtilp->append(exe_path, "win64/SLVoice.exe"); // use bundled win64 version + break; + } // #endif // See if the vivox executable exists @@ -897,7 +1004,7 @@ bool LLVivoxVoiceClient::startAndLaunchDaemon() // On Linux the viewer can run SLVoice.exe through wine (https://www.winehq.org/) params.executable = exe_path; - if( !viewerUsesWineForVoice() ) + if( EWineMode::eNoWine == viewerUsesWineForVoice() ) params.executable = exe_path; else { @@ -1140,21 +1247,24 @@ bool LLVivoxVoiceClient::provisionVoiceAccount() LLVoiceVivoxStats::getInstance()->provisionAttemptStart(); result = httpAdapter->postAndSuspend(httpRequest, url, LLSD(), httpOpts); + if (sShuttingDown) + { + return false; + } + LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); if (status == LLCore::HttpStatus(404)) { F32 timeout = pow(PROVISION_RETRY_TIMEOUT, static_cast(retryCount)); - LL_WARNS("Voice") << "Provision CAP 404. Retrying in " << timeout << " seconds." << LL_ENDL; + LL_WARNS("Voice") << "Provision CAP 404. Retrying in " << timeout << " seconds. Retries: " << (S32)retryCount << LL_ENDL; + llcoro::suspendUntilTimeout(timeout); + if (sShuttingDown) { return false; } - else - { - llcoro::suspendUntilTimeout(timeout); - } } else if (!status) { @@ -1529,6 +1639,11 @@ bool LLVivoxVoiceClient::requestParcelVoiceInfo() LLSD result = httpAdapter->postAndSuspend(httpRequest, url, LLSD()); + if (sShuttingDown) + { + return false; + } + LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); @@ -1634,6 +1749,11 @@ bool LLVivoxVoiceClient::addAndJoinSession(const sessionStatePtr_t &nextSession) llcoro::suspend(); + if (sShuttingDown) + { + return false; + } + LLSD result; if (mSpatialJoiningNum == MAX_NORMAL_JOINING_SPATIAL_NUM) @@ -1699,7 +1819,6 @@ bool LLVivoxVoiceClient::addAndJoinSession(const sessionStatePtr_t &nextSession) if (sShuttingDown) { - mIsJoiningSession = false; return false; } @@ -1822,6 +1941,11 @@ bool LLVivoxVoiceClient::terminateAudioSession(bool wait) result = llcoro::suspendUntilEventOnWithTimeout(mVivoxPump, LOGOUT_ATTEMPT_TIMEOUT, timeoutResult); + if (sShuttingDown) + { + return false; + } + LL_DEBUGS("Voice") << "event=" << ll_stream_notation_sd(result) << LL_ENDL; if (result.has("session")) { @@ -1886,50 +2010,76 @@ bool LLVivoxVoiceClient::terminateAudioSession(bool wait) return status; } + +typedef enum e_voice_wait_for_channel_state +{ + VOICE_CHANNEL_STATE_LOGIN = 0, // entry point + VOICE_CHANNEL_STATE_CHECK_EFFECTS, + VOICE_CHANNEL_STATE_START_CHANNEL_PROCESSING, + VOICE_CHANNEL_STATE_PROCESS_CHANNEL, + VOICE_CHANNEL_STATE_NEXT_CHANNEL_DELAY, + VOICE_CHANNEL_STATE_NEXT_CHANNEL_CHECK, + VOICE_CHANNEL_STATE_LOGOUT, + VOICE_CHANNEL_STATE_RELOG, + VOICE_CHANNEL_STATE_DONE, +} EVoiceWaitForChannelState; + bool LLVivoxVoiceClient::waitForChannel() { LL_INFOS("Voice") << "Waiting for channel" << LL_ENDL; + EVoiceWaitForChannelState state = VOICE_CHANNEL_STATE_LOGIN; + do { - if (!loginToVivox()) - { - return false; - } - if (sShuttingDown) { - logoutOfVivox(false); + // terminate() forcefully disconects voice, no need for cleanup return false; } - if (LLVoiceClient::instance().getVoiceEffectEnabled()) + switch (state) { - retrieveVoiceFonts(); - - // Request the set of available voice fonts. - refreshVoiceEffectLists(false); - } - -#if USE_SESSION_GROUPS - // Rider: This code is completely unchanged from the original state machine - // It does not seem to be in active use... but I'd rather not rip it out. - // create the main session group - setState(stateCreatingSessionGroup); - sessionGroupCreateSendMessage(); -#endif - - do - { - mIsProcessingChannels = true; - llcoro::suspend(); - - if (sShuttingDown) + case VOICE_CHANNEL_STATE_LOGIN: + if (!loginToVivox()) { - mRelogRequested = false; - break; + return false; + } + state = VOICE_CHANNEL_STATE_CHECK_EFFECTS; + break; + + case VOICE_CHANNEL_STATE_CHECK_EFFECTS: + if (LLVoiceClient::instance().getVoiceEffectEnabled()) + { + retrieveVoiceFonts(); + + if (sShuttingDown) + { + return false; + } + + // Request the set of available voice fonts. + refreshVoiceEffectLists(false); } +#if USE_SESSION_GROUPS + // Rider: This code is completely unchanged from the original state machine + // It does not seem to be in active use... but I'd rather not rip it out. + // create the main session group + setState(stateCreatingSessionGroup); + sessionGroupCreateSendMessage(); +#endif + + state = VOICE_CHANNEL_STATE_START_CHANNEL_PROCESSING; + break; + + case VOICE_CHANNEL_STATE_START_CHANNEL_PROCESSING: + mIsProcessingChannels = true; + llcoro::suspend(); + state = VOICE_CHANNEL_STATE_PROCESS_CHANNEL; + break; + + case VOICE_CHANNEL_STATE_PROCESS_CHANNEL: if (mTuningMode) { performMicTuning(); @@ -1973,54 +2123,91 @@ bool LLVivoxVoiceClient::waitForChannel() } } - if (!mNextAudioSession && !sShuttingDown) + state = VOICE_CHANNEL_STATE_NEXT_CHANNEL_DELAY; + break; + + case VOICE_CHANNEL_STATE_NEXT_CHANNEL_DELAY: + if (!mNextAudioSession) { llcoro::suspendUntilTimeout(1.0); } + state = VOICE_CHANNEL_STATE_NEXT_CHANNEL_CHECK; + break; - if (sShuttingDown) + case VOICE_CHANNEL_STATE_NEXT_CHANNEL_CHECK: + if (mVoiceEnabled && !mRelogRequested) { - mRelogRequested = false; + state = VOICE_CHANNEL_STATE_START_CHANNEL_PROCESSING; + break; + } + else + { + mIsProcessingChannels = false; + LL_DEBUGS("Voice") + << "leaving inner waitForChannel loop" + << " RelogRequested=" << mRelogRequested + << " VoiceEnabled=" << mVoiceEnabled + << LL_ENDL; + state = VOICE_CHANNEL_STATE_LOGOUT; break; } - } while (mVoiceEnabled && !mRelogRequested && !sShuttingDown); + case VOICE_CHANNEL_STATE_LOGOUT: + logoutOfVivox(true /*bool wait*/); + if (mRelogRequested) + { + state = VOICE_CHANNEL_STATE_RELOG; + } + else + { + state = VOICE_CHANNEL_STATE_DONE; + } + break; - LL_DEBUGS("Voice") - << "leaving inner waitForChannel loop" - << " RelogRequested=" << mRelogRequested - << " VoiceEnabled=" << mVoiceEnabled - << LL_ENDL; - - mIsProcessingChannels = false; - - logoutOfVivox(!sShuttingDown /*bool wait*/); - - if (mRelogRequested && !sShuttingDown) - { + case VOICE_CHANNEL_STATE_RELOG: LL_DEBUGS("Voice") << "Relog Requested, restarting provisioning" << LL_ENDL; if (!provisionVoiceAccount()) { + if (sShuttingDown) + { + return false; + } LL_WARNS("Voice") << "provisioning voice failed; giving up" << LL_ENDL; giveUp(); return false; } + if (mVoiceEnabled && mRelogRequested && isGatewayRunning()) + { + state = VOICE_CHANNEL_STATE_LOGIN; + } + else + { + state = VOICE_CHANNEL_STATE_DONE; + } + break; + case VOICE_CHANNEL_STATE_DONE: + LL_DEBUGS("Voice") + << "exiting" + << " RelogRequested=" << mRelogRequested + << " VoiceEnabled=" << mVoiceEnabled + << LL_ENDL; + return !sShuttingDown; } - } while (mVoiceEnabled && mRelogRequested && isGatewayRunning() && !sShuttingDown); - - LL_DEBUGS("Voice") - << "exiting" - << " RelogRequested=" << mRelogRequested - << " VoiceEnabled=" << mVoiceEnabled - << LL_ENDL; - return !sShuttingDown; + } while (true); } bool LLVivoxVoiceClient::runSession(const sessionStatePtr_t &session) { LL_INFOS("Voice") << "running new voice session " << session->mHandle << LL_ENDL; - if (!addAndJoinSession(session)) + bool joined_session = addAndJoinSession(session); + + if (sShuttingDown) + { + return false; + } + + if (!joined_session) { notifyStatusObservers(LLVoiceClientStatusObserver::ERROR_UNKNOWN); @@ -2044,9 +2231,19 @@ bool LLVivoxVoiceClient::runSession(const sessionStatePtr_t &session) mIsInChannel = true; mMuteMicDirty = true; - while (mVoiceEnabled && isGatewayRunning() && !mSessionTerminateRequested && !mTuningMode) + while (!sShuttingDown + && mVoiceEnabled + && isGatewayRunning() + && !mSessionTerminateRequested + && !mTuningMode) { sendCaptureAndRenderDevices(); // suspends + + if (sShuttingDown) + { + return false; + } + if (mSessionTerminateRequested) { break; @@ -2076,10 +2273,15 @@ bool LLVivoxVoiceClient::runSession(const sessionStatePtr_t &session) // cap for the parcel voice info. If we can't request it // then we don't have the cap URL so we do nothing and will // recheck next time around - if (requestParcelVoiceInfo()) + if (requestParcelVoiceInfo()) // suspends { // The parcel voice URI has changed.. break out and reconnect. break; } + + if (sShuttingDown) + { + return false; + } } // Do the calculation that enforces the listener<->speaker tether (and also updates the real camera position) enforceTether(); @@ -2098,6 +2300,12 @@ bool LLVivoxVoiceClient::runSession(const sessionStatePtr_t &session) mIsInitialized = true; LLSD result = llcoro::suspendUntilEventOnWithTimeout(mVivoxPump, UPDATE_THROTTLE_SECONDS, timeoutEvent); + + if (sShuttingDown) + { + return false; + } + if (!result.has("timeout")) // logging the timeout event spams the log { LL_DEBUGS("Voice") << "event=" << ll_stream_notation_sd(result) << LL_ENDL; @@ -2140,6 +2348,11 @@ bool LLVivoxVoiceClient::runSession(const sessionStatePtr_t &session) } } + if (sShuttingDown) + { + return false; + } + mIsInChannel = false; LL_DEBUGS("Voice") << "terminating at end of runSession" << LL_ENDL; terminateAudioSession(true); @@ -4849,6 +5062,12 @@ bool LLVivoxVoiceClient::switchChannel( // The old session may now need to be deleted. reapSession(oldSession); + // If voice was on, turn it off + if (LLVoiceClient::getInstance()->getUserPTTState()) + { + LLVoiceClient::getInstance()->setUserPTTState(false); + } + notifyStatusObservers(LLVoiceClientStatusObserver::STATUS_VOICE_DISABLED); } else diff --git a/indra/newview/llvoicevivox.h b/indra/newview/llvoicevivox.h index 886acf677a..d19e6ca718 100644 --- a/indra/newview/llvoicevivox.h +++ b/indra/newview/llvoicevivox.h @@ -636,8 +636,8 @@ private: // Coroutine support methods //--- void voiceControlCoro(); + void voiceControlStateMachine(S32 &coro_state); - bool startAndConnectSession(); bool endAndDisconnectSession(); bool callbackEndDaemon(const LLSD& data); diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp index 7ce1730b26..29cdd84baa 100644 --- a/indra/newview/llvovolume.cpp +++ b/indra/newview/llvovolume.cpp @@ -91,6 +91,7 @@ #include "rlvlocks.h" // [/RLVa:KB] #include "llviewernetwork.h" +#include "fsperfstats.h" // performance stats support const F32 FORCE_SIMPLE_RENDER_AREA = 512.f; const F32 FORCE_CULL_AREA = 8.f; @@ -397,6 +398,18 @@ U32 LLVOVolume::processUpdateMessage(LLMessageSystem *mesgsys, { delete mTextureAnimp; mTextureAnimp = NULL; + + for (S32 i = 0; i < getNumTEs(); i++) + { + LLFace* facep = mDrawable->getFace(i); + if (facep && facep->mTextureMatrix) + { + // delete or reset + delete facep->mTextureMatrix; + facep->mTextureMatrix = NULL; + } + } + gPipeline.markTextured(mDrawable); mFaceMappingChanged = TRUE; mTexAnimMode = 0; @@ -593,6 +606,18 @@ U32 LLVOVolume::processUpdateMessage(LLMessageSystem *mesgsys, { delete mTextureAnimp; mTextureAnimp = NULL; + + for (S32 i = 0; i < getNumTEs(); i++) + { + LLFace* facep = mDrawable->getFace(i); + if (facep && facep->mTextureMatrix) + { + // delete or reset + delete facep->mTextureMatrix; + facep->mTextureMatrix = NULL; + } + } + gPipeline.markTextured(mDrawable); mFaceMappingChanged = TRUE; mTexAnimMode = 0; @@ -5545,7 +5570,7 @@ void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep, } } - if (type == LLRenderPass::PASS_ALPHA) + // if (type == LLRenderPass::PASS_ALPHA) // allow tracking through pipeline { //for alpha sorting facep->setDrawInfo(draw_info); } @@ -5761,6 +5786,7 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group) LL_RECORD_BLOCK_TIME(FTM_REBUILD_VOLUME_FACE_LIST); //get all the faces into a list + std::unique_ptr ratPtr{}; // render time capture for (LLSpatialGroup::element_iter drawable_iter = group->getDataBegin(); drawable_iter != group->getDataEnd(); ++drawable_iter) { @@ -5783,6 +5809,7 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group) continue; } + // Stop doing stupid stuff we don;t need to. // Moving this inside a debug enabled check // std::string vobj_name = llformat("Vol%p", vobj); @@ -5793,6 +5820,12 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group) { continue; } + // Capture render times + if(vobj->isAttachment()) + { + trackAttachments( vobj, drawablep->isState(LLDrawable::RIGGED),&ratPtr); + } + // LLVolume* volume = vobj->getVolume(); if (volume) @@ -6360,7 +6393,7 @@ static LLTrace::BlockTimerStatHandle FTM_REBUILD_MESH_FLUSH("Flush Mesh"); void LLVolumeGeometryManager::rebuildMesh(LLSpatialGroup* group) { llassert(group); - LL_RECORD_BLOCK_TIME(FTM_REBUILD_VOLUME_VB);// move out one scope (but are these even useful as dupes?) + // LL_RECORD_BLOCK_TIME(FTM_REBUILD_VOLUME_VB);// High volume remove (roughly 1000:1 ratio to inside the if statement) if (group && group->hasState(LLSpatialGroup::MESH_DIRTY) && !group->hasState(LLSpatialGroup::GEOM_DIRTY)) { // LL_RECORD_BLOCK_TIME(FTM_REBUILD_VOLUME_VB);// move out one scope (but are these even useful as dupes?) @@ -6375,13 +6408,21 @@ void LLVolumeGeometryManager::rebuildMesh(LLSpatialGroup* group) U32 buffer_count = 0; + std::unique_ptr ratPtr{}; // capture render times for (LLSpatialGroup::element_iter drawable_iter = group->getDataBegin(); drawable_iter != group->getDataEnd(); ++drawable_iter) { LLDrawable* drawablep = (LLDrawable*)(*drawable_iter)->getDrawable(); if (drawablep && !drawablep->isDead() && drawablep->isState(LLDrawable::REBUILD_ALL) && !drawablep->isState(LLDrawable::RIGGED) ) { + FSZoneN("Rebuild all non-Rigged"); LLVOVolume* vobj = drawablep->getVOVolume(); + // capture render times + if( vobj && vobj->isAttachment() ) + { + trackAttachments( vobj, drawablep->isState(LLDrawable::RIGGED), &ratPtr ); + } + // // avoid unfortunate sleep during trylock by static check //if(debugLoggingEnabled("AnimatedObjectsLinkset")) static auto debug_logging_on = debugLoggingEnabled("AnimatedObjectsLinkset"); @@ -6794,10 +6835,18 @@ U32 LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, LLFace U32 indices_index = 0; U16 index_offset = 0; + std::unique_ptr ratPtr; // capture render times while (face_iter < i) { //update face indices for new buffer facep = *face_iter; + LLViewerObject* vobj = facep->getViewerObject(); + // capture render times + if(vobj && vobj->isAttachment()) + { + trackAttachments(vobj, LLPipeline::sShadowRender, &ratPtr); + } + // if (buffer.isNull()) { // Bulk allocation failed @@ -7013,8 +7062,12 @@ U32 LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, LLFace else if (is_alpha) { // can we safely treat this as an alpha mask? - if (facep->getFaceColor().mV[3] <= 0.f) + // Nothing actually sets facecolor use the TE alpha instead. + // if (facep->getFaceColor().mV[3] <= 0.f) + if (te->getAlpha() <=0.f || facep->getFaceColor().mV[3] <= 0.f) + // { //100% transparent, don't render unless we're highlighting transparent + FSZoneN("facep->alpha -> invisible"); registerFace(group, facep, LLRenderPass::PASS_ALPHA_INVISIBLE); } else if (facep->canRenderAsMask()) diff --git a/indra/newview/llwearableitemslist.cpp b/indra/newview/llwearableitemslist.cpp index 8fa1f1f530..26c071b66e 100644 --- a/indra/newview/llwearableitemslist.cpp +++ b/indra/newview/llwearableitemslist.cpp @@ -1017,7 +1017,7 @@ void LLWearableItemsList::ContextMenu::show(LLView* spawning_view, LLWearableTyp setMenuItemVisible(menup, "wearable_attach_to", false); setMenuItemVisible(menup, "wearable_attach_to_hud", false); - std::string new_label = LLTrans::getString("create_new_" + LLWearableType::getTypeName(w_type)); + std::string new_label = LLTrans::getString("create_new_" + LLWearableType::getInstance()->getTypeName(w_type)); LLMenuItemGL* menu_item = menup->getChild("create_new"); menu_item->setLabel(new_label); @@ -1253,7 +1253,7 @@ void LLWearableItemsList::ContextMenu::updateItemsLabels(LLContextMenu* menu) if (!item || !item->isWearableType()) return; LLWearableType::EType w_type = item->getWearableType(); - std::string new_label = LLTrans::getString("create_new_" + LLWearableType::getTypeName(w_type)); + std::string new_label = LLTrans::getString("create_new_" + LLWearableType::getInstance()->getTypeName(w_type)); LLMenuItemGL* menu_item = menu->getChild("create_new"); menu_item->setLabel(new_label); diff --git a/indra/newview/llwearablelist.cpp b/indra/newview/llwearablelist.cpp index 10e25bb86b..2a6c0ef6ba 100644 --- a/indra/newview/llwearablelist.cpp +++ b/indra/newview/llwearablelist.cpp @@ -257,7 +257,8 @@ LLViewerWearable* LLWearableList::createNewWearable( LLWearableType::EType type, LLViewerWearable *wearable = generateNewWearable(); wearable->setType( type, avatarp ); - std::string name = LLTrans::getString( LLWearableType::getTypeDefaultNewName(wearable->getType()) ); + // LLWearableType has pre-translated getTypeLabel(), but it returns 'name', not 'New Name'. + std::string name = LLTrans::getString( LLWearableType::getInstance()->getTypeDefaultNewName(wearable->getType()) ); wearable->setName( name ); LLPermissions perm; diff --git a/indra/newview/llweb.cpp b/indra/newview/llweb.cpp index be1027a473..601c4ebe84 100644 --- a/indra/newview/llweb.cpp +++ b/indra/newview/llweb.cpp @@ -38,6 +38,7 @@ #include "llfloaterreg.h" #include "lllogininstance.h" #include "llparcel.h" +#include "llregex.h" #include "llsd.h" #include "llui.h" #include "lluri.h" @@ -51,8 +52,6 @@ #include "lluriparser.h" #include "uriparser/Uri.h" -#include - bool on_load_url_external_response(const LLSD& notification, const LLSD& response, bool async ); @@ -246,13 +245,13 @@ bool LLWeb::useExternalBrowser(const std::string &url) boost::regex pattern = boost::regex("\\b(lindenlab.com|secondlife.com|secondlife.io|secondlifegrid.net|secondlife-status.statuspage.io)$", boost::regex::perl|boost::regex::icase); // boost::match_results matches; - return !(boost::regex_search(uri_string, matches, pattern)); + return !(ll_regex_search(uri_string, matches, pattern)); } else { boost::regex pattern = boost::regex("^mailto:", boost::regex::perl | boost::regex::icase); boost::match_results matches; - return boost::regex_search(url, matches, pattern); + return ll_regex_search(url, matches, pattern); } #endif } diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp index be66720237..7b5c595f15 100644 --- a/indra/newview/pipeline.cpp +++ b/indra/newview/pipeline.cpp @@ -370,6 +370,7 @@ bool LLPipeline::sReflectionRender = false; bool LLPipeline::sDistortionRender = false; bool LLPipeline::sImpostorRender = false; bool LLPipeline::sImpostorRenderAlphaDepthPass = false; +bool LLPipeline::sShowJellyDollAsImpostor = true; bool LLPipeline::sUnderWaterRender = false; bool LLPipeline::sTextureBindTest = false; bool LLPipeline::sRenderFrameTest = false; @@ -822,19 +823,24 @@ void LLPipeline::resizeScreenTexture() GLuint resY = gViewerWindow->getWorldViewHeightRaw(); // [SL:KB] - Patch: Settings-RenderResolutionMultiplier | Checked: Catznip-5.4 + GLuint scaledResX = resX; + GLuint scaledResY = resY; if ( (RenderResolutionDivisor > 1) && (RenderResolutionDivisor < resX) && (RenderResolutionDivisor < resY) ) { - resX /= RenderResolutionDivisor; - resY /= RenderResolutionDivisor; + scaledResX /= RenderResolutionDivisor; + scaledResY /= RenderResolutionDivisor; } else if (RenderResolutionMultiplier > 0.f && RenderResolutionMultiplier < 1.f) { - resX *= RenderResolutionMultiplier; - resY *= RenderResolutionMultiplier; + scaledResX *= RenderResolutionMultiplier; + scaledResY *= RenderResolutionMultiplier; } // [/SL:KB] - if (gResizeScreenTexture || (resX != mScreen.getWidth()) || (resY != mScreen.getHeight())) +// if (gResizeScreenTexture || (resX != mScreen.getWidth()) || (resY != mScreen.getHeight())) +// [SL:KB] - Patch: Settings-RenderResolutionMultiplier | Checked: Catznip-5.4 + if (gResizeScreenTexture || (scaledResX != mScreen.getWidth()) || (scaledResY != mScreen.getHeight())) +// [/SL:KB] { releaseScreenBuffers(); releaseShadowTargets(); @@ -1195,6 +1201,7 @@ void LLPipeline::refreshCachedSettings() LLPipeline::sAutoMaskAlphaDeferred = gSavedSettings.getBOOL("RenderAutoMaskAlphaDeferred"); LLPipeline::sAutoMaskAlphaNonDeferred = gSavedSettings.getBOOL("RenderAutoMaskAlphaNonDeferred"); LLPipeline::sUseFarClip = gSavedSettings.getBOOL("RenderUseFarClip"); + LLPipeline::sShowJellyDollAsImpostor = gSavedSettings.getBOOL("RenderJellyDollsAsImpostors"); LLVOAvatar::sMaxNonImpostors = gSavedSettings.getU32("RenderAvatarMaxNonImpostors"); LLVOAvatar::updateImpostorRendering(LLVOAvatar::sMaxNonImpostors); LLPipeline::sDelayVBUpdate = gSavedSettings.getBOOL("RenderDelayVBUpdate"); @@ -2829,6 +2836,7 @@ void LLPipeline::doOcclusion(LLCamera& camera, LLRenderTarget& source, LLRenderT void LLPipeline::doOcclusion(LLCamera& camera) { + FSZoneN("doOcclusion"); if (LLPipeline::sUseOcclusion > 1 && !LLSpatialPartition::sTeleportRequested && (sCull->hasOcclusionGroups() || LLVOCachePartition::sNeedsOcclusionCheck)) { @@ -3544,6 +3552,8 @@ void LLPipeline::stateSort(LLCamera& camera, LLCullResult &result) //LLVertexBuffer::unbind(); grabReferences(result); + { + FSZoneN("checkOcclusionAndRebuildMesh"); for (LLCullResult::sg_iterator iter = sCull->beginDrawableGroups(); iter != sCull->endDrawableGroups(); ++iter) { LLSpatialGroup* group = *iter; @@ -3567,9 +3577,11 @@ void LLPipeline::stateSort(LLCamera& camera, LLCullResult &result) } } } + } if (LLViewerCamera::sCurCameraID == LLViewerCamera::CAMERA_WORLD) { + FSZoneN("WorldCamera"); LLSpatialGroup* last_group = NULL; BOOL fov_changed = LLViewerCamera::getInstance()->isDefaultFOVChanged(); for (LLCullResult::bridge_iterator i = sCull->beginVisibleBridge(); i != sCull->endVisibleBridge(); ++i) @@ -3603,7 +3615,8 @@ void LLPipeline::stateSort(LLCamera& camera, LLCullResult &result) last_group->mLastUpdateDistance = last_group->mDistance; } } - + { + FSZoneN("StateSort: visible groups"); for (LLCullResult::sg_iterator iter = sCull->beginVisibleGroups(); iter != sCull->endVisibleGroups(); ++iter) { LLSpatialGroup* group = *iter; @@ -3622,7 +3635,7 @@ void LLPipeline::stateSort(LLCamera& camera, LLCullResult &result) group->rebuildMesh(); } } - } + }} { LL_RECORD_BLOCK_TIME(FTM_STATESORT_DRAWABLE); @@ -3978,6 +3991,8 @@ void LLPipeline::postSort(LLCamera& camera) LL_PUSH_CALLSTACKS(); //rebuild drawable geometry + { + FSZoneN("PostSort: rebuildGeom"); for (LLCullResult::sg_iterator i = sCull->beginDrawableGroups(); i != sCull->endDrawableGroups(); ++i) { LLSpatialGroup* group = *i; @@ -3996,6 +4011,8 @@ void LLPipeline::postSort(LLCamera& camera) //build render map + { + FSZoneN("build render map"); for (LLCullResult::sg_iterator i = sCull->beginVisibleGroups(); i != sCull->endVisibleGroups(); ++i) { LLSpatialGroup* group = *i; @@ -4041,6 +4058,7 @@ void LLPipeline::postSort(LLCamera& camera) if (hasRenderType(LLPipeline::RENDER_TYPE_PASS_ALPHA)) { + FSZoneN("Collect Alpha groups"); LLSpatialGroup::draw_map_t::iterator alpha = group->mDrawMap.find(LLRenderPass::PASS_ALPHA); if (alpha != group->mDrawMap.end()) @@ -4066,6 +4084,7 @@ void LLPipeline::postSort(LLCamera& camera) } } } + } //flush particle VB if (LLVOPartGroup::sVB) @@ -4091,12 +4110,15 @@ void LLPipeline::postSort(LLCamera& camera) glBeginQueryARB(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN, mMeshDirtyQueryObject); }*/ - + { + FSZoneN("rebuild delayed upd groups"); //pack vertex buffers for groups that chose to delay their updates for (LLSpatialGroup::sg_vector_t::iterator iter = mMeshDirtyGroup.begin(); iter != mMeshDirtyGroup.end(); ++iter) { (*iter)->rebuildMesh(); } + } + } /*if (use_transform_feedback) { @@ -4105,12 +4127,17 @@ void LLPipeline::postSort(LLCamera& camera) mMeshDirtyGroup.clear(); + { + FSZoneN("sort alpha groups"); if (!sShadowRender) { std::sort(sCull->beginAlphaGroups(), sCull->endAlphaGroups(), LLSpatialGroup::CompareDepthGreater()); } + } LL_PUSH_CALLSTACKS(); + { + FSZoneN("beacon rendering flags"); // only render if the flag is set. The flag is only set if we are in edit mode or the toggle is set in the menus // Ansariel: Make beacons also show when beacons floater is closed. if (/*LLFloaterReg::instanceVisible("beacons") &&*/ !sShadowRender) @@ -4164,6 +4191,7 @@ void LLPipeline::postSort(LLCamera& camera) forAllVisibleDrawables(renderSoundHighlights); } } + } LL_PUSH_CALLSTACKS(); // If managing your telehub, draw beacons at telehub and currently selected spawnpoint. if (LLFloaterTelehub::renderBeacons()) @@ -4173,6 +4201,7 @@ void LLPipeline::postSort(LLCamera& camera) if (!sShadowRender) { + FSZoneN("Render face highlights"); mSelectedFaces.clear(); LLPipeline::setRenderHighlightTextureChannel(gFloaterTools->getPanelFace()->getTextureChannelToEdit()); @@ -11241,9 +11270,11 @@ void LLPipeline::generateImpostor(LLVOAvatar* avatar) << " is " << ( too_complex ? "" : "not ") << "too complex" << LL_ENDL; + bool too_slow = avatar->isTooSlowWithoutShadows(); // only if we really have to do we imposter. + pushRenderTypeMask(); - if (visually_muted || too_complex) + if ( !too_slow && ( visually_muted || too_complex ) ) { andRenderTypeMask(LLPipeline::RENDER_TYPE_AVATAR, LLPipeline::RENDER_TYPE_CONTROL_AV, diff --git a/indra/newview/pipeline.h b/indra/newview/pipeline.h index d9c8aaef29..d8ce953187 100644 --- a/indra/newview/pipeline.h +++ b/indra/newview/pipeline.h @@ -600,6 +600,7 @@ public: static bool sDistortionRender; static bool sImpostorRender; static bool sImpostorRenderAlphaDepthPass; + static bool sShowJellyDollAsImpostor; static bool sUnderWaterRender; static bool sRenderGlow; static bool sTextureBindTest; diff --git a/indra/newview/rlvcommon.cpp b/indra/newview/rlvcommon.cpp index e22b30186e..9b33285368 100644 --- a/indra/newview/rlvcommon.cpp +++ b/indra/newview/rlvcommon.cpp @@ -22,6 +22,7 @@ #include "llimview.h" #include "llinstantmessage.h" #include "llnotificationsutil.h" +#include "llregex.h" #include "llregionhandle.h" #include "llsdserialize.h" #include "lltrans.h" @@ -43,7 +44,6 @@ #include // icontains #include // regex_replace_all #include -#include // ============================================================================ @@ -220,7 +220,7 @@ bool RlvSettings::isCompatibilityModeObject(const LLUUID& idRlvObject) for (const std::string& strCompatName : s_CompatItemNames) { boost::regex regexp(strCompatName, boost::regex::perl | boost::regex::icase); - if (boost::regex_match(strAttachName, regexp)) + if (ll_regex_match(strAttachName, regexp)) { fCompatMode = true; break; diff --git a/indra/newview/rlvdefines.h b/indra/newview/rlvdefines.h index 4977a42632..b9135f379e 100644 --- a/indra/newview/rlvdefines.h +++ b/indra/newview/rlvdefines.h @@ -39,7 +39,7 @@ const S32 RLV_VERSION_BUILD_COMPAT = 0; // Implementation version const S32 RLVa_VERSION_MAJOR = 2; const S32 RLVa_VERSION_MINOR = 4; -const S32 RLVa_VERSION_PATCH = 1; +const S32 RLVa_VERSION_PATCH = 2; const S32 RLVa_IMPL_ID = 13; // Uncomment before a final release diff --git a/indra/newview/rlvfloaters.cpp b/indra/newview/rlvfloaters.cpp index 92a5e4efb3..05232a8322 100644 --- a/indra/newview/rlvfloaters.cpp +++ b/indra/newview/rlvfloaters.cpp @@ -45,7 +45,7 @@ std::string rlvGetItemName(const LLViewerInventoryItem* pItem) { if ( (pItem) && ((LLAssetType::AT_BODYPART == pItem->getType()) || (LLAssetType::AT_CLOTHING == pItem->getType())) ) { - return llformat("%s (%s)", pItem->getName().c_str(), LLWearableType::getTypeName(pItem->getWearableType()).c_str()); + return llformat("%s (%s)", pItem->getName().c_str(), LLWearableType::getInstance()->getTypeName(pItem->getWearableType()).c_str()); } else if ( (pItem) && (LLAssetType::AT_OBJECT == pItem->getType()) && (isAgentAvatarValid()) ) { @@ -192,7 +192,7 @@ std::string rlvFolderLockSourceToTarget(RlvFolderLocks::folderlock_source_t lock } case RlvFolderLocks::ST_WEARABLETYPE: { - const std::string& strTypeName = LLWearableType::getTypeName(boost::get(lockSource.second)); + const std::string& strTypeName = LLWearableType::getInstance()->getTypeName(boost::get(lockSource.second)); return llformat("Wearable type (%s)", strTypeName.c_str()); } default: @@ -531,7 +531,7 @@ void RlvFloaterLocks::refreshAll() for (RlvWearableLocks::rlv_wearabletypelock_map_t::const_iterator itWearableType = wearableTypeAdd.begin(); itWearableType != wearableTypeAdd.end(); ++itWearableType) { - sdColumns[2]["value"] = LLWearableType::getTypeLabel(itWearableType->first); + sdColumns[2]["value"] = LLWearableType::getInstance()->getTypeLabel(itWearableType->first); sdColumns[3]["value"] = rlvGetItemNameFromObjID(itWearableType->second); pLockList->addElement(sdRow, ADD_BOTTOM); @@ -542,7 +542,7 @@ void RlvFloaterLocks::refreshAll() for (RlvWearableLocks::rlv_wearabletypelock_map_t::const_iterator itWearableType = wearableTypeRem.begin(); itWearableType != wearableTypeRem.end(); ++itWearableType) { - sdColumns[2]["value"] = LLWearableType::getTypeName(itWearableType->first); + sdColumns[2]["value"] = LLWearableType::getInstance()->getTypeName(itWearableType->first); sdColumns[3]["value"] = rlvGetItemNameFromObjID(itWearableType->second); pLockList->addElement(sdRow, ADD_BOTTOM); diff --git a/indra/newview/rlvhandler.cpp b/indra/newview/rlvhandler.cpp index 2d6bbb39a6..beebf94dc5 100644 --- a/indra/newview/rlvhandler.cpp +++ b/indra/newview/rlvhandler.cpp @@ -2451,6 +2451,7 @@ void RlvBehaviourToggleHandler::onCommandToggle(ERlvBehaviour e RlvBehaviourToggleHandler::onCommandToggle(RLV_BHVR_SETCAM_UNLOCK, !fHasCamUnlock); gRlvHandler.setCameraOverride(fHasBhvr); + RlvBehaviourDictionary::instance().getModifier(RLV_MODIFIER_SETCAM_AVDIST)->setPrimaryObject(idRlvObject); RlvBehaviourDictionary::instance().getModifier(RLV_MODIFIER_SETCAM_AVDISTMIN)->setPrimaryObject(idRlvObject); RlvBehaviourDictionary::instance().getModifier(RLV_MODIFIER_SETCAM_AVDISTMAX)->setPrimaryObject(idRlvObject); RlvBehaviourDictionary::instance().getModifier(RLV_MODIFIER_SETCAM_ORIGINDISTMIN)->setPrimaryObject(idRlvObject); @@ -3909,7 +3910,7 @@ ERlvCmdRet RlvHandler::onGetOutfit(const RlvCommand& rlvCmd, std::string& strRep // (Compatibility: RLV-1.16.1 will execute @getoutfit= if is invalid while we just return failure) LLWearableType::EType wtType = LLWearableType::WT_INVALID; - if ( (rlvCmd.hasOption()) && ((wtType = LLWearableType::typeNameToType(rlvCmd.getOption())) == LLWearableType::WT_INVALID) ) + if ( (rlvCmd.hasOption()) && ((wtType = LLWearableType::getInstance()->typeNameToType(rlvCmd.getOption())) == LLWearableType::WT_INVALID) ) return RLV_RET_FAILED_OPTION; const LLWearableType::EType wtRlvTypes[] = @@ -3929,7 +3930,7 @@ ERlvCmdRet RlvHandler::onGetOutfit(const RlvCommand& rlvCmd, std::string& strRep // (nor do we hide a layer if the issuing object is the only one that has this layer locked) bool fWorn = (gAgentWearables.getWearableCount(wtRlvTypes[idxType]) > 0) && ( (!RlvSettings::getHideLockedLayers()) || - (LLAssetType::AT_BODYPART == LLWearableType::getAssetType(wtRlvTypes[idxType])) || + (LLAssetType::AT_BODYPART == LLWearableType::getInstance()->getAssetType(wtRlvTypes[idxType])) || (RlvForceWear::isForceRemovable(wtRlvTypes[idxType], true, rlvCmd.getObjectID())) ); strReply.push_back( (fWorn) ? '1' : '0' ); } @@ -3970,7 +3971,7 @@ ERlvCmdRet RlvHandler::onGetOutfitNames(const RlvCommand& rlvCmd, std::string& s { if (!strReply.empty()) strReply.push_back(','); - strReply.append(LLWearableType::getTypeName(wtType)); + strReply.append(LLWearableType::getInstance()->getTypeName(wtType)); } } return RLV_RET_SUCCESS; diff --git a/indra/newview/rlvhelper.cpp b/indra/newview/rlvhelper.cpp index 7af251e9ca..d686aee5f1 100644 --- a/indra/newview/rlvhelper.cpp +++ b/indra/newview/rlvhelper.cpp @@ -708,6 +708,10 @@ bool RlvBehaviourModifier::convertOptionValue(const std::string& optionValue, co { return false; } + catch (const std::out_of_range&) + { + return false; + } } // ============================================================================ @@ -815,6 +819,10 @@ bool RlvCommandOptionHelper::parseOption(const std::string& strOption, int& { return false; } + catch (const std::out_of_range&) + { + return false; + } return true; } @@ -835,6 +843,10 @@ bool RlvCommandOptionHelper::parseOption(const std::string& strOption, boo ss >> std::boolalpha >> fOption; return !ss.fail(); } + catch (const std::out_of_range&) + { + return false; + } } template<> @@ -848,13 +860,17 @@ bool RlvCommandOptionHelper::parseOption(const std::string& strOption, fl { return false; } + catch (const std::out_of_range&) + { + return false; + } return true; } template<> bool RlvCommandOptionHelper::parseOption(const std::string& strOption, LLWearableType::EType& wtOption) { - wtOption = LLWearableType::typeNameToType(strOption); + wtOption = LLWearableType::getInstance()->typeNameToType(strOption); return (LLWearableType::WT_INVALID != wtOption) && (LLWearableType::WT_NONE != wtOption); } @@ -1904,13 +1920,13 @@ void RlvBehaviourNotifyHandler::sendNotification(const std::string& strText, con // Checked: 2011-03-31 (RLVa-1.3.0f) | Added: RLVa-1.3.0f void RlvBehaviourNotifyHandler::onWear(LLWearableType::EType eType, bool fAllowed) { - sendNotification(llformat("worn %s %s", (fAllowed) ? "legally" : "illegally", LLWearableType::getTypeName(eType).c_str())); + sendNotification(llformat("worn %s %s", (fAllowed) ? "legally" : "illegally", LLWearableType::getInstance()->getTypeName(eType).c_str())); } // Checked: 2011-03-31 (RLVa-1.3.0f) | Added: RLVa-1.3.0f void RlvBehaviourNotifyHandler::onTakeOff(LLWearableType::EType eType, bool fAllowed) { - sendNotification(llformat("unworn %s %s", (fAllowed) ? "legally" : "illegally", LLWearableType::getTypeName(eType).c_str())); + sendNotification(llformat("unworn %s %s", (fAllowed) ? "legally" : "illegally", LLWearableType::getInstance()->getTypeName(eType).c_str())); } // Checked: 2011-03-31 (RLVa-1.3.0f) | Added: RLVa-1.3.0f diff --git a/indra/newview/skins/ansastorm/colors.xml b/indra/newview/skins/ansastorm/colors.xml index 1e740bf20c..a69ba44a78 100644 --- a/indra/newview/skins/ansastorm/colors.xml +++ b/indra/newview/skins/ansastorm/colors.xml @@ -1318,6 +1318,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/indra/newview/skins/default/html/common/equirectangular/eqr_gen.html b/indra/newview/skins/default/html/common/equirectangular/eqr_gen.html new file mode 100644 index 0000000000..2675d37727 --- /dev/null +++ b/indra/newview/skins/default/html/common/equirectangular/eqr_gen.html @@ -0,0 +1,150 @@ + + + + + + + + + + + + + +
UNABLE TO LOAD EQR IMAGE
+
Preview Quality
+ + \ No newline at end of file diff --git a/indra/newview/skins/default/textures/textures.xml b/indra/newview/skins/default/textures/textures.xml index bde3278ada..58d8e61e14 100644 --- a/indra/newview/skins/default/textures/textures.xml +++ b/indra/newview/skins/default/textures/textures.xml @@ -137,7 +137,8 @@ with the same filename but different name - + + @@ -158,6 +159,7 @@ with the same filename but different name + @@ -242,6 +244,11 @@ with the same filename but different name + + + + + diff --git a/indra/newview/skins/default/textures/toolbar_icons/360_capture.png b/indra/newview/skins/default/textures/toolbar_icons/360_capture.png new file mode 100644 index 0000000000..163cebe29f Binary files /dev/null and b/indra/newview/skins/default/textures/toolbar_icons/360_capture.png differ diff --git a/indra/newview/skins/default/textures/toolbar_icons/performance.png b/indra/newview/skins/default/textures/toolbar_icons/performance.png new file mode 100644 index 0000000000..91baf849c8 Binary files /dev/null and b/indra/newview/skins/default/textures/toolbar_icons/performance.png differ diff --git a/indra/newview/skins/default/toolbars.xml b/indra/newview/skins/default/toolbars.xml index 5fa8b9b652..144281f640 100644 --- a/indra/newview/skins/default/toolbars.xml +++ b/indra/newview/skins/default/toolbars.xml @@ -8,6 +8,7 @@ button_alignment="left" button_display_mode="icons_only" button_layout_style="fill"> + diff --git a/indra/newview/skins/default/xui/de/floater_360capture.xml b/indra/newview/skins/default/xui/de/floater_360capture.xml new file mode 100644 index 0000000000..c38cc98288 --- /dev/null +++ b/indra/newview/skins/default/xui/de/floater_360capture.xml @@ -0,0 +1,22 @@ + + + + + Qualität + + + + + + + + + + + + + + + Graphics settings + + + Choose settings for distance, water, lighting and more. + + + + + + Avatars nearby + + + Manage which nearby avatars are fully displayed. + + +Time spent +drawing +avatars + + + 00% + + + + + + Your avatar complexity + + + Be a good citizen. Manage the impact of your avatar + + + + + + Your active HUDs + + + Removing unnecessary HUDs may improve speed. + + +Time spent +drawing +HUDs + + + 00% + + + + + + + + + + diff --git a/indra/newview/skins/default/xui/en/floater_preferences.xml b/indra/newview/skins/default/xui/en/floater_preferences.xml index 253afc9877..f5df673b98 100644 --- a/indra/newview/skins/default/xui/en/floater_preferences.xml +++ b/indra/newview/skins/default/xui/en/floater_preferences.xml @@ -11,16 +11,6 @@ single_instance="true" title="Preferences" width="662"> - - Please verify your email to enable IM to Email by visiting -https://accounts.secondlife.com/change_email/ - - - - Login to change - -