From 4b7710eab2e01c2e8f827b3741caae3fe03b1bbd Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Thu, 16 Jan 2020 20:33:59 -0500 Subject: [PATCH 001/443] DRTVWR-476: Re-encode certain files with non-ASCII chars as UTF8. --- indra/llcommon/StackWalker.cpp | 2 +- indra/newview/licenses-linux.txt | 2 +- indra/newview/licenses-mac.txt | 2 +- indra/newview/licenses-win32.txt | 8 ++++---- indra/newview/tests/gpus_results.txt | 14 +++++++------- indra/newview/tests/gpus_seen.txt | 16 ++++++++-------- 6 files changed, 22 insertions(+), 22 deletions(-) diff --git a/indra/llcommon/StackWalker.cpp b/indra/llcommon/StackWalker.cpp index c0d3104099..40eff0ea7b 100644 --- a/indra/llcommon/StackWalker.cpp +++ b/indra/llcommon/StackWalker.cpp @@ -657,7 +657,7 @@ private: pGMI = (tGMI) GetProcAddress( hPsapi, "GetModuleInformation" ); if ( (pEPM == NULL) || (pGMFNE == NULL) || (pGMBN == NULL) || (pGMI == NULL) ) { - // we couldnt find all functions + // we couldn´t find all functions FreeLibrary(hPsapi); return FALSE; } diff --git a/indra/newview/licenses-linux.txt b/indra/newview/licenses-linux.txt index b43c402e64..388bb54541 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® 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..38db59354c 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® 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..e0d6dc478b 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® 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/tests/gpus_results.txt b/indra/newview/tests/gpus_results.txt index 106593afd5..c3e2db76a3 100644 --- a/indra/newview/tests/gpus_results.txt +++ b/indra/newview/tests/gpus_results.txt @@ -1487,8 +1487,8 @@ Intel Open Source Technology Center Mesa DRI Intel(R) Sandybridge Desktop Intel Open Source Technology Center Mesa DRI Intel(R) Sandybridge Desktop x86/MMX/SSE2 unsupported 1 1 3 Mesa Intel Open Source Technology Center Mesa DRI Intel(R) Sandybridge Mobile unsupported 1 1 3 Mesa Intel Open Source Technology Center Mesa DRI Intel(R) Sandybridge Mobile x86/MMX/SSE2 unsupported 1 1 3 Mesa -Intel Open Source Technology Center Mesa DRI Mobile Intel GM45 Express Chipset unsupported 1 1 3 Mesa -Intel Open Source Technology Center Mesa DRI Mobile Intel GM45 Express Chipset x86/MMX/SSE2 unsupported 1 1 3 Mesa +Intel Open Source Technology Center Mesa DRI Mobile Intelå¨ GM45 Express Chipset unsupported 1 1 3 Mesa +Intel Open Source Technology Center Mesa DRI Mobile Intelå¨ GM45 Express Chipset x86/MMX/SSE2 unsupported 1 1 3 Mesa Intel Pineview supported 0 1 1.4 Intel Pineview Intel Q45/Q43 supported 1 1 2.1 Intel Q45/Q43 Intel Royal BNA Driver unsupported 0 0 0 Intel Royal BNA @@ -3012,11 +3012,11 @@ Tungsten Graphics, Inc Mesa DRI Intel(R) Sandybridge Mobile x86/MMX/SSE2 Tungsten Graphics, Inc Mesa DRI Intel(R) Sandybridge Mobile GEM 20100330 DEVELOPMENT x86/MMX/SSE2 unsupported 1 1 3 Mesa Tungsten Graphics, Inc Mesa DRI Intel(R) Sandybridge Mobile x86/MMX/SSE2 unsupported 1 1 3 Mesa Tungsten Graphics, Inc Mesa DRI Intel(R) Sandybridge Server unsupported 1 1 3 Mesa -Tungsten Graphics, Inc Mesa DRI Mobile Intel GM45 Express Chipset unsupported 1 1 3 Mesa -Tungsten Graphics, Inc Mesa DRI Mobile Intel GM45 Express Chipset GEM 20091221 2009Q4 supported 1 1 2.1 Intel Q45/Q43 -Tungsten Graphics, Inc Mesa DRI Mobile Intel GM45 Express Chipset GEM 20091221 2009Q4 x86/MMX/SSE2 supported 1 1 2.1 Intel Q45/Q43 -Tungsten Graphics, Inc Mesa DRI Mobile Intel GM45 Express Chipset GEM 20100330 DEVELOPMENT x86/MMX unsupported 1 1 3 Mesa -Tungsten Graphics, Inc Mesa DRI Mobile Intel GM45 Express Chipset x86/MMX/SSE2 unsupported 1 1 3 Mesa +Tungsten Graphics, Inc Mesa DRI Mobile Intelå¨ GM45 Express Chipset unsupported 1 1 3 Mesa +Tungsten Graphics, Inc Mesa DRI Mobile Intelå¨ GM45 Express Chipset GEM 20091221 2009Q4 supported 1 1 2.1 Intel Q45/Q43 +Tungsten Graphics, Inc Mesa DRI Mobile Intelå¨ GM45 Express Chipset GEM 20091221 2009Q4 x86/MMX/SSE2 supported 1 1 2.1 Intel Q45/Q43 +Tungsten Graphics, Inc Mesa DRI Mobile Intelå¨ GM45 Express Chipset GEM 20100330 DEVELOPMENT x86/MMX unsupported 1 1 3 Mesa +Tungsten Graphics, Inc Mesa DRI Mobile Intelå¨ GM45 Express Chipset x86/MMX/SSE2 unsupported 1 1 3 Mesa Tungsten Graphics, Inc. Mesa DRI R100 (RS200 4437) x86/MMX/SSE2 NO-TCL DRI2 unsupported 1 1 3 Mesa Tungsten Graphics, Inc. Mesa DRI R100 (RV200 4C57) TCL DRI2 unsupported 1 1 3 Mesa Tungsten Graphics, Inc. Mesa DRI R100 (RV200 4C57) x86/MMX/SSE2 TCL DRI2 unsupported 1 1 3 Mesa diff --git a/indra/newview/tests/gpus_seen.txt b/indra/newview/tests/gpus_seen.txt index a417cb3761..f7c733daa2 100644 --- a/indra/newview/tests/gpus_seen.txt +++ b/indra/newview/tests/gpus_seen.txt @@ -1954,8 +1954,8 @@ Intel Open Source Technology Center Mesa DRI Intel(R) Sandybridge Desktop x86/MM Intel Open Source Technology Center Mesa DRI Intel(R) Sandybridge Mobile Intel Open Source Technology Center Mesa DRI Intel(R) Sandybridge Mobile x86/MMX/SSE2 Intel Open Source Technology Center Mesa DRI Intel(R) Sandybridge Mobile x86/MMX/SSE2 -Intel Open Source Technology Center Mesa DRI Mobile Intel GM45 Express Chipset -Intel Open Source Technology Center Mesa DRI Mobile Intel GM45 Express Chipset x86/MMX/SSE2 +Intel Open Source Technology Center Mesa DRI Mobile Intelå¨ GM45 Express Chipset +Intel Open Source Technology Center Mesa DRI Mobile Intelå¨ GM45 Express Chipset x86/MMX/SSE2 Intel Pineview Intel Q45/Q43 Intel Royal BNA Driver @@ -4079,12 +4079,12 @@ Tungsten Graphics, Inc Mesa DRI Intel(R) Sandybridge Mobile GEM 20100330 DEVELOP Tungsten Graphics, Inc Mesa DRI Intel(R) Sandybridge Mobile x86/MMX/SSE2 Tungsten Graphics, Inc Mesa DRI Intel(R) Sandybridge Mobile x86/MMX/SSE2 Tungsten Graphics, Inc Mesa DRI Intel(R) Sandybridge Server -Tungsten Graphics, Inc Mesa DRI Mobile Intel GM45 Express Chipset -Tungsten Graphics, Inc Mesa DRI Mobile Intel GM45 Express Chipset GEM 20091221 2009Q4 -Tungsten Graphics, Inc Mesa DRI Mobile Intel GM45 Express Chipset GEM 20091221 2009Q4 x86/MMX/SSE2 -Tungsten Graphics, Inc Mesa DRI Mobile Intel GM45 Express Chipset GEM 20100330 DEVELOPMENT x86/MMX/SSE2 -Tungsten Graphics, Inc Mesa DRI Mobile Intel GM45 Express Chipset x86/MMX/SSE2 -Tungsten Graphics, Inc Mesa DRI Mobile Intel GM45 Express Chipset x86/MMX/SSE2 +Tungsten Graphics, Inc Mesa DRI Mobile Intelå¨ GM45 Express Chipset +Tungsten Graphics, Inc Mesa DRI Mobile Intelå¨ GM45 Express Chipset GEM 20091221 2009Q4 +Tungsten Graphics, Inc Mesa DRI Mobile Intelå¨ GM45 Express Chipset GEM 20091221 2009Q4 x86/MMX/SSE2 +Tungsten Graphics, Inc Mesa DRI Mobile Intelå¨ GM45 Express Chipset GEM 20100330 DEVELOPMENT x86/MMX/SSE2 +Tungsten Graphics, Inc Mesa DRI Mobile Intelå¨ GM45 Express Chipset x86/MMX/SSE2 +Tungsten Graphics, Inc Mesa DRI Mobile Intelå¨ GM45 Express Chipset x86/MMX/SSE2 Tungsten Graphics, Inc. Mesa DRI R100 (RS200 4437) x86/MMX/SSE2 NO-TCL DRI2 Tungsten Graphics, Inc. Mesa DRI R100 (RV200 4C57) TCL DRI2 Tungsten Graphics, Inc. Mesa DRI R100 (RV200 4C57) x86/MMX/SSE2 TCL DRI2 From 87504be07d77911377e8317fa49285cbc8db7ca0 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Thu, 16 Jan 2020 20:49:10 -0500 Subject: [PATCH 002/443] DRTVWR-476: Try again to fix some of the (R) characters as UTF8. --- indra/newview/tests/gpus_results.txt | 14 +++++++------- indra/newview/tests/gpus_seen.txt | 16 ++++++++-------- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/indra/newview/tests/gpus_results.txt b/indra/newview/tests/gpus_results.txt index c3e2db76a3..531f88ebd4 100644 --- a/indra/newview/tests/gpus_results.txt +++ b/indra/newview/tests/gpus_results.txt @@ -1487,8 +1487,8 @@ Intel Open Source Technology Center Mesa DRI Intel(R) Sandybridge Desktop Intel Open Source Technology Center Mesa DRI Intel(R) Sandybridge Desktop x86/MMX/SSE2 unsupported 1 1 3 Mesa Intel Open Source Technology Center Mesa DRI Intel(R) Sandybridge Mobile unsupported 1 1 3 Mesa Intel Open Source Technology Center Mesa DRI Intel(R) Sandybridge Mobile x86/MMX/SSE2 unsupported 1 1 3 Mesa -Intel Open Source Technology Center Mesa DRI Mobile Intelå¨ GM45 Express Chipset unsupported 1 1 3 Mesa -Intel Open Source Technology Center Mesa DRI Mobile Intelå¨ GM45 Express Chipset x86/MMX/SSE2 unsupported 1 1 3 Mesa +Intel Open Source Technology Center Mesa DRI Mobile Intel® GM45 Express Chipset unsupported 1 1 3 Mesa +Intel Open Source Technology Center Mesa DRI Mobile Intel® GM45 Express Chipset x86/MMX/SSE2 unsupported 1 1 3 Mesa Intel Pineview supported 0 1 1.4 Intel Pineview Intel Q45/Q43 supported 1 1 2.1 Intel Q45/Q43 Intel Royal BNA Driver unsupported 0 0 0 Intel Royal BNA @@ -3012,11 +3012,11 @@ Tungsten Graphics, Inc Mesa DRI Intel(R) Sandybridge Mobile x86/MMX/SSE2 Tungsten Graphics, Inc Mesa DRI Intel(R) Sandybridge Mobile GEM 20100330 DEVELOPMENT x86/MMX/SSE2 unsupported 1 1 3 Mesa Tungsten Graphics, Inc Mesa DRI Intel(R) Sandybridge Mobile x86/MMX/SSE2 unsupported 1 1 3 Mesa Tungsten Graphics, Inc Mesa DRI Intel(R) Sandybridge Server unsupported 1 1 3 Mesa -Tungsten Graphics, Inc Mesa DRI Mobile Intelå¨ GM45 Express Chipset unsupported 1 1 3 Mesa -Tungsten Graphics, Inc Mesa DRI Mobile Intelå¨ GM45 Express Chipset GEM 20091221 2009Q4 supported 1 1 2.1 Intel Q45/Q43 -Tungsten Graphics, Inc Mesa DRI Mobile Intelå¨ GM45 Express Chipset GEM 20091221 2009Q4 x86/MMX/SSE2 supported 1 1 2.1 Intel Q45/Q43 -Tungsten Graphics, Inc Mesa DRI Mobile Intelå¨ GM45 Express Chipset GEM 20100330 DEVELOPMENT x86/MMX unsupported 1 1 3 Mesa -Tungsten Graphics, Inc Mesa DRI Mobile Intelå¨ GM45 Express Chipset x86/MMX/SSE2 unsupported 1 1 3 Mesa +Tungsten Graphics, Inc Mesa DRI Mobile Intel® GM45 Express Chipset unsupported 1 1 3 Mesa +Tungsten Graphics, Inc Mesa DRI Mobile Intel® GM45 Express Chipset GEM 20091221 2009Q4 supported 1 1 2.1 Intel Q45/Q43 +Tungsten Graphics, Inc Mesa DRI Mobile Intel® GM45 Express Chipset GEM 20091221 2009Q4 x86/MMX/SSE2 supported 1 1 2.1 Intel Q45/Q43 +Tungsten Graphics, Inc Mesa DRI Mobile Intel® GM45 Express Chipset GEM 20100330 DEVELOPMENT x86/MMX unsupported 1 1 3 Mesa +Tungsten Graphics, Inc Mesa DRI Mobile Intel® GM45 Express Chipset x86/MMX/SSE2 unsupported 1 1 3 Mesa Tungsten Graphics, Inc. Mesa DRI R100 (RS200 4437) x86/MMX/SSE2 NO-TCL DRI2 unsupported 1 1 3 Mesa Tungsten Graphics, Inc. Mesa DRI R100 (RV200 4C57) TCL DRI2 unsupported 1 1 3 Mesa Tungsten Graphics, Inc. Mesa DRI R100 (RV200 4C57) x86/MMX/SSE2 TCL DRI2 unsupported 1 1 3 Mesa diff --git a/indra/newview/tests/gpus_seen.txt b/indra/newview/tests/gpus_seen.txt index f7c733daa2..50facf5de8 100644 --- a/indra/newview/tests/gpus_seen.txt +++ b/indra/newview/tests/gpus_seen.txt @@ -1954,8 +1954,8 @@ Intel Open Source Technology Center Mesa DRI Intel(R) Sandybridge Desktop x86/MM Intel Open Source Technology Center Mesa DRI Intel(R) Sandybridge Mobile Intel Open Source Technology Center Mesa DRI Intel(R) Sandybridge Mobile x86/MMX/SSE2 Intel Open Source Technology Center Mesa DRI Intel(R) Sandybridge Mobile x86/MMX/SSE2 -Intel Open Source Technology Center Mesa DRI Mobile Intelå¨ GM45 Express Chipset -Intel Open Source Technology Center Mesa DRI Mobile Intelå¨ GM45 Express Chipset x86/MMX/SSE2 +Intel Open Source Technology Center Mesa DRI Mobile Intel® GM45 Express Chipset +Intel Open Source Technology Center Mesa DRI Mobile Intel® GM45 Express Chipset x86/MMX/SSE2 Intel Pineview Intel Q45/Q43 Intel Royal BNA Driver @@ -4079,12 +4079,12 @@ Tungsten Graphics, Inc Mesa DRI Intel(R) Sandybridge Mobile GEM 20100330 DEVELOP Tungsten Graphics, Inc Mesa DRI Intel(R) Sandybridge Mobile x86/MMX/SSE2 Tungsten Graphics, Inc Mesa DRI Intel(R) Sandybridge Mobile x86/MMX/SSE2 Tungsten Graphics, Inc Mesa DRI Intel(R) Sandybridge Server -Tungsten Graphics, Inc Mesa DRI Mobile Intelå¨ GM45 Express Chipset -Tungsten Graphics, Inc Mesa DRI Mobile Intelå¨ GM45 Express Chipset GEM 20091221 2009Q4 -Tungsten Graphics, Inc Mesa DRI Mobile Intelå¨ GM45 Express Chipset GEM 20091221 2009Q4 x86/MMX/SSE2 -Tungsten Graphics, Inc Mesa DRI Mobile Intelå¨ GM45 Express Chipset GEM 20100330 DEVELOPMENT x86/MMX/SSE2 -Tungsten Graphics, Inc Mesa DRI Mobile Intelå¨ GM45 Express Chipset x86/MMX/SSE2 -Tungsten Graphics, Inc Mesa DRI Mobile Intelå¨ GM45 Express Chipset x86/MMX/SSE2 +Tungsten Graphics, Inc Mesa DRI Mobile Intel® GM45 Express Chipset +Tungsten Graphics, Inc Mesa DRI Mobile Intel® GM45 Express Chipset GEM 20091221 2009Q4 +Tungsten Graphics, Inc Mesa DRI Mobile Intel® GM45 Express Chipset GEM 20091221 2009Q4 x86/MMX/SSE2 +Tungsten Graphics, Inc Mesa DRI Mobile Intel® GM45 Express Chipset GEM 20100330 DEVELOPMENT x86/MMX/SSE2 +Tungsten Graphics, Inc Mesa DRI Mobile Intel® GM45 Express Chipset x86/MMX/SSE2 +Tungsten Graphics, Inc Mesa DRI Mobile Intel® GM45 Express Chipset x86/MMX/SSE2 Tungsten Graphics, Inc. Mesa DRI R100 (RS200 4437) x86/MMX/SSE2 NO-TCL DRI2 Tungsten Graphics, Inc. Mesa DRI R100 (RV200 4C57) TCL DRI2 Tungsten Graphics, Inc. Mesa DRI R100 (RV200 4C57) x86/MMX/SSE2 TCL DRI2 From a6543d6a3dc1709cc85f86b159e00f612357be80 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Fri, 17 Jan 2020 09:49:12 -0500 Subject: [PATCH 003/443] DRTVWR-476: Never mind UTF8, replace non-ASCII chars with ASCII. --- indra/llcommon/StackWalker.cpp | 2 +- indra/newview/licenses-linux.txt | 2 +- indra/newview/licenses-mac.txt | 2 +- indra/newview/licenses-win32.txt | 6 +++--- indra/newview/tests/gpus_results.txt | 14 +++++++------- indra/newview/tests/gpus_seen.txt | 16 ++++++++-------- 6 files changed, 21 insertions(+), 21 deletions(-) diff --git a/indra/llcommon/StackWalker.cpp b/indra/llcommon/StackWalker.cpp index 40eff0ea7b..a87dad2e75 100644 --- a/indra/llcommon/StackWalker.cpp +++ b/indra/llcommon/StackWalker.cpp @@ -657,7 +657,7 @@ private: pGMI = (tGMI) GetProcAddress( hPsapi, "GetModuleInformation" ); if ( (pEPM == NULL) || (pGMFNE == NULL) || (pGMBN == NULL) || (pGMI == NULL) ) { - // we couldn´t find all functions + // we couldn't find all functions FreeLibrary(hPsapi); return FALSE; } diff --git a/indra/newview/licenses-linux.txt b/indra/newview/licenses-linux.txt index 388bb54541..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 38db59354c..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 e0d6dc478b..90e9b429ab 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. @@ -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/tests/gpus_results.txt b/indra/newview/tests/gpus_results.txt index 531f88ebd4..3b3fb1aeb6 100644 --- a/indra/newview/tests/gpus_results.txt +++ b/indra/newview/tests/gpus_results.txt @@ -1487,8 +1487,8 @@ Intel Open Source Technology Center Mesa DRI Intel(R) Sandybridge Desktop Intel Open Source Technology Center Mesa DRI Intel(R) Sandybridge Desktop x86/MMX/SSE2 unsupported 1 1 3 Mesa Intel Open Source Technology Center Mesa DRI Intel(R) Sandybridge Mobile unsupported 1 1 3 Mesa Intel Open Source Technology Center Mesa DRI Intel(R) Sandybridge Mobile x86/MMX/SSE2 unsupported 1 1 3 Mesa -Intel Open Source Technology Center Mesa DRI Mobile Intel® GM45 Express Chipset unsupported 1 1 3 Mesa -Intel Open Source Technology Center Mesa DRI Mobile Intel® GM45 Express Chipset x86/MMX/SSE2 unsupported 1 1 3 Mesa +Intel Open Source Technology Center Mesa DRI Mobile Intel(R) GM45 Express Chipset unsupported 1 1 3 Mesa +Intel Open Source Technology Center Mesa DRI Mobile Intel(R) GM45 Express Chipset x86/MMX/SSE2 unsupported 1 1 3 Mesa Intel Pineview supported 0 1 1.4 Intel Pineview Intel Q45/Q43 supported 1 1 2.1 Intel Q45/Q43 Intel Royal BNA Driver unsupported 0 0 0 Intel Royal BNA @@ -3012,11 +3012,11 @@ Tungsten Graphics, Inc Mesa DRI Intel(R) Sandybridge Mobile x86/MMX/SSE2 Tungsten Graphics, Inc Mesa DRI Intel(R) Sandybridge Mobile GEM 20100330 DEVELOPMENT x86/MMX/SSE2 unsupported 1 1 3 Mesa Tungsten Graphics, Inc Mesa DRI Intel(R) Sandybridge Mobile x86/MMX/SSE2 unsupported 1 1 3 Mesa Tungsten Graphics, Inc Mesa DRI Intel(R) Sandybridge Server unsupported 1 1 3 Mesa -Tungsten Graphics, Inc Mesa DRI Mobile Intel® GM45 Express Chipset unsupported 1 1 3 Mesa -Tungsten Graphics, Inc Mesa DRI Mobile Intel® GM45 Express Chipset GEM 20091221 2009Q4 supported 1 1 2.1 Intel Q45/Q43 -Tungsten Graphics, Inc Mesa DRI Mobile Intel® GM45 Express Chipset GEM 20091221 2009Q4 x86/MMX/SSE2 supported 1 1 2.1 Intel Q45/Q43 -Tungsten Graphics, Inc Mesa DRI Mobile Intel® GM45 Express Chipset GEM 20100330 DEVELOPMENT x86/MMX unsupported 1 1 3 Mesa -Tungsten Graphics, Inc Mesa DRI Mobile Intel® GM45 Express Chipset x86/MMX/SSE2 unsupported 1 1 3 Mesa +Tungsten Graphics, Inc Mesa DRI Mobile Intel(R) GM45 Express Chipset unsupported 1 1 3 Mesa +Tungsten Graphics, Inc Mesa DRI Mobile Intel(R) GM45 Express Chipset GEM 20091221 2009Q4 supported 1 1 2.1 Intel Q45/Q43 +Tungsten Graphics, Inc Mesa DRI Mobile Intel(R) GM45 Express Chipset GEM 20091221 2009Q4 x86/MMX/SSE2 supported 1 1 2.1 Intel Q45/Q43 +Tungsten Graphics, Inc Mesa DRI Mobile Intel(R) GM45 Express Chipset GEM 20100330 DEVELOPMENT x86/MMX unsupported 1 1 3 Mesa +Tungsten Graphics, Inc Mesa DRI Mobile Intel(R) GM45 Express Chipset x86/MMX/SSE2 unsupported 1 1 3 Mesa Tungsten Graphics, Inc. Mesa DRI R100 (RS200 4437) x86/MMX/SSE2 NO-TCL DRI2 unsupported 1 1 3 Mesa Tungsten Graphics, Inc. Mesa DRI R100 (RV200 4C57) TCL DRI2 unsupported 1 1 3 Mesa Tungsten Graphics, Inc. Mesa DRI R100 (RV200 4C57) x86/MMX/SSE2 TCL DRI2 unsupported 1 1 3 Mesa diff --git a/indra/newview/tests/gpus_seen.txt b/indra/newview/tests/gpus_seen.txt index 50facf5de8..66cbeece97 100644 --- a/indra/newview/tests/gpus_seen.txt +++ b/indra/newview/tests/gpus_seen.txt @@ -1954,8 +1954,8 @@ Intel Open Source Technology Center Mesa DRI Intel(R) Sandybridge Desktop x86/MM Intel Open Source Technology Center Mesa DRI Intel(R) Sandybridge Mobile Intel Open Source Technology Center Mesa DRI Intel(R) Sandybridge Mobile x86/MMX/SSE2 Intel Open Source Technology Center Mesa DRI Intel(R) Sandybridge Mobile x86/MMX/SSE2 -Intel Open Source Technology Center Mesa DRI Mobile Intel® GM45 Express Chipset -Intel Open Source Technology Center Mesa DRI Mobile Intel® GM45 Express Chipset x86/MMX/SSE2 +Intel Open Source Technology Center Mesa DRI Mobile Intel(R) GM45 Express Chipset +Intel Open Source Technology Center Mesa DRI Mobile Intel(R) GM45 Express Chipset x86/MMX/SSE2 Intel Pineview Intel Q45/Q43 Intel Royal BNA Driver @@ -4079,12 +4079,12 @@ Tungsten Graphics, Inc Mesa DRI Intel(R) Sandybridge Mobile GEM 20100330 DEVELOP Tungsten Graphics, Inc Mesa DRI Intel(R) Sandybridge Mobile x86/MMX/SSE2 Tungsten Graphics, Inc Mesa DRI Intel(R) Sandybridge Mobile x86/MMX/SSE2 Tungsten Graphics, Inc Mesa DRI Intel(R) Sandybridge Server -Tungsten Graphics, Inc Mesa DRI Mobile Intel® GM45 Express Chipset -Tungsten Graphics, Inc Mesa DRI Mobile Intel® GM45 Express Chipset GEM 20091221 2009Q4 -Tungsten Graphics, Inc Mesa DRI Mobile Intel® GM45 Express Chipset GEM 20091221 2009Q4 x86/MMX/SSE2 -Tungsten Graphics, Inc Mesa DRI Mobile Intel® GM45 Express Chipset GEM 20100330 DEVELOPMENT x86/MMX/SSE2 -Tungsten Graphics, Inc Mesa DRI Mobile Intel® GM45 Express Chipset x86/MMX/SSE2 -Tungsten Graphics, Inc Mesa DRI Mobile Intel® GM45 Express Chipset x86/MMX/SSE2 +Tungsten Graphics, Inc Mesa DRI Mobile Intel(R) GM45 Express Chipset +Tungsten Graphics, Inc Mesa DRI Mobile Intel(R) GM45 Express Chipset GEM 20091221 2009Q4 +Tungsten Graphics, Inc Mesa DRI Mobile Intel(R) GM45 Express Chipset GEM 20091221 2009Q4 x86/MMX/SSE2 +Tungsten Graphics, Inc Mesa DRI Mobile Intel(R) GM45 Express Chipset GEM 20100330 DEVELOPMENT x86/MMX/SSE2 +Tungsten Graphics, Inc Mesa DRI Mobile Intel(R) GM45 Express Chipset x86/MMX/SSE2 +Tungsten Graphics, Inc Mesa DRI Mobile Intel(R) GM45 Express Chipset x86/MMX/SSE2 Tungsten Graphics, Inc. Mesa DRI R100 (RS200 4437) x86/MMX/SSE2 NO-TCL DRI2 Tungsten Graphics, Inc. Mesa DRI R100 (RV200 4C57) TCL DRI2 Tungsten Graphics, Inc. Mesa DRI R100 (RV200 4C57) x86/MMX/SSE2 TCL DRI2 From 5d32c4272d9e80f3373f12b433895b9b44f6490d Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Fri, 17 Jan 2020 09:53:45 -0500 Subject: [PATCH 004/443] DRTVWR-476: Fix one more stray non-ASCII character. --- indra/newview/licenses-win32.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/indra/newview/licenses-win32.txt b/indra/newview/licenses-win32.txt index 90e9b429ab..98edd35bea 100644 --- a/indra/newview/licenses-win32.txt +++ b/indra/newview/licenses-win32.txt @@ -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. From e10051ca080a02a8db6d66d1d2d1777256290be2 Mon Sep 17 00:00:00 2001 From: Andrey Lihatskiy Date: Thu, 1 Oct 2020 07:23:36 +0300 Subject: [PATCH 005/443] SL-14044 Updated VLC to codeticket version 549888 --- autobuild.xml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/autobuild.xml b/autobuild.xml index eacf11fb0f..3115b32ab6 100644 --- a/autobuild.xml +++ b/autobuild.xml @@ -3260,9 +3260,9 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors archive hash - 5e553a4358203f283c74744aed2fcd8c + b639d0035f4a8c9b4973be428a1b7e61 url - http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/54836/510036/vlc_bin-2.2.8.538966-darwin64-538966.tar.bz2 + http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/69569/671323/vlc_bin-3.0.9.549888-darwin64-549888.tar.bz2 name darwin64 @@ -3284,9 +3284,9 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors archive hash - ca84b7c5f86e702fb35727eed8f0c8c4 + 4f50b0c47daa081dd4fcb83763d5b0b2 url - http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/54958/511725/vlc_bin-2.2.8.538966-windows-538966.tar.bz2 + http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/69567/671314/vlc_bin-3.0.9.549888-windows-549888.tar.bz2 name windows @@ -3296,16 +3296,16 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors archive hash - 93cd88d90cb8aedbed5cd90ff9262409 + c2f8c01fb6c261b72beb07f0c4cd423f url - http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/54954/511718/vlc_bin-2.2.8.538966-windows64-538966.tar.bz2 + http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/69568/671315/vlc_bin-3.0.9.549888-windows64-549888.tar.bz2 name windows64 version - 2.2.8.538966 + 3.0.9.549888 xmlrpc-epi From 1811cdc447bbf7c6dfd186be8592cbda896f0df4 Mon Sep 17 00:00:00 2001 From: Andrey Lihatskiy Date: Thu, 1 Oct 2020 08:44:30 +0300 Subject: [PATCH 006/443] SL-14044 Windows build fix --- indra/media_plugins/libvlc/media_plugin_libvlc.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/indra/media_plugins/libvlc/media_plugin_libvlc.cpp b/indra/media_plugins/libvlc/media_plugin_libvlc.cpp index f7d35b33c2..5d4a488e64 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" From 1a4b66e89cae064184aa89e86a4f2fca2a33f215 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Fri, 16 Oct 2020 19:04:13 +0300 Subject: [PATCH 007/443] SL-14136 Mistake in llfloaterpreference.cpp --- indra/newview/llfloaterpreference.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp index 96094dcf14..e1f0f2aa83 100644 --- a/indra/newview/llfloaterpreference.cpp +++ b/indra/newview/llfloaterpreference.cpp @@ -2486,7 +2486,7 @@ BOOL LLPanelPreference::postBuild() } //////////////////////PanelSetup /////////////////// - 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)); From 89fb672503d9dee4f18b11460f66d6c74ec190fd Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Mon, 19 Oct 2020 21:45:36 +0300 Subject: [PATCH 008/443] SL-13599 Missing bounds checks in deserializer code Pulled in and updated Rider's changes --- indra/llmessage/lldatapacker.cpp | 164 +++++++++++++++++ indra/llmessage/lldatapacker.h | 17 ++ indra/llprimitive/llprimitive.cpp | 291 +++++++++++++++++------------- indra/llprimitive/llprimitive.h | 5 +- 4 files changed, 345 insertions(+), 132 deletions(-) diff --git a/indra/llmessage/lldatapacker.cpp b/indra/llmessage/lldatapacker.cpp index 6cf6af6437..96c1297e0d 100644 --- a/indra/llmessage/lldatapacker.cpp +++ b/indra/llmessage/lldatapacker.cpp @@ -173,6 +173,71 @@ BOOL LLDataPacker::unpackFixed(F32 &value, const char *name, return ok; } +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 //--------------------------------------------------------------------------- @@ -319,6 +384,29 @@ BOOL LLDataPackerBinaryBuffer::unpackU16(U16 &value, const char *name) return success; } +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) { @@ -884,6 +972,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) { @@ -1587,6 +1721,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 5140f56c01..ac28cadbce 100644 --- a/indra/llmessage/lldatapacker.h +++ b/indra/llmessage/lldatapacker.h @@ -60,6 +60,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; @@ -69,6 +74,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. @@ -82,6 +88,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; @@ -94,6 +101,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: @@ -139,6 +147,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); @@ -247,6 +258,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); @@ -375,6 +389,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/llprimitive/llprimitive.cpp b/indra/llprimitive/llprimitive.cpp index 53b83a40d7..3894ae20e0 100644 --- a/indra/llprimitive/llprimitive.cpp +++ b/indra/llprimitive/llprimitive.cpp @@ -1079,50 +1079,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 @@ -1316,47 +1351,42 @@ 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) - { - cur_ptr++; - cur_ptr += unpackTEField(cur_ptr, tec.packed_buffer+tec.size, (U8 *)material_data, 16, tec.face_count, MVT_LLUUID); - } - else + 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 (!unpack_TEField((U8 *)material_data, tec.face_count, cur_ptr, buffer_end, MVT_LLUUID)) { memset(material_data, 0, sizeof(material_data)); } @@ -1375,7 +1405,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]; @@ -1388,20 +1417,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; @@ -1423,24 +1447,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(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]; + U8 material_data[MAX_TES * 16]; + + memset(scale_s, 0, sizeof(scale_s)); + memset(scale_t, 0, sizeof(scale_t)); + memset(offset_s, 0, sizeof(offset_s)); + memset(offset_t, 0, sizeof(offset_t)); + memset(image_rot, 0, sizeof(image_rot)); + memset(bump, 0, sizeof(bump)); + memset(media_flags, 0, sizeof(media_flags)); + memset(glow, 0, sizeof(glow)); S32 size; U32 face_count = 0; @@ -1456,50 +1488,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) - { - cur_ptr++; - cur_ptr += unpackTEField(cur_ptr, packed_buffer+size, (U8 *)material_data, 16, face_count, MVT_LLUUID); - } - else + 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 (!unpack_TEField((U8 *)material_data, face_count, cur_ptr, buffer_end, MVT_LLUUID)) { memset(material_data, 0, sizeof(material_data)); } for (i = 0; i < face_count; i++) { - memcpy(image_ids[i].mData,&image_data[i*16],16); /* Flawfinder: ignore */ material_ids[i].set(&material_data[i * 16]); } 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); @@ -1507,15 +1541,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 b1f8112223..309b18faa9 100644 --- a/indra/llprimitive/llprimitive.h +++ b/indra/llprimitive/llprimitive.h @@ -330,8 +330,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]; @@ -423,7 +423,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 From 701edc36f3ed03c89a563fc25fc661c90fbd0c94 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Tue, 20 Oct 2020 20:24:23 +0300 Subject: [PATCH 009/443] SL-14138 Favorites panel was not responding in some cases --- indra/newview/llfavoritesbar.cpp | 58 +++++++++++++++++++------------- indra/newview/llfavoritesbar.h | 2 +- 2 files changed, 35 insertions(+), 25 deletions(-) diff --git a/indra/newview/llfavoritesbar.cpp b/indra/newview/llfavoritesbar.cpp index 347997a69a..c76920c9ce 100644 --- a/indra/newview/llfavoritesbar.cpp +++ b/indra/newview/llfavoritesbar.cpp @@ -677,8 +677,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() @@ -741,8 +745,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)) @@ -773,28 +782,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; - int rightest_point = getRect().mRight - mMoreTextBox->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 571208aa31..d4a6f7b06b 100644 --- a/indra/newview/llfavoritesbar.h +++ b/indra/newview/llfavoritesbar.h @@ -75,7 +75,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); From a74cadff8369ab5779877af6f1b030e1cc40e961 Mon Sep 17 00:00:00 2001 From: Mnikolenko Productengine Date: Fri, 23 Oct 2020 16:05:31 +0300 Subject: [PATCH 010/443] SL-14149 FIXED The text is displayed black after double-clicking on it --- indra/llui/lltextbase.cpp | 6 ++++++ indra/llui/lltextbase.h | 2 +- indra/llui/lltextbox.cpp | 4 +++- 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/indra/llui/lltextbase.cpp b/indra/llui/lltextbase.cpp index ff72417867..d92f10bdbb 100644 --- a/indra/llui/lltextbase.cpp +++ b/indra/llui/lltextbase.cpp @@ -184,6 +184,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), @@ -1017,6 +1018,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 4e966b7cef..2e2e1b9833 100644 --- a/indra/llui/lltextbase.h +++ b/indra/llui/lltextbase.h @@ -699,7 +699,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 0afd32f332..4dc2a6a597 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() {} From 802b52f3044dfaaec3406d654c091d626955f569 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Tue, 22 Sep 2020 23:38:23 +0300 Subject: [PATCH 011/443] SL-13979 Crash of logging system at LLError::Settings::getInstance() LLSingleton depends onto logging system, having logging system be based on LLSingleton causes crashes and deadlocks --- indra/llcommon/llerror.cpp | 84 +++++++++++++++------------------ indra/llcommon/llerrorcontrol.h | 5 -- indra/llcommon/llsingleton.cpp | 31 +----------- indra/newview/llappviewer.cpp | 6 +-- 4 files changed, 42 insertions(+), 84 deletions(-) diff --git a/indra/llcommon/llerror.cpp b/indra/llcommon/llerror.cpp index 411412c883..f876b8ee4a 100644 --- a/indra/llcommon/llerror.cpp +++ b/indra/llcommon/llerror.cpp @@ -332,12 +332,9 @@ namespace LLError } // huh, that's odd, we should see one or the other prefix -- but don't // try to log unless logging is already initialized - if (is_available()) - { - // in Python, " or ".join(vector) -- but in C++, a PITB - LL_DEBUGS() << "Did not see 'class' or 'struct' prefix on '" - << name << "'" << LL_ENDL; - } + // in Python, " or ".join(vector) -- but in C++, a PITB + LL_DEBUGS() << "Did not see 'class' or 'struct' prefix on '" + << name << "'" << LL_ENDL; return name; #else // neither GCC nor Visual Studio @@ -438,9 +435,12 @@ namespace typedef std::vector Recorders; typedef std::vector CallSiteVector; - class Globals : public LLSingleton + class Globals { - LLSINGLETON(Globals); + public: + static Globals* getInstance(); + protected: + Globals(); public: std::ostringstream messageStream; bool messageStreamInUse; @@ -460,6 +460,16 @@ namespace { } + Globals* Globals::getInstance() + { + // According to C++11 Function-Local Initialization + // of static variables is supposed to be thread safe + // without risk of deadlocks. + static Globals inst; + + return &inst; + } + void Globals::addCallSite(LLError::CallSite& site) { callSites.push_back(&site); @@ -512,14 +522,17 @@ namespace LLError typedef LLPointer SettingsConfigPtr; - class Settings : public LLSingleton + class Settings { - LLSINGLETON(Settings); + public: + static Settings* getInstance(); + protected: + Settings(); public: SettingsConfigPtr getSettingsConfig(); void reset(); - SettingsStoragePtr saveAndReset(); + SettingsStoragePtr saveAndReset(); void restore(SettingsStoragePtr pSettingsStorage); private: @@ -553,6 +566,16 @@ namespace LLError { } + Settings* Settings::getInstance() + { + // 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; + } + SettingsConfigPtr Settings::getSettingsConfig() { return mSettingsConfig; @@ -577,11 +600,6 @@ namespace LLError SettingsConfigPtr newSettingsConfig(dynamic_cast(pSettingsStorage.get())); mSettingsConfig = newSettingsConfig; } - - bool is_available() - { - return Settings::instanceExists() && Globals::instanceExists(); - } } namespace LLError @@ -1028,7 +1046,7 @@ namespace LLError std::pair, Recorders::iterator> findRecorderPos() { - SettingsConfigPtr s = Settings::instance().getSettingsConfig(); + SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig(); // Since we promise to return an iterator, use a classic iterator // loop. auto end{s->mRecorders.end()}; @@ -1071,7 +1089,7 @@ namespace LLError auto found = findRecorderPos(); if (found.first) { - SettingsConfigPtr s = Settings::instance().getSettingsConfig(); + SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig(); s->mRecorders.erase(found.second); } return bool(found.first); @@ -1307,14 +1325,6 @@ namespace LLError return false; } - // If we hit a logging request very late during shutdown processing, - // when either of the relevant LLSingletons has already been deleted, - // DO NOT resurrect them. - if (Settings::wasDeleted() || Globals::wasDeleted()) - { - return false; - } - SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig(); s->mShouldLogCallCounter++; @@ -1353,10 +1363,8 @@ namespace LLError std::ostringstream* Log::out() { LLMutexTrylock lock(getMutex(),5); - // If we hit a logging request very late during shutdown processing, - // when either of the relevant LLSingletons has already been deleted, - // DO NOT resurrect them. - if (lock.isLocked() && ! (Settings::wasDeleted() || Globals::wasDeleted())) + + if (lock.isLocked()) { Globals* g = Globals::getInstance(); @@ -1378,14 +1386,6 @@ namespace LLError return; } - // If we hit a logging request very late during shutdown processing, - // when either of the relevant LLSingletons has already been deleted, - // DO NOT resurrect them. - if (Settings::wasDeleted() || Globals::wasDeleted()) - { - return; - } - if(strlen(out->str().c_str()) < 128) { strcpy(message, out->str().c_str()); @@ -1418,14 +1418,6 @@ namespace LLError return; } - // If we hit a logging request very late during shutdown processing, - // when either of the relevant LLSingletons has already been deleted, - // DO NOT resurrect them. - if (Settings::wasDeleted() || Globals::wasDeleted()) - { - return; - } - Globals* g = Globals::getInstance(); SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig(); diff --git a/indra/llcommon/llerrorcontrol.h b/indra/llcommon/llerrorcontrol.h index bfa2269025..25786d5457 100644 --- a/indra/llcommon/llerrorcontrol.h +++ b/indra/llcommon/llerrorcontrol.h @@ -203,11 +203,6 @@ namespace LLError LL_COMMON_API std::string abbreviateFile(const std::string& filePath); LL_COMMON_API int shouldLogCallCount(); - - // Check whether Globals exists. This should only be used by LLSingleton - // infrastructure to avoid trying to log when our internal LLSingleton is - // unavailable -- circularity ensues. - LL_COMMON_API bool is_available(); }; #endif // LL_LLERRORCONTROL_H diff --git a/indra/llcommon/llsingleton.cpp b/indra/llcommon/llsingleton.cpp index d3d25201b2..83a4b64e8f 100644 --- a/indra/llcommon/llsingleton.cpp +++ b/indra/llcommon/llsingleton.cpp @@ -28,7 +28,7 @@ #include "llsingleton.h" #include "llerror.h" -#include "llerrorcontrol.h" // LLError::is_available() +#include "llerrorcontrol.h" #include "lldependencies.h" #include "llexception.h" #include "llcoros.h" @@ -41,8 +41,6 @@ namespace { void log(LLError::ELevel level, const char* p1, const char* p2, const char* p3, const char* p4); - -bool oktolog(); } // anonymous namespace // Our master list of all LLSingletons is itself an LLSingleton. We used to @@ -279,8 +277,6 @@ void LLSingletonBase::reset_initializing(list_t::size_type size) void LLSingletonBase::MasterList::LockedInitializing::log(const char* verb, const char* name) { - if (oktolog()) - { LL_DEBUGS("LLSingleton") << verb << ' ' << demangle(name) << ';'; if (mList) { @@ -292,7 +288,6 @@ void LLSingletonBase::MasterList::LockedInitializing::log(const char* verb, cons } } LL_ENDL; - } } void LLSingletonBase::capture_dependency() @@ -455,33 +450,11 @@ void LLSingletonBase::deleteAll() /*---------------------------- Logging helpers -----------------------------*/ namespace { -bool oktolog() -{ - // See comments in log() below. - return LLError::is_available(); -} void log(LLError::ELevel level, const char* p1, const char* p2, const char* p3, const char* p4) { - // The is_available() test below ensures that we'll stop logging once - // LLError has been cleaned up. If we had a similar portable test for - // std::cerr, this would be a good place to use it. - - // Check LLError::is_available() because some of LLError's infrastructure - // is itself an LLSingleton. If that LLSingleton has not yet been - // initialized, trying to log will engage LLSingleton machinery... and - // around and around we go. - if (LLError::is_available()) - { - LL_VLOGS(level, "LLSingleton") << p1 << p2 << p3 << p4 << LL_ENDL; - } - else - { - // Caller may be a test program, or something else whose stderr is - // visible to the user. - std::cerr << p1 << p2 << p3 << p4 << std::endl; - } + LL_VLOGS(level, "LLSingleton") << p1 << p2 << p3 << p4 << LL_ENDL; } } // anonymous namespace diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 70b41a0a5f..f58d49ec0a 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -2109,14 +2109,12 @@ bool LLAppViewer::cleanup() // still see above are calls that MUST happen before the generic cleanup // kicks in. - // The logging subsystem depends on an LLSingleton. Any logging after - // LLSingletonBase::deleteAll() won't be recorded. - LL_INFOS() << "Goodbye!" << LL_ENDL; - // This calls every remaining LLSingleton's cleanupSingleton() and // deleteSingleton() methods. LLSingletonBase::deleteAll(); + LL_INFOS() << "Goodbye!" << LL_ENDL; + removeDumpDir(); // return 0; From 95e724f3deb856b0b69a3850ceb938c81d1f0321 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Mon, 26 Oct 2020 21:04:10 +0200 Subject: [PATCH 012/443] SL-14004 Coalesce viewer's LLError::Settings and Globals --- indra/llcommon/llerror.cpp | 265 +++++++++++++++++-------------------- 1 file changed, 122 insertions(+), 143 deletions(-) diff --git a/indra/llcommon/llerror.cpp b/indra/llcommon/llerror.cpp index f876b8ee4a..781c41f3de 100644 --- a/indra/llcommon/llerror.cpp +++ b/indra/llcommon/llerror.cpp @@ -435,6 +435,60 @@ 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; + + 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(), + mShouldLogCallCounter(0) + { + } + + SettingsConfig::~SettingsConfig() + { + mRecorders.clear(); + } + class Globals { public: @@ -449,14 +503,21 @@ namespace 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() : messageStream(), messageStreamInUse(false), - callSites() + callSites(), + mSettingsConfig(new SettingsConfig()) { } @@ -486,120 +547,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(NULL), - 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 @@ -723,7 +695,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); @@ -765,13 +737,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; } @@ -782,72 +754,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; } @@ -892,8 +869,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(); @@ -1020,7 +998,7 @@ namespace LLError { return; } - SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig(); + SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig(); s->mRecorders.push_back(recorder); } @@ -1030,7 +1008,7 @@ namespace LLError { return; } - SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig(); + SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig(); s->mRecorders.erase(std::remove(s->mRecorders.begin(), s->mRecorders.end(), recorder), s->mRecorders.end()); } @@ -1046,7 +1024,7 @@ namespace LLError std::pair, Recorders::iterator> findRecorderPos() { - SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig(); + SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig(); // Since we promise to return an iterator, use a classic iterator // loop. auto end{s->mRecorders.end()}; @@ -1089,7 +1067,7 @@ namespace LLError auto found = findRecorderPos(); if (found.first) { - SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig(); + SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig(); s->mRecorders.erase(found.second); } return bool(found.first); @@ -1187,7 +1165,7 @@ 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; @@ -1325,7 +1303,8 @@ namespace LLError return false; } - SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig(); + Globals *g = Globals::getInstance(); + SettingsConfigPtr s = g->getSettingsConfig(); s->mShouldLogCallCounter++; @@ -1355,7 +1334,7 @@ namespace LLError : false); site.mCached = true; - Globals::getInstance()->addCallSite(site); + g->addCallSite(site); return site.mShouldLog = site.mLevel >= compareLevel; } @@ -1419,7 +1398,7 @@ namespace LLError } Globals* g = Globals::getInstance(); - SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig(); + SettingsConfigPtr s = g->getSettingsConfig(); std::string message = out->str(); if (out == &g->messageStream) @@ -1478,12 +1457,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) @@ -1529,7 +1508,7 @@ namespace LLError int shouldLogCallCount() { - SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig(); + SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig(); return s->mShouldLogCallCounter; } @@ -1707,8 +1686,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; From f930717bacbfd2445e82d71537ccd11c2dd0e9b4 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Fri, 25 Sep 2020 16:26:18 +0300 Subject: [PATCH 013/443] SL-13034 removeMarkerFiles() happens in destructor Depends onto SL-13979 for proper logging --- indra/newview/llappviewer.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index f58d49ec0a..f61f0d9181 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -2100,8 +2100,6 @@ bool LLAppViewer::cleanup() LLError::LLCallStacks::cleanup(); - removeMarkerFiles(); - // It's not at first obvious where, in this long sequence, a generic cleanup // call OUGHT to go. So let's say this: as we migrate cleanup from // explicit hand-placed calls into the generic mechanism, eventually From 9b511e87f5f3d52f430b89aa61860d5409469db7 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Mon, 26 Oct 2020 22:29:54 +0200 Subject: [PATCH 014/443] SL-13560 Water reflections do not reflect everything when ALM is enabled Contribution --- doc/contributions.txt | 3 ++- .../shaders/class1/lighting/lightAlphaMaskNonIndexedF.glsl | 6 +++--- .../class1/lighting/lightFullbrightWaterAlphaMaskF.glsl | 4 ++-- .../lighting/lightFullbrightWaterNonIndexedAlphaMaskF.glsl | 4 +++- .../shaders/class1/lighting/lightWaterAlphaMaskF.glsl | 4 ++-- .../class1/lighting/lightWaterAlphaMaskNonIndexedF.glsl | 4 ++-- 6 files changed, 14 insertions(+), 11 deletions(-) diff --git a/doc/contributions.txt b/doc/contributions.txt index 07a96d8766..28d702b38b 100755 --- a/doc/contributions.txt +++ b/doc/contributions.txt @@ -1347,7 +1347,8 @@ Sovereign Engineer MAINT-7343 SL-11079 OPEN-343 - SL-11625 + SL-11625 + BUG-229030 SpacedOut Frye VWR-34 VWR-45 diff --git a/indra/newview/app_settings/shaders/class1/lighting/lightAlphaMaskNonIndexedF.glsl b/indra/newview/app_settings/shaders/class1/lighting/lightAlphaMaskNonIndexedF.glsl index b768d609f4..d87403c78f 100644 --- a/indra/newview/app_settings/shaders/class1/lighting/lightAlphaMaskNonIndexedF.glsl +++ b/indra/newview/app_settings/shaders/class1/lighting/lightAlphaMaskNonIndexedF.glsl @@ -43,13 +43,13 @@ void default_lighting() { vec4 color = texture2D(diffuseMap,vary_texcoord0.xy); - color *= vertex_color; - if (color.a < minimum_alpha) { discard; } - + + color *= vertex_color; + color.rgb = atmosLighting(color.rgb); color.rgb = scaleSoftClip(color.rgb); diff --git a/indra/newview/app_settings/shaders/class1/lighting/lightFullbrightWaterAlphaMaskF.glsl b/indra/newview/app_settings/shaders/class1/lighting/lightFullbrightWaterAlphaMaskF.glsl index d04cd79f4b..37cac5f437 100644 --- a/indra/newview/app_settings/shaders/class1/lighting/lightFullbrightWaterAlphaMaskF.glsl +++ b/indra/newview/app_settings/shaders/class1/lighting/lightFullbrightWaterAlphaMaskF.glsl @@ -43,13 +43,13 @@ void fullbright_lighting_water() { vec4 color = diffuseLookup(vary_texcoord0.xy); - color.rgb *= vertex_color.rgb; - if (color.a < minimum_alpha) { discard; } + color.rgb *= vertex_color.rgb; + color.rgb = fullbrightAtmosTransport(color.rgb); frag_color = applyWaterFog(color); diff --git a/indra/newview/app_settings/shaders/class1/lighting/lightFullbrightWaterNonIndexedAlphaMaskF.glsl b/indra/newview/app_settings/shaders/class1/lighting/lightFullbrightWaterNonIndexedAlphaMaskF.glsl index 3b9c04b22b..c98db4795c 100644 --- a/indra/newview/app_settings/shaders/class1/lighting/lightFullbrightWaterNonIndexedAlphaMaskF.glsl +++ b/indra/newview/app_settings/shaders/class1/lighting/lightFullbrightWaterNonIndexedAlphaMaskF.glsl @@ -41,13 +41,15 @@ VARYING vec2 vary_texcoord0; void fullbright_lighting_water() { - vec4 color = texture2D(diffuseMap, vary_texcoord0.xy) * vertex_color; + vec4 color = texture2D(diffuseMap, vary_texcoord0.xy); if (color.a < minimum_alpha) { discard; } + color.rgb *= vertex_color.rgb; + color.rgb = fullbrightAtmosTransport(color.rgb); frag_color = applyWaterFog(color); diff --git a/indra/newview/app_settings/shaders/class1/lighting/lightWaterAlphaMaskF.glsl b/indra/newview/app_settings/shaders/class1/lighting/lightWaterAlphaMaskF.glsl index 0916797259..9c89c09573 100644 --- a/indra/newview/app_settings/shaders/class1/lighting/lightWaterAlphaMaskF.glsl +++ b/indra/newview/app_settings/shaders/class1/lighting/lightWaterAlphaMaskF.glsl @@ -41,13 +41,13 @@ void default_lighting_water() { vec4 color = diffuseLookup(vary_texcoord0.xy); - color.rgb *= vertex_color.rgb; - if (color.a < minimum_alpha) { discard; } + color.rgb *= vertex_color.rgb; + color.rgb = atmosLighting(color.rgb); frag_color = applyWaterFog(color); diff --git a/indra/newview/app_settings/shaders/class1/lighting/lightWaterAlphaMaskNonIndexedF.glsl b/indra/newview/app_settings/shaders/class1/lighting/lightWaterAlphaMaskNonIndexedF.glsl index f2a84f1d42..9de7a03180 100644 --- a/indra/newview/app_settings/shaders/class1/lighting/lightWaterAlphaMaskNonIndexedF.glsl +++ b/indra/newview/app_settings/shaders/class1/lighting/lightWaterAlphaMaskNonIndexedF.glsl @@ -43,13 +43,13 @@ void default_lighting_water() { vec4 color = texture2D(diffuseMap,vary_texcoord0.xy); - color.rgb *= vertex_color.rgb; - if (color.a < minimum_alpha) { discard; } + color.rgb *= vertex_color.rgb; + color.rgb = atmosLighting(color.rgb); color = applyWaterFog(color); From 10775e307958aa07b6c9533cf3570b0cfa1e26ff Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Wed, 28 Oct 2020 19:05:14 +0200 Subject: [PATCH 015/443] SL-13599 Don't spam into logs when te has no material ids --- indra/llprimitive/llprimitive.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/indra/llprimitive/llprimitive.cpp b/indra/llprimitive/llprimitive.cpp index 3894ae20e0..01431967ab 100644 --- a/indra/llprimitive/llprimitive.cpp +++ b/indra/llprimitive/llprimitive.cpp @@ -1386,7 +1386,7 @@ S32 LLPrimitive::parseTEMessage(LLMessageSystem* mesgsys, char const* block_name return 0; } - if (!unpack_TEField((U8 *)material_data, tec.face_count, cur_ptr, buffer_end, MVT_LLUUID)) + if (cur_ptr >= buffer_end || !unpack_TEField((U8 *)material_data, tec.face_count, cur_ptr, buffer_end, MVT_LLUUID)) { memset(material_data, 0, sizeof(material_data)); } @@ -1520,7 +1520,7 @@ S32 LLPrimitive::unpackTEMessage(LLDataPacker &dp) return 0; } - if (!unpack_TEField((U8 *)material_data, face_count, cur_ptr, buffer_end, MVT_LLUUID)) + if (cur_ptr >= buffer_end || !unpack_TEField((U8 *)material_data, face_count, cur_ptr, buffer_end, MVT_LLUUID)) { memset(material_data, 0, sizeof(material_data)); } From 6786b9118cda676e1984936a34cd3ed011794b88 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Wed, 28 Oct 2020 20:30:17 +0200 Subject: [PATCH 016/443] SL-13599 Variable should correspond to type --- indra/llprimitive/llprimitive.cpp | 45 +++++++++++++++++++++++++------ 1 file changed, 37 insertions(+), 8 deletions(-) diff --git a/indra/llprimitive/llprimitive.cpp b/indra/llprimitive/llprimitive.cpp index 01431967ab..9ce3da490f 100644 --- a/indra/llprimitive/llprimitive.cpp +++ b/indra/llprimitive/llprimitive.cpp @@ -114,6 +114,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 +{ + material_id_type() + { + memset(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 }; + //static // LEGACY: by default we use the LLVolumeMgr::gVolumeMgr global // TODO -- eliminate this global from the codebase! @@ -1333,9 +1362,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) { @@ -1386,14 +1415,14 @@ S32 LLPrimitive::parseTEMessage(LLMessageSystem* mesgsys, char const* block_name return 0; } - if (cur_ptr >= buffer_end || !unpack_TEField((U8 *)material_data, tec.face_count, cur_ptr, buffer_end, MVT_LLUUID)) + if (cur_ptr >= buffer_end || !unpack_TEField(material_data, tec.face_count, cur_ptr, buffer_end, MVT_LLUUID)) { memset(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; @@ -1463,7 +1492,7 @@ S32 LLPrimitive::unpackTEMessage(LLDataPacker &dp) U8 bump[MAX_TES]; U8 media_flags[MAX_TES]; U8 glow[MAX_TES]; - U8 material_data[MAX_TES * 16]; + material_id_type material_data[MAX_TES]; memset(scale_s, 0, sizeof(scale_s)); memset(scale_t, 0, sizeof(scale_t)); @@ -1520,14 +1549,14 @@ S32 LLPrimitive::unpackTEMessage(LLDataPacker &dp) return 0; } - if (cur_ptr >= buffer_end || !unpack_TEField((U8 *)material_data, face_count, cur_ptr, buffer_end, MVT_LLUUID)) + if (cur_ptr >= buffer_end || !unpack_TEField(material_data, face_count, cur_ptr, buffer_end, MVT_LLUUID)) { memset(material_data, 0, sizeof(material_data)); } for (i = 0; i < face_count; i++) { - material_ids[i].set(&material_data[i * 16]); + material_ids[i].set(&(material_data[i])); } LLColor4 color; From bf28c9b287ad3195662927df708134c7e865eda4 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Wed, 28 Oct 2020 22:49:18 +0200 Subject: [PATCH 017/443] SL-14224 RelWithDebInfo viewer stops with 'assert' when disabling atmospheric shader --- indra/newview/llviewercontrol.cpp | 14 ++++++++++++++ indra/newview/llviewershadermgr.cpp | 2 +- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/indra/newview/llviewercontrol.cpp b/indra/newview/llviewercontrol.cpp index c65431d6f6..625543b814 100644 --- a/indra/newview/llviewercontrol.cpp +++ b/indra/newview/llviewercontrol.cpp @@ -143,6 +143,20 @@ static 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; diff --git a/indra/newview/llviewershadermgr.cpp b/indra/newview/llviewershadermgr.cpp index f108d96320..1a21cfd7db 100644 --- a/indra/newview/llviewershadermgr.cpp +++ b/indra/newview/llviewershadermgr.cpp @@ -457,8 +457,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; From d83f2e56dab87e2448399a02a97fb07e243ea5e6 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Fri, 30 Oct 2020 00:52:06 +0200 Subject: [PATCH 018/443] SL-14201 Fix Altgr in CEF --- autobuild.xml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/autobuild.xml b/autobuild.xml index eacf11fb0f..3dc3a52868 100644 --- a/autobuild.xml +++ b/autobuild.xml @@ -580,9 +580,9 @@ archive hash - e145f8ea99a21712434e0e868d1885dc + f7f5a5b5f6cd35da69a86beb9a5dd083 url - http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/62333/588183/dullahan-1.7.0.202006240858_81.3.10_gb223419_chromium-81.0.4044.138-darwin64-544091.tar.bz2 + http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/71404/690443/dullahan-1.7.0.202010291542_81.3.10_gb223419_chromium-81.0.4044.138-darwin64-551434.tar.bz2 name darwin64 @@ -592,9 +592,9 @@ archive hash - fdbbbfc377e28cba664f2b1c54ea6086 + 550d6a172215282b3941167de62d9154 url - http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/62331/588162/dullahan-1.7.0.202006241556_81.3.10_gb223419_chromium-81.0.4044.138-windows-544091.tar.bz2 + http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/71408/690463/dullahan-1.7.0.202010292249_81.3.10_gb223419_chromium-81.0.4044.138-windows-551434.tar.bz2 name windows @@ -604,16 +604,16 @@ archive hash - d85a32d905b199534e8feafa34b28e39 + 389bccd9d1205fa2fbb0c2c0407dee76 url - http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/62332/588168/dullahan-1.7.0.202006241556_81.3.10_gb223419_chromium-81.0.4044.138-windows64-544091.tar.bz2 + http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/71403/690437/dullahan-1.7.0.202010292241_81.3.10_gb223419_chromium-81.0.4044.138-windows64-551434.tar.bz2 name windows64 version - 1.7.0.202006240858_81.3.10_gb223419_chromium-81.0.4044.138 + 1.7.0.202010292249_81.3.10_gb223419_chromium-81.0.4044.138 elfio From 73303d918465090b8e2a39514f4d9db49d0ff109 Mon Sep 17 00:00:00 2001 From: Mnikolenko Productengine Date: Mon, 2 Nov 2020 19:35:31 +0200 Subject: [PATCH 019/443] SL-14075 Allow bulk download of textures/pictures --- indra/newview/app_settings/settings.xml | 11 ++++++ indra/newview/llinventorybridge.cpp | 36 ++++++++++++++--- indra/newview/llinventoryfunctions.cpp | 31 +++++++++++++++ indra/newview/llinventoryfunctions.h | 2 + indra/newview/llpreviewtexture.cpp | 39 +++++++++++++++++++ indra/newview/llpreviewtexture.h | 1 + .../skins/default/xui/en/menu_inventory.xml | 8 ++++ 7 files changed, 123 insertions(+), 5 deletions(-) diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index 52dc4744f2..96da0743a4 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -12641,6 +12641,17 @@ Value 50 + TextureSaveLocation + + Comment + Current location for bulk saving textures to disk + Persist + 0 + Type + String + Value + + ThrottleBandwidthKBPS Comment diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp index 539d80532c..8fbc3c52ab 100644 --- a/indra/newview/llinventorybridge.cpp +++ b/indra/newview/llinventorybridge.cpp @@ -5469,11 +5469,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")); + } + } + } addLinkReplaceMenuOption(items, disabled_items); hide_context_entries(menu, items, disabled_items); @@ -5491,6 +5500,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(); + } + } + else + { + LL_WARNS() << "You don't have permission to save " << getName() << " to disk." << LL_ENDL; + } + + } else LLItemBridge::performAction(model, action); } diff --git a/indra/newview/llinventoryfunctions.cpp b/indra/newview/llinventoryfunctions.cpp index 646d92b9e1..9f54feb3d7 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" @@ -2444,6 +2445,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(); + } else { std::set::iterator set_iter; @@ -2471,6 +2476,32 @@ 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::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; + LLInvFVBridge* bridge = (LLInvFVBridge*)folder_item->getViewModelItem(); + if(!bridge) continue; + 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 fd106bc2d8..75db1efba8 100644 --- a/indra/newview/llinventoryfunctions.h +++ b/indra/newview/llinventoryfunctions.h @@ -462,6 +462,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); + static const int sConfirmOnDeleteItemsNumber; private: diff --git a/indra/newview/llpreviewtexture.cpp b/indra/newview/llpreviewtexture.cpp index 9d8be4b2fe..303034ca3d 100644 --- a/indra/newview/llpreviewtexture.cpp +++ b/indra/newview/llpreviewtexture.cpp @@ -50,6 +50,7 @@ #include "llviewertexture.h" #include "llviewertexturelist.h" #include "lluictrlfactory.h" +#include "llviewercontrol.h" #include "llviewerwindow.h" #include "lllineeditor.h" @@ -317,6 +318,44 @@ void LLPreviewTexture::saveTextureToFile(const std::vector& filenam 0, TRUE, FALSE, new LLUUID(mItemUUID), &mCallbackTextureList); } + +void LLPreviewTexture::saveMultipleToFile() +{ + std::string texture_location(gSavedSettings.getString("TextureSaveLocation")); + std::string texture_name = getItem()->getName(); + + std::string filepath; + S32 i = 0; + S32 err = 0; + std::string extension(".png"); + 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. + mImage->setLoadedCallback(LLPreviewTexture::onFileLoadedForSave, + 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 ad77d9e118..cc6c7854b6 100644 --- a/indra/newview/llpreviewtexture.h +++ b/indra/newview/llpreviewtexture.h @@ -63,6 +63,7 @@ public: void openToSave(); void saveTextureToFile(const std::vector& filenames); + void saveMultipleToFile(); static void onSaveAsBtn(void* data); diff --git a/indra/newview/skins/default/xui/en/menu_inventory.xml b/indra/newview/skins/default/xui/en/menu_inventory.xml index 9aa84c1bac..71a780bf7e 100644 --- a/indra/newview/skins/default/xui/en/menu_inventory.xml +++ b/indra/newview/skins/default/xui/en/menu_inventory.xml @@ -807,6 +807,14 @@ function="Inventory.DoToSelected" parameter="save_as" /> + + + From 2d04f4feef42e56852eb19cd01eda1a64781db65 Mon Sep 17 00:00:00 2001 From: Ansariel Date: Wed, 4 Nov 2020 15:39:31 +0100 Subject: [PATCH 020/443] Build fix --- indra/newview/llvoavatar.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp index 8fe1ecbb57..0b25d77fbe 100644 --- a/indra/newview/llvoavatar.cpp +++ b/indra/newview/llvoavatar.cpp @@ -10014,13 +10014,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; From 273e5bc44953914e13d95a99159cbaaea827d432 Mon Sep 17 00:00:00 2001 From: Ansariel Date: Wed, 4 Nov 2020 15:40:48 +0100 Subject: [PATCH 021/443] Respect FSTextureDefaultSaveAsFormat debug setting when multi-saving textures --- indra/newview/llpreviewtexture.cpp | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/indra/newview/llpreviewtexture.cpp b/indra/newview/llpreviewtexture.cpp index ec14038b76..53670501cf 100644 --- a/indra/newview/llpreviewtexture.cpp +++ b/indra/newview/llpreviewtexture.cpp @@ -479,6 +479,12 @@ void LLPreviewTexture::saveMultipleToFile() 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; @@ -503,8 +509,20 @@ void LLPreviewTexture::saveMultipleToFile() getWindow()->incBusyCount(); mImage->forceToSaveRawImage(0);//re-fetch the raw image if the old one is removed. - mImage->setLoadedCallback(LLPreviewTexture::onFileLoadedForSavePNG, - 0, TRUE, FALSE, new LLUUID(mItemUUID), &mCallbackTextureList); + // 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 From 0604887a6ef7963a5d97d3c72ecd3f9d2a5d6f96 Mon Sep 17 00:00:00 2001 From: Ansariel Date: Wed, 4 Nov 2020 15:50:08 +0100 Subject: [PATCH 022/443] Better wording since the user selects a folder to save the images to --- indra/newview/skins/default/xui/en/menu_inventory.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/indra/newview/skins/default/xui/en/menu_inventory.xml b/indra/newview/skins/default/xui/en/menu_inventory.xml index 0e7926800d..6239831c94 100644 --- a/indra/newview/skins/default/xui/en/menu_inventory.xml +++ b/indra/newview/skins/default/xui/en/menu_inventory.xml @@ -880,7 +880,7 @@ parameter="save_as" /> Date: Wed, 4 Nov 2020 15:52:18 +0100 Subject: [PATCH 023/443] Update German translation --- indra/newview/skins/default/xui/de/menu_inventory.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/indra/newview/skins/default/xui/de/menu_inventory.xml b/indra/newview/skins/default/xui/de/menu_inventory.xml index 2845a4eba2..4ac5159ce4 100644 --- a/indra/newview/skins/default/xui/de/menu_inventory.xml +++ b/indra/newview/skins/default/xui/de/menu_inventory.xml @@ -110,6 +110,7 @@ + From e95e4e5290dc26c36fa08b788b14a5e9b881fb45 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Wed, 4 Nov 2020 21:35:59 +0200 Subject: [PATCH 024/443] SL-14201 Fix Altgr in CEF #2 --- autobuild.xml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/autobuild.xml b/autobuild.xml index 3dc3a52868..dd619d2145 100644 --- a/autobuild.xml +++ b/autobuild.xml @@ -580,9 +580,9 @@ archive hash - f7f5a5b5f6cd35da69a86beb9a5dd083 + 067190e7540d44993c8ad7aec865250a url - http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/71404/690443/dullahan-1.7.0.202010291542_81.3.10_gb223419_chromium-81.0.4044.138-darwin64-551434.tar.bz2 + https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/71704/693528/dullahan-1.7.0.202011041132_81.3.10_gb223419_chromium-81.0.4044.138-darwin64-551696.tar.bz2 name darwin64 @@ -592,9 +592,9 @@ archive hash - 550d6a172215282b3941167de62d9154 + dd7c6c527629c465ff439f979f22394f url - http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/71408/690463/dullahan-1.7.0.202010292249_81.3.10_gb223419_chromium-81.0.4044.138-windows-551434.tar.bz2 + https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/71702/693519/dullahan-1.7.0.202011041930_81.3.10_gb223419_chromium-81.0.4044.138-windows-551696.tar.bz2 name windows @@ -604,16 +604,16 @@ archive hash - 389bccd9d1205fa2fbb0c2c0407dee76 + 226ab47e31576c200ea0c6171b5f1a61 url - http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/71403/690437/dullahan-1.7.0.202010292241_81.3.10_gb223419_chromium-81.0.4044.138-windows64-551434.tar.bz2 + https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/71703/693520/dullahan-1.7.0.202011041930_81.3.10_gb223419_chromium-81.0.4044.138-windows64-551696.tar.bz2 name windows64 version - 1.7.0.202010292249_81.3.10_gb223419_chromium-81.0.4044.138 + 1.7.0.202011041930_81.3.10_gb223419_chromium-81.0.4044.138 elfio From e76243b920797ece3b3c2838a7185b329bc01026 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Fri, 6 Nov 2020 22:10:07 +0200 Subject: [PATCH 025/443] SL-14276 The L$ balance in viewer is not updated on group creation --- indra/newview/llpanelgroupcreate.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/indra/newview/llpanelgroupcreate.cpp b/indra/newview/llpanelgroupcreate.cpp index 052212dc27..52be75072c 100644 --- a/indra/newview/llpanelgroupcreate.cpp +++ b/indra/newview/llpanelgroupcreate.cpp @@ -45,6 +45,7 @@ #include "llfloaterreg.h" #include "llfloater.h" #include "llgroupmgr.h" +#include "llstatusbar.h" // to re-request balance #include "lltrans.h" #include "llnotificationsutil.h" #include "lluicolortable.h" @@ -117,6 +118,7 @@ void LLPanelGroupCreate::refreshCreatedGroup(const LLUUID& group_id) params["group_id"] = group_id; params["open_tab_name"] = "panel_group_info_sidetray"; LLFloaterSidePanelContainer::showPanel("people", "panel_group_info_sidetray", params); + LLStatusBar::sendMoneyBalanceRequest(); } void LLPanelGroupCreate::addMembershipRow(const std::string &name) From 79ec8a8be4ebf143dfb2487ded13e0498982e6b8 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Mon, 9 Nov 2020 13:22:05 +0200 Subject: [PATCH 026/443] SL-13599 Fixed missing zero --- indra/llprimitive/llprimitive.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/indra/llprimitive/llprimitive.cpp b/indra/llprimitive/llprimitive.cpp index 9ce3da490f..e08b1914e8 100644 --- a/indra/llprimitive/llprimitive.cpp +++ b/indra/llprimitive/llprimitive.cpp @@ -114,7 +114,7 @@ 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 +struct material_id_type // originally from llrendermaterialtable { material_id_type() { @@ -141,7 +141,7 @@ struct material_id_type 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 }; +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 From 46ebe69f328f4f734b01d1cd8bec8da6008078fe Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Tue, 10 Nov 2020 18:18:31 +0200 Subject: [PATCH 027/443] SL-14303 Fix LLWearableType to not spam in logs --- indra/llappearance/llviewervisualparam.cpp | 2 +- indra/llappearance/llwearable.cpp | 6 +- indra/llappearance/llwearabledata.cpp | 5 +- indra/llappearance/llwearabletype.cpp | 115 ++++++--------------- indra/llappearance/llwearabletype.h | 56 +++++++--- indra/newview/llagentwearables.cpp | 9 +- indra/newview/llappearancemgr.cpp | 2 +- indra/newview/llappviewer.cpp | 9 +- indra/newview/llcofwearables.cpp | 2 +- indra/newview/llfloaterlinkreplace.cpp | 2 +- indra/newview/llinventorybridge.cpp | 2 +- indra/newview/llinventoryicon.cpp | 2 +- indra/newview/lloutfitgallery.cpp | 2 +- indra/newview/lloutfitslist.cpp | 2 +- indra/newview/llpaneleditwearable.cpp | 2 +- indra/newview/llpaneloutfitedit.cpp | 11 +- indra/newview/llsidepanelappearance.cpp | 2 +- indra/newview/llviewerinventory.cpp | 2 +- indra/newview/llviewermenu.cpp | 4 +- indra/newview/llviewerwearable.cpp | 4 +- indra/newview/llvoavatar.cpp | 5 +- indra/newview/llvoavatarself.cpp | 9 +- indra/newview/llwearableitemslist.cpp | 2 +- indra/newview/llwearablelist.cpp | 3 +- 24 files changed, 123 insertions(+), 137 deletions(-) diff --git a/indra/llappearance/llviewervisualparam.cpp b/indra/llappearance/llviewervisualparam.cpp index af8394b60c..fb0d12f0af 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 6079913a8e..e8df3d19f6 100644 --- a/indra/llappearance/llwearable.cpp +++ b/indra/llappearance/llwearable.cpp @@ -73,17 +73,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 2bf3b9085b..9cc65dc2ce 100644 --- a/indra/llappearance/llwearabledata.cpp +++ b/indra/llappearance/llwearabledata.cpp @@ -231,10 +231,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); } @@ -244,7 +245,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) { return (getClothingLayerCount() < MAX_CLOTHING_LAYERS); diff --git a/indra/llappearance/llwearabletype.cpp b/indra/llappearance/llwearabletype.cpp index 281060d01d..4ac611b1de 100644 --- a/indra/llappearance/llwearabletype.cpp +++ b/indra/llappearance/llwearabletype.cpp @@ -30,153 +30,98 @@ #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; -}; + 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)); -class LLWearableDictionary : public LLParamSingleton, - public LLDictionary -{ - LLSINGLETON(LLWearableDictionary, LLWearableType&); -}; + addEntry(LLWearableType::WT_PHYSICS, new WearableEntry(trans, "physics", "New Physics", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_PHYSICS, TRUE, TRUE)); -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_PHYSICS, new WearableEntry(wtype, "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..c83f03e621 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,53 @@ 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; //keep mLabel for backward compatibility + LLInventoryType::EIconName mIconName; + BOOL mDisableCameraSwitch; + BOOL mAllowMultiwear; + }; + + class LLWearableDictionary : public LLDictionary + { + public: + LLWearableDictionary(LLTranslationBridge::ptr_t& trans); + ~LLWearableDictionary() {} + }; + + LLWearableDictionary mDictionary; }; #endif // LL_LLWEARABLETYPE_H diff --git a/indra/newview/llagentwearables.cpp b/indra/newview/llagentwearables.cpp index 2411f0f86d..45e76ff90b 100644 --- a/indra/newview/llagentwearables.cpp +++ b/indra/newview/llagentwearables.cpp @@ -1056,13 +1056,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); } @@ -1082,7 +1083,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); @@ -1169,7 +1170,7 @@ void LLAgentWearables::setWearableItem(LLInventoryItem* new_item, LLViewerWearab 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; } @@ -1601,7 +1602,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); } diff --git a/indra/newview/llappearancemgr.cpp b/indra/newview/llappearancemgr.cpp index 168b8eb47a..ef6c85b73b 100644 --- a/indra/newview/llappearancemgr.cpp +++ b/indra/newview/llappearancemgr.cpp @@ -1021,7 +1021,7 @@ 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) + LL_DEBUGS() << "Wearable " << LLWearableType::getInstance()->getTypeLabel(type) << " could not be downloaded. Replaced inventory item with default wearable." << LL_ENDL; LLViewerWearable* wearable = LLWearableList::instance().createNewWearable(type, gAgentAvatarp); diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index f61f0d9181..874482b9ec 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -775,10 +775,6 @@ bool LLAppViewer::init() // Start of the application // - // initialize LLWearableType translation bridge. - // Memory will be cleaned up in ::cleanupClass() - LLWearableType::initParamSingleton(new LLUITranslationBridge()); - // initialize the LLSettingsType translation bridge. LLTranslationBridge::ptr_t trans = std::make_shared(); LLSettingsType::initClass(trans); @@ -800,9 +796,14 @@ bool LLAppViewer::init() // init_default_trans_args(); + // inits from settings.xml and from strings.xml if (!initConfiguration()) return false; + // initialize LLWearableType translation bridge. + // Will immediately use LLTranslationBridge to init LLWearableDictionary + LLWearableType::initParamSingleton(trans); + LL_INFOS("InitInfo") << "Configuration initialized." << LL_ENDL ; //set the max heap size. diff --git a/indra/newview/llcofwearables.cpp b/indra/newview/llcofwearables.cpp index 1caefd58ab..dc80eb4487 100644 --- a/indra/newview/llcofwearables.cpp +++ b/indra/newview/llcofwearables.cpp @@ -74,7 +74,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/llfloaterlinkreplace.cpp b/indra/newview/llfloaterlinkreplace.cpp index 595d584799..8ee7a72055 100644 --- a/indra/newview/llfloaterlinkreplace.cpp +++ b/indra/newview/llfloaterlinkreplace.cpp @@ -162,7 +162,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/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp index 8fbc3c52ab..50fe88174b 100644 --- a/indra/newview/llinventorybridge.cpp +++ b/indra/newview/llinventorybridge.cpp @@ -6825,7 +6825,7 @@ void LLWearableBridge::buildContextMenu(LLMenuGL& menu, U32 flags) disabled_items.push_back(std::string("Wearable Edit")); } - if (LLWearableType::getAllowMultiwear(mWearableType)) + if (LLWearableType::getInstance()->getAllowMultiwear(mWearableType)) { items.push_back(std::string("Wearable Add")); if (!gAgentWearables.canAddWearable(mWearableType)) diff --git a/indra/newview/llinventoryicon.cpp b/indra/newview/llinventoryicon.cpp index 81c001b8bd..44e493fdf4 100644 --- a/indra/newview/llinventoryicon.cpp +++ b/indra/newview/llinventoryicon.cpp @@ -196,7 +196,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/lloutfitgallery.cpp b/indra/newview/lloutfitgallery.cpp index 272e7ae351..ca7bd8cb2c 100644 --- a/indra/newview/lloutfitgallery.cpp +++ b/indra/newview/lloutfitgallery.cpp @@ -893,7 +893,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 71ab826e1c..a71432e314 100644 --- a/indra/newview/lloutfitslist.cpp +++ b/indra/newview/lloutfitslist.cpp @@ -1210,7 +1210,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 c601a6c210..be11a4a9f3 100644 --- a/indra/newview/llpaneleditwearable.cpp +++ b/indra/newview/llpaneleditwearable.cpp @@ -1276,7 +1276,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/llpaneloutfitedit.cpp b/indra/newview/llpaneloutfitedit.cpp index 1d87aa6f5d..9828e14262 100644 --- a/indra/newview/llpaneloutfitedit.cpp +++ b/indra/newview/llpaneloutfitedit.cpp @@ -97,7 +97,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; @@ -173,7 +173,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; @@ -188,19 +188,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/llsidepanelappearance.cpp b/indra/newview/llsidepanelappearance.cpp index 6e2b4a00fc..81b67134d2 100644 --- a/indra/newview/llsidepanelappearance.cpp +++ b/indra/newview/llsidepanelappearance.cpp @@ -204,7 +204,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/llviewerinventory.cpp b/indra/newview/llviewerinventory.cpp index d0cbd1181b..b2ce9059ce 100644 --- a/indra/newview/llviewerinventory.cpp +++ b/indra/newview/llviewerinventory.cpp @@ -1851,7 +1851,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/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index e6bd20b58f..efcf5b4730 100644 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -8441,7 +8441,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) return LLAgentWearables::selfHasWearable(type); return false; @@ -8457,7 +8457,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)) diff --git a/indra/newview/llviewerwearable.cpp b/indra/newview/llviewerwearable.cpp index 2d7a0f920f..ebb31f9453 100644 --- a/indra/newview/llviewerwearable.cpp +++ b/indra/newview/llviewerwearable.cpp @@ -563,7 +563,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 @@ -589,7 +589,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/llvoavatar.cpp b/indra/newview/llvoavatar.cpp index 0aee4a3398..603af7e5cc 100644 --- a/indra/newview/llvoavatar.cpp +++ b/indra/newview/llvoavatar.cpp @@ -8734,7 +8734,7 @@ void dump_visual_param(apr_file_t* file, LLVisualParam* viewer_param, F32 value) 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()); } @@ -9508,6 +9508,7 @@ void LLVOAvatar::dumpArchetypeXML(const std::string& prefix, bool group_by_weara std::string outfilename = get_sequential_numbered_file_name(outprefix,".xml"); LLAPRFile outfile; + LLWearableType *wr_inst = LLWearableType::getInstance(); std::string fullpath = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,outfilename); if (APR_SUCCESS == outfile.open(fullpath, LL_APR_WB )) { @@ -9524,7 +9525,7 @@ void LLVOAvatar::dumpArchetypeXML(const std::string& prefix, bool group_by_weara { 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()) diff --git a/indra/newview/llvoavatarself.cpp b/indra/newview/llvoavatarself.cpp index aea12380e8..c0f063e54a 100644 --- a/indra/newview/llvoavatarself.cpp +++ b/indra/newview/llvoavatarself.cpp @@ -2030,6 +2030,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 = LLAvatarAppearanceDictionary::getInstance()->getBakedTextures().begin(); baked_iter != LLAvatarAppearanceDictionary::getInstance()->getBakedTextures().end(); @@ -2053,7 +2054,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) { @@ -2108,6 +2109,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)); @@ -2131,7 +2133,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); @@ -2838,9 +2840,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/llwearableitemslist.cpp b/indra/newview/llwearableitemslist.cpp index e7bbee5efd..0333765af2 100644 --- a/indra/newview/llwearableitemslist.cpp +++ b/indra/newview/llwearableitemslist.cpp @@ -949,7 +949,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 b61fbbd073..b07905629a 100644 --- a/indra/newview/llwearablelist.cpp +++ b/indra/newview/llwearablelist.cpp @@ -241,7 +241,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 uses default translation + std::string name = LLTrans::getString( LLWearableType::getInstance()->getTypeDefaultNewName(wearable->getType()) ); wearable->setName( name ); LLPermissions perm; From 94be1ab38f7c061658af766b3a39283c4d19bbf7 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Tue, 10 Nov 2020 22:05:25 +0200 Subject: [PATCH 028/443] SL-14209 Saving notecard in object sometimes erases all content --- indra/newview/llpreviewnotecard.cpp | 38 ++++++++++++++++++++++++++++- indra/newview/llpreviewnotecard.h | 8 +++++- 2 files changed, 44 insertions(+), 2 deletions(-) diff --git a/indra/newview/llpreviewnotecard.cpp b/indra/newview/llpreviewnotecard.cpp index 7ef0ef0e8b..75644dce11 100644 --- a/indra/newview/llpreviewnotecard.cpp +++ b/indra/newview/llpreviewnotecard.cpp @@ -232,6 +232,7 @@ void LLPreviewNotecard::loadAsset() if (!editor) return; + bool fail = false; if(item) { @@ -314,7 +315,31 @@ void LLPreviewNotecard::loadAsset() getChildView("Delete")->setEnabled(TRUE); } } - else + else if (mObjectUUID.notNull() && mItemUUID.notNull()) + { + LLViewerObject* objectp = gObjectList.findObject(mObjectUUID); + if (objectp && (objectp->isInventoryPending() || objectp->isInventoryDirty())) + { + // It's a notecard in object's inventory and we failed to get it because inventory is not up to date. + // Subscribe for callback and retry at inventoryChanged() + registerVOInventoryListener(objectp, NULL); //removes previous listener + + if (objectp->isInventoryDirty()) + { + objectp->requestInventory(); + } + } + else + { + fail = true; + } + } + else + { + fail = true; + } + + if (fail) { editor->setText(LLStringUtil::null); editor->makePristine(); @@ -599,6 +624,17 @@ void LLPreviewNotecard::syncExternal() } } +/*virtual*/ +void LLPreviewNotecard::inventoryChanged(LLViewerObject* object, + LLInventoryObject::object_list_t* inventory, + S32 serial_num, + void* user_data) +{ + removeVOInventoryListener(); + loadAsset(); +} + + void LLPreviewNotecard::deleteNotecard() { LLNotificationsUtil::add("DeleteNotecard", LLSD(), LLSD(), boost::bind(&LLPreviewNotecard::handleConfirmDeleteDialog,this, _1, _2)); diff --git a/indra/newview/llpreviewnotecard.h b/indra/newview/llpreviewnotecard.h index d9c14815c1..3a706b8645 100644 --- a/indra/newview/llpreviewnotecard.h +++ b/indra/newview/llpreviewnotecard.h @@ -31,6 +31,7 @@ #include "llassetstorage.h" #include "llpreviewscript.h" #include "lliconctrl.h" +#include "llvoinventorylistener.h" //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Class LLPreviewNotecard @@ -41,7 +42,7 @@ class LLViewerTextEditor; class LLButton; -class LLPreviewNotecard : public LLPreview +class LLPreviewNotecard : public LLPreview, public LLVOInventoryListener { public: LLPreviewNotecard(const LLSD& key); @@ -75,6 +76,11 @@ public: void syncExternal(); + void inventoryChanged(LLViewerObject* object, + LLInventoryObject::object_list_t* inventory, + S32 serial_num, + void* user_data) override; + protected: void updateTitleButtons() override; From b1f84f13a8a1d0404e4593ac413b66af8d135f40 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Wed, 11 Nov 2020 23:20:45 +0200 Subject: [PATCH 029/443] SL-14201 pulled in updated dullahan branch (after merge from D507) --- autobuild.xml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/autobuild.xml b/autobuild.xml index dd619d2145..bf7d1b1282 100644 --- a/autobuild.xml +++ b/autobuild.xml @@ -580,9 +580,9 @@ archive hash - 067190e7540d44993c8ad7aec865250a + b50d355c1c7088cafe5e12d31f1fb07f url - https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/71704/693528/dullahan-1.7.0.202011041132_81.3.10_gb223419_chromium-81.0.4044.138-darwin64-551696.tar.bz2 + https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/72181/697551/dullahan-1.7.0.202011111255_81.3.10_gb223419_chromium-81.0.4044.138-darwin64-552103.tar.bz2 name darwin64 @@ -592,9 +592,9 @@ archive hash - dd7c6c527629c465ff439f979f22394f + 0a52a79ad9a182529f7856f78bf4a96f url - https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/71702/693519/dullahan-1.7.0.202011041930_81.3.10_gb223419_chromium-81.0.4044.138-windows-551696.tar.bz2 + https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/72199/697588/dullahan-1.7.0.202011112115_81.3.10_gb223419_chromium-81.0.4044.138-windows-552103.tar.bz2 name windows @@ -604,16 +604,16 @@ archive hash - 226ab47e31576c200ea0c6171b5f1a61 + 715fe1bad3ba216508648b5763ea0404 url - https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/71703/693520/dullahan-1.7.0.202011041930_81.3.10_gb223419_chromium-81.0.4044.138-windows64-551696.tar.bz2 + https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/72196/697581/dullahan-1.7.0.202011112112_81.3.10_gb223419_chromium-81.0.4044.138-windows64-552103.tar.bz2 name windows64 version - 1.7.0.202011041930_81.3.10_gb223419_chromium-81.0.4044.138 + 1.7.0.202011112112_81.3.10_gb223419_chromium-81.0.4044.138 elfio From 6397badddd03f28a62b3f93b2653a2c0193114bf Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Fri, 13 Nov 2020 14:58:14 +0200 Subject: [PATCH 030/443] SL-14303 Wearable type label should contain translated intead of default string Startup has two initStrings calls, only after second one LLtrans will return properly translated calls, but we don't want 'translated' for logging, so modified logging to not use getTypeLabel. --- indra/llappearance/llwearabletype.h | 2 +- indra/newview/llappearancemgr.cpp | 6 +++--- indra/newview/llappviewer.cpp | 8 ++++---- indra/newview/llwearablelist.cpp | 3 +-- 4 files changed, 9 insertions(+), 10 deletions(-) diff --git a/indra/llappearance/llwearabletype.h b/indra/llappearance/llwearabletype.h index c83f03e621..793a33cc87 100644 --- a/indra/llappearance/llwearabletype.h +++ b/indra/llappearance/llwearabletype.h @@ -99,7 +99,7 @@ private: } const LLAssetType::EType mAssetType; const std::string mLabel; - const std::string mDefaultNewName; //keep mLabel for backward compatibility + const std::string mDefaultNewName; LLInventoryType::EIconName mIconName; BOOL mDisableCameraSwitch; BOOL mAllowMultiwear; diff --git a/indra/newview/llappearancemgr.cpp b/indra/newview/llappearancemgr.cpp index 5ceeb65d0e..97a0c2f1a7 100644 --- a/indra/newview/llappearancemgr.cpp +++ b/indra/newview/llappearancemgr.cpp @@ -957,7 +957,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); @@ -1021,8 +1021,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::getInstance()->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. diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index e8466610d2..e71aebb93b 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -802,10 +802,6 @@ bool LLAppViewer::init() if (!initConfiguration()) return false; - // initialize LLWearableType translation bridge. - // Will immediately use LLTranslationBridge to init LLWearableDictionary - LLWearableType::initParamSingleton(trans); - LL_INFOS("InitInfo") << "Configuration initialized." << LL_ENDL ; //set the max heap size. @@ -869,6 +865,10 @@ bool LLAppViewer::init() // Setup LLTrans after LLUI::initClass has been called. initStrings(); + // initialize LLWearableType translation bridge. + // Will immediately use LLTranslationBridge to init LLWearableDictionary + LLWearableType::initParamSingleton(trans); + // Setup notifications after LLUI::initClass() has been called. LLNotifications::instance(); LL_INFOS("InitInfo") << "Notifications initialized." << LL_ENDL ; diff --git a/indra/newview/llwearablelist.cpp b/indra/newview/llwearablelist.cpp index b07905629a..00f8bace70 100644 --- a/indra/newview/llwearablelist.cpp +++ b/indra/newview/llwearablelist.cpp @@ -241,8 +241,7 @@ LLViewerWearable* LLWearableList::createNewWearable( LLWearableType::EType type, LLViewerWearable *wearable = generateNewWearable(); wearable->setType( type, avatarp ); - // LLWearableType has pre-translated getTypeLabel(), but it uses default translation - std::string name = LLTrans::getString( LLWearableType::getInstance()->getTypeDefaultNewName(wearable->getType()) ); + std::string name = LLWearableType::getInstance()->getTypeLabel(wearable->getType()); wearable->setName( name ); LLPermissions perm; From 0812d81e7b64ef80f7ca832f7110f43f1ce9ff33 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Mon, 16 Nov 2020 22:06:17 +0200 Subject: [PATCH 031/443] SL-13287 Removed unused hack --- indra/newview/lltoolpie.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/indra/newview/lltoolpie.cpp b/indra/newview/lltoolpie.cpp index 864ce09430..f98f9c69f2 100644 --- a/indra/newview/lltoolpie.cpp +++ b/indra/newview/lltoolpie.cpp @@ -1109,8 +1109,6 @@ BOOL LLToolPie::handleTooltipObject( LLViewerObject* hover_object, std::string l final_name = LLTrans::getString("TooltipPerson");; } - // *HACK: We may select this object, so pretend it was clicked - mPick = mHoverPick; LLInspector::Params p; p.fillFrom(LLUICtrlFactory::instance().getDefaultParams()); p.message(final_name); @@ -1222,8 +1220,6 @@ BOOL LLToolPie::handleTooltipObject( LLViewerObject* hover_object, std::string l if (show_all_object_tips || needs_tip) { - // We may select this object, so pretend it was clicked - mPick = mHoverPick; LLInspector::Params p; p.fillFrom(LLUICtrlFactory::instance().getDefaultParams()); p.message(tooltip_msg); From 52c0776afdcd75ba8ebadc6b45d8611564e3b833 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Mon, 16 Nov 2020 22:11:19 +0200 Subject: [PATCH 032/443] SL-14340 Fix crash on llerror's recorders --- indra/llcommon/llerror.cpp | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/indra/llcommon/llerror.cpp b/indra/llcommon/llerror.cpp index 781c41f3de..012ec08f07 100644 --- a/indra/llcommon/llerror.cpp +++ b/indra/llcommon/llerror.cpp @@ -458,6 +458,7 @@ namespace LLError::TimeFunction mTimeFunction; Recorders mRecorders; + LLMutex mRecorderMutex; int mShouldLogCallCounter; @@ -480,6 +481,7 @@ namespace mCrashFunction(NULL), mTimeFunction(NULL), mRecorders(), + mRecorderMutex(), mShouldLogCallCounter(0) { } @@ -999,6 +1001,7 @@ namespace LLError return; } SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig(); + LLMutexLock lock(&s->mRecorderMutex); s->mRecorders.push_back(recorder); } @@ -1009,6 +1012,7 @@ namespace LLError return; } SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig(); + LLMutexLock lock(&s->mRecorderMutex); s->mRecorders.erase(std::remove(s->mRecorders.begin(), s->mRecorders.end(), recorder), s->mRecorders.end()); } @@ -1020,11 +1024,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 = Globals::getInstance()->getSettingsConfig(); // Since we promise to return an iterator, use a classic iterator // loop. auto end{s->mRecorders.end()}; @@ -1055,7 +1060,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 @@ -1064,10 +1071,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 = Globals::getInstance()->getSettingsConfig(); s->mRecorders.erase(found.second); } return bool(found.first); @@ -1168,7 +1176,8 @@ namespace 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) From b3043314344a190a3a8154614cbc4f690f64f335 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Tue, 17 Nov 2020 21:16:04 +0200 Subject: [PATCH 033/443] SL-14283 When updater is missing, viewer fails to launch silently --- indra/newview/llappviewer.cpp | 28 +++++++++++++++---- .../skins/default/xui/en/notifications.xml | 4 +++ 2 files changed, 27 insertions(+), 5 deletions(-) diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index e71aebb93b..ad91d6167b 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -1171,14 +1171,18 @@ bool LLAppViewer::init() // Because it's the updater, it MUST persist beyond the lifespan of the // viewer itself. updater.autokill = false; + std::string updater_file; #if LL_WINDOWS - updater.executable = gDirUtilp->getExpandedFilename(LL_PATH_EXECUTABLE, "SLVersionChecker.exe"); + updater_file = "SLVersionChecker.exe"; + updater.executable = gDirUtilp->getExpandedFilename(LL_PATH_EXECUTABLE, updater_file); #elif LL_DARWIN // explicitly run the system Python interpreter on SLVersionChecker.py updater.executable = "python"; - updater.args.add(gDirUtilp->add(gDirUtilp->getAppRODataDir(), "updater", "SLVersionChecker.py")); + updater_file = "SLVersionChecker.py"; + updater.args.add(gDirUtilp->add(gDirUtilp->getAppRODataDir(), "updater", updater_file)); #else - updater.executable = gDirUtilp->getExpandedFilename(LL_PATH_EXECUTABLE, "SLVersionChecker"); + updater_file = "SLVersionChecker"; + updater.executable = gDirUtilp->getExpandedFilename(LL_PATH_EXECUTABLE, updater_file); #endif // add LEAP mode command-line argument to whichever of these we selected updater.args.add("leap"); @@ -1191,8 +1195,22 @@ bool LLAppViewer::init() // ForceAddressSize updater.args.add(stringize(gSavedSettings.getU32("ForceAddressSize"))); - // Run the updater. An exception from launching the updater should bother us. - LLLeap::create(updater, true); + try + { + // Run the updater. An exception from launching the updater should bother us. + LLLeap::create(updater, true); + } + catch (...) + { + LLUIString details = LLNotifications::instance().getGlobalString("LLLeapUpdaterFailure"); + details.setArg("[UPDATER_APP]", updater_file); + OSMessageBox( + details.getString(), + LLStringUtil::null, + OSMB_OK); + // pass this exception to crash handler + throw; + } } else { diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml index 29d570de64..2f4da4f9b7 100644 --- a/indra/newview/skins/default/xui/en/notifications.xml +++ b/indra/newview/skins/default/xui/en/notifications.xml @@ -9595,6 +9595,10 @@ If you continue to have problems, please visit the [SUPPORT_SITE]. - Your system memory does not meet the minimum requirements. + + +Failed to launch updater service [UPDATER_APP]. Please verify the viewer is installed correctly and has the necessary permissions to run. If you continue to experience issues, please visit the [SUPPORT_SITE]. + From 8346e4984ed338a7bf9c35618edb36194057b8bd Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Tue, 17 Nov 2020 22:20:40 +0200 Subject: [PATCH 034/443] Reverted SL-14201, change was moved to DRTVWR-514 --- autobuild.xml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/autobuild.xml b/autobuild.xml index 3e1bd522de..a8203bb643 100644 --- a/autobuild.xml +++ b/autobuild.xml @@ -580,9 +580,9 @@ archive hash - b50d355c1c7088cafe5e12d31f1fb07f + cc26af2ebfa241891caca829a6e46b88 url - https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/72181/697551/dullahan-1.7.0.202011111255_81.3.10_gb223419_chromium-81.0.4044.138-darwin64-552103.tar.bz2 + http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/65005/607316/dullahan-1.7.0.202008031101_81.3.10_gb223419_chromium-81.0.4044.138-darwin64-546064.tar.bz2 name darwin64 @@ -592,9 +592,9 @@ archive hash - 0a52a79ad9a182529f7856f78bf4a96f + 4e5b9e2fe65d94e30a4f3d831c767199 url - https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/72199/697588/dullahan-1.7.0.202011112115_81.3.10_gb223419_chromium-81.0.4044.138-windows-552103.tar.bz2 + http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/65004/607304/dullahan-1.7.0.202008031759_81.3.10_gb223419_chromium-81.0.4044.138-windows-546064.tar.bz2 name windows @@ -604,16 +604,16 @@ archive hash - 715fe1bad3ba216508648b5763ea0404 + 6f7bf7f915f3d75dbdad08a2d41ca74e url - https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/72196/697581/dullahan-1.7.0.202011112112_81.3.10_gb223419_chromium-81.0.4044.138-windows64-552103.tar.bz2 + http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/65003/607308/dullahan-1.7.0.202008031800_81.3.10_gb223419_chromium-81.0.4044.138-windows64-546064.tar.bz2 name windows64 version - 1.7.0.202011112112_81.3.10_gb223419_chromium-81.0.4044.138 + 1.7.0.202008031800_81.3.10_gb223419_chromium-81.0.4044.138 elfio From da3bd5a796e187f2e3c3b32d9b95ae0d7b15b423 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Mon, 23 Nov 2020 14:02:36 +0200 Subject: [PATCH 035/443] SL-13599 Resolve gcc v10 'no trivial copy-assigment' warnings --- indra/llprimitive/llprimitive.cpp | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/indra/llprimitive/llprimitive.cpp b/indra/llprimitive/llprimitive.cpp index e08b1914e8..67c225d25d 100644 --- a/indra/llprimitive/llprimitive.cpp +++ b/indra/llprimitive/llprimitive.cpp @@ -118,7 +118,7 @@ struct material_id_type // originally from llrendermaterialtable { material_id_type() { - memset(m_value, 0, sizeof(m_value)); + memset((void*)m_value, 0, sizeof(m_value)); } bool operator==(const material_id_type& other) const @@ -1417,7 +1417,7 @@ S32 LLPrimitive::parseTEMessage(LLMessageSystem* mesgsys, char const* block_name if (cur_ptr >= buffer_end || !unpack_TEField(material_data, tec.face_count, cur_ptr, buffer_end, MVT_LLUUID)) { - memset(material_data, 0, sizeof(material_data)); + memset((void*)material_data, 0, sizeof(material_data)); } for (U32 i = 0; i < tec.face_count; i++) @@ -1480,7 +1480,7 @@ S32 LLPrimitive::unpackTEMessage(LLDataPacker &dp) const U32 MAX_TE_BUFFER = 4096; U8 packed_buffer[MAX_TE_BUFFER]; - memset(packed_buffer, 0, MAX_TE_BUFFER); + memset((void*)packed_buffer, 0, MAX_TE_BUFFER); LLUUID image_data[MAX_TES]; LLColor4U colors[MAX_TES]; @@ -1494,14 +1494,14 @@ S32 LLPrimitive::unpackTEMessage(LLDataPacker &dp) U8 glow[MAX_TES]; material_id_type material_data[MAX_TES]; - memset(scale_s, 0, sizeof(scale_s)); - memset(scale_t, 0, sizeof(scale_t)); - memset(offset_s, 0, sizeof(offset_s)); - memset(offset_t, 0, sizeof(offset_t)); - memset(image_rot, 0, sizeof(image_rot)); - memset(bump, 0, sizeof(bump)); - memset(media_flags, 0, sizeof(media_flags)); - memset(glow, 0, sizeof(glow)); + 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; @@ -1551,7 +1551,7 @@ S32 LLPrimitive::unpackTEMessage(LLDataPacker &dp) if (cur_ptr >= buffer_end || !unpack_TEField(material_data, face_count, cur_ptr, buffer_end, MVT_LLUUID)) { - memset(material_data, 0, sizeof(material_data)); + memset((void*)material_data, 0, sizeof(material_data)); } for (i = 0; i < face_count; i++) From 1a7ca0ac711ffc197ece0cebe9edb1deb7dfdcbe Mon Sep 17 00:00:00 2001 From: Mnikolenko Productengine Date: Tue, 24 Nov 2020 16:21:05 +0200 Subject: [PATCH 036/443] SL-14366 Close empty script actions floater --- indra/newview/llviewermenu.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index 4890867f29..ed1058f085 100644 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -7206,7 +7206,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(); @@ -7228,6 +7228,7 @@ void queue_actions(LLFloaterScriptQueue* q, const std::string& msg) { LL_ERRS() << "Bad logic." << LL_ENDL; } + q->closeFloater(); } else { @@ -7236,6 +7237,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 @@ -7283,8 +7285,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 { From 1b21cc8ffb4eb085fe0294796afbeb0c34bac588 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Tue, 24 Nov 2020 22:12:42 +0200 Subject: [PATCH 037/443] SL-14372 Changes to parcel properties should not pause or ask about music unless url changed --- indra/newview/llvieweraudio.cpp | 2 +- indra/newview/llvieweraudio.h | 5 ++-- indra/newview/llviewerparcelmgr.cpp | 42 ++++++++++++++++++++--------- indra/newview/llviewerparcelmgr.h | 2 +- 4 files changed, 34 insertions(+), 17 deletions(-) diff --git a/indra/newview/llvieweraudio.cpp b/indra/newview/llvieweraudio.cpp index cb20801756..f97ba0930e 100644 --- a/indra/newview/llvieweraudio.cpp +++ b/indra/newview/llvieweraudio.cpp @@ -81,7 +81,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/llviewerparcelmgr.cpp b/indra/newview/llviewerparcelmgr.cpp index d5365e4ee8..b4bca5b321 100644 --- a/indra/newview/llviewerparcelmgr.cpp +++ b/indra/newview/llviewerparcelmgr.cpp @@ -1890,7 +1890,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(); @@ -1908,7 +1909,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 @@ -1945,9 +1946,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) @@ -1957,25 +1962,35 @@ void LLViewerParcelMgr::optionally_start_music(const std::string &music_url, con // only play music when you enter a new parcel if the UI control for this // was not *explicitly* stopped by the user. (part of SL-4878) LLPanelNearByMedia* nearby_media_panel = gStatusBar->getNearbyMediaPanel(); + LLViewerAudio* viewer_audio = LLViewerAudio::getInstance(); // 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 @@ -1987,11 +2002,12 @@ void LLViewerParcelMgr::optionally_start_music(const std::string &music_url, con && tentative_autoplay)) { 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 508a63c398..6ce389ab88 100644 --- a/indra/newview/llviewerparcelmgr.h +++ b/indra/newview/llviewerparcelmgr.h @@ -271,7 +271,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); From 58835c4b230cd6524a4f4a9f8d95a37359837811 Mon Sep 17 00:00:00 2001 From: Mnikolenko Productengine Date: Thu, 26 Nov 2020 16:31:36 +0200 Subject: [PATCH 038/443] SL-14396 FIXED Sizing increment units ignored for HUDs. --- indra/newview/llselectmgr.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/indra/newview/llselectmgr.cpp b/indra/newview/llselectmgr.cpp index 50884762a8..5bbdeb1f98 100644 --- a/indra/newview/llselectmgr.cpp +++ b/indra/newview/llselectmgr.cpp @@ -1368,11 +1368,8 @@ 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); - break; case SELECT_TYPE_WORLD: - mGridScale = LLVector3(1.f, 1.f, 1.f) * gSavedSettings.getF32("GridResolution"); + mGridScale = LLVector3(1.f, 1.f, 1.f) * llmin(gSavedSettings.getF32("GridResolution"), 0.5f); break; } } From f187d258ecd79e216ab0b0c67146acbe046db78f Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Wed, 2 Dec 2020 00:39:19 +0200 Subject: [PATCH 039/443] SL-14392 Fixed blocking UI behavior when estimating the price of buying land --- indra/newview/llfloaterbuyland.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/indra/newview/llfloaterbuyland.cpp b/indra/newview/llfloaterbuyland.cpp index 0a0e5ffc06..5768b727f9 100644 --- a/indra/newview/llfloaterbuyland.cpp +++ b/indra/newview/llfloaterbuyland.cpp @@ -996,7 +996,7 @@ void LLFloaterBuyLandUI::draw() // virtual BOOL LLFloaterBuyLandUI::canClose() { - bool can_close = (mTransaction ? FALSE : TRUE) && mCurrency.canCancel(); + bool can_close = (mTransaction ? FALSE : TRUE) && mTransactionType != TransactionBuy; if (!can_close) { // explain to user why they can't do this, see DEV-9605 From e3b910e14113030b79004bf216193c96c6fb9521 Mon Sep 17 00:00:00 2001 From: Mnikolenko Productengine Date: Fri, 4 Dec 2020 17:02:22 +0200 Subject: [PATCH 040/443] SL-14462 FIXED The wrong mouse cursor is shown when sitting on a touch-scripted object --- indra/newview/lltoolpie.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/indra/newview/lltoolpie.cpp b/indra/newview/lltoolpie.cpp index 864ce09430..e9dda9a29c 100644 --- a/indra/newview/lltoolpie.cpp +++ b/indra/newview/lltoolpie.cpp @@ -691,7 +691,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); From 970345e6eaf4bd9f0e3ce2189695fab6b9c8db06 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Fri, 4 Dec 2020 01:24:59 +0200 Subject: [PATCH 041/443] SL-2363 Windows product key not suitable as unique machine key --- indra/newview/llmachineid.cpp | 552 ++++++++++++++++++--------- indra/newview/llmachineid.h | 2 + indra/newview/llsechandler_basic.cpp | 32 +- indra/newview/llsechandler_basic.h | 1 + 4 files changed, 394 insertions(+), 193 deletions(-) diff --git a/indra/newview/llmachineid.cpp b/indra/newview/llmachineid.cpp index 57a6ecb604..d48aadfe74 100644 --- a/indra/newview/llmachineid.cpp +++ b/indra/newview/llmachineid.cpp @@ -35,28 +35,316 @@ using namespace std; #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; }; + +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" << 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" << 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" << 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" << 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" << 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" << 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" << 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; +} + #endif //LL_WINDOWS // get an unique machine id. @@ -69,201 +357,79 @@ 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; + // Try motherboard/bios id, if it is present it is supposed to be sufficiently + // unique (it's used for Win8 activation) + if (comInit.getComputerSystemProductUUID(static_unique_id, len)) + { + has_static_unique_id = true; + LL_DEBUGS("AppInit") << "Using product uuid as serial" << LL_ENDL; + } - // Step 1: -------------------------------------------------- - // Initialize COM. ------------------------------------------ + // Try HDD and CPU ids + if (!has_static_unique_id) + { + unsigned char hdd_id[] = { 0,0,0,0,0,0 }; + unsigned char cpu_id[] = { 0,0,0,0,0,0 }; + unsigned char mbrd_id[] = { 0,0,0,0,0,0 }; - 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)) + if (comInit.getDiskDriveSerialNumber(hdd_id, len) + && comInit.getProcessorSerialNumber(cpu_id, len) + && comInit.getMotherboardSerialNumber(mbrd_id, len)) { - 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) + // Combine HDD, CPU and motherboard ids + // By themself they are not sufficiently unique and often contain model + // instead of unique number, but should be good enough when combined + // Todo: if not sufficiently unique, add hdd's partition id + S32 summ = 0; + for (S32 i = 0; i < len; i++) { - break; + static_unique_id[i] = hdd_id[i] + cpu_id[i] + mbrd_id[i]; + summ += static_unique_id[i]; } - - VARIANT vtProp; - - // Get the value of the Name property - hr = pclsObj->Get(L"SerialNumber", 0, &vtProp, 0, 0); - if (FAILED(hr)) + if (summ > 0) { - LL_WARNS() << "Failed to get SerialNumber. Error code = 0x" << hex << hres << LL_ENDL; - pclsObj->Release(); - pclsObj = NULL; - continue; + has_static_unique_id = true; + LL_DEBUGS("AppInit") << "Using hdd and cpu ids as serial" << LL_ENDL; } - 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; + // 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; #else unsigned char * staticPtr = (unsigned char *)(&static_unique_id[0]); ret_code = LLUUID::getNodeID(staticPtr); -#endif 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 +458,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/llsechandler_basic.cpp b/indra/newview/llsechandler_basic.cpp index 737ef30ada..dcedf5858a 100644 --- a/indra/newview/llsechandler_basic.cpp +++ b/indra/newview/llsechandler_basic.cpp @@ -1302,8 +1302,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(), @@ -1314,9 +1314,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); @@ -1367,6 +1365,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; diff --git a/indra/newview/llsechandler_basic.h b/indra/newview/llsechandler_basic.h index 0bc7f5230f..b21a5d08f9 100644 --- a/indra/newview/llsechandler_basic.h +++ b/indra/newview/llsechandler_basic.h @@ -326,6 +326,7 @@ public: protected: + void _readProtectedData(unsigned char *unique_id, U32 id_len); void _readProtectedData(); void _writeProtectedData(); std::string _legacyLoadPassword(); From 9432e092d340f3ac988cdfde182b21302ed47e91 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Fri, 4 Dec 2020 23:26:46 +0200 Subject: [PATCH 042/443] SL-2363 Use only product uuid and fallback to product serial --- indra/newview/llmachineid.cpp | 34 ++-------------------------------- 1 file changed, 2 insertions(+), 32 deletions(-) diff --git a/indra/newview/llmachineid.cpp b/indra/newview/llmachineid.cpp index d48aadfe74..cfcf085876 100644 --- a/indra/newview/llmachineid.cpp +++ b/indra/newview/llmachineid.cpp @@ -368,41 +368,11 @@ S32 LLMachineID::init() has_static_legacy_id = true; } - // Try motherboard/bios id, if it is present it is supposed to be sufficiently - // unique (it's used for Win8 activation) + // 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 serial" << LL_ENDL; - } - - // Try HDD and CPU ids - if (!has_static_unique_id) - { - unsigned char hdd_id[] = { 0,0,0,0,0,0 }; - unsigned char cpu_id[] = { 0,0,0,0,0,0 }; - unsigned char mbrd_id[] = { 0,0,0,0,0,0 }; - - if (comInit.getDiskDriveSerialNumber(hdd_id, len) - && comInit.getProcessorSerialNumber(cpu_id, len) - && comInit.getMotherboardSerialNumber(mbrd_id, len)) - { - // Combine HDD, CPU and motherboard ids - // By themself they are not sufficiently unique and often contain model - // instead of unique number, but should be good enough when combined - // Todo: if not sufficiently unique, add hdd's partition id - S32 summ = 0; - for (S32 i = 0; i < len; i++) - { - static_unique_id[i] = hdd_id[i] + cpu_id[i] + mbrd_id[i]; - summ += static_unique_id[i]; - } - if (summ > 0) - { - has_static_unique_id = true; - LL_DEBUGS("AppInit") << "Using hdd and cpu ids as serial" << LL_ENDL; - } - } + LL_DEBUGS("AppInit") << "Using product uuid as unique id" << LL_ENDL; } // Fallback to legacy From ab58b135340ae566ae8e5e781f708e16e7b914ce Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Mon, 7 Dec 2020 11:55:24 +0200 Subject: [PATCH 043/443] SL-2363 Update Unit Tests --- indra/newview/tests/lllogininstance_test.cpp | 4 ++++ indra/newview/tests/llsechandler_basic_test.cpp | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/indra/newview/tests/lllogininstance_test.cpp b/indra/newview/tests/lllogininstance_test.cpp index 57f2d31eab..e0044c40ee 100644 --- a/indra/newview/tests/lllogininstance_test.cpp +++ b/indra/newview/tests/lllogininstance_test.cpp @@ -302,6 +302,10 @@ S32 LLMachineID::getUniqueID(unsigned char *unique_id, size_t len) memcpy(unique_id, gMACAddress, len); return 1; } +S32 LLMachineID::getUniqueID(unsigned char *unique_id, size_t len) +{ + return 0; +} //----------------------------------------------------------------------------- // misc std::string xml_escape_string(const std::string& in) diff --git a/indra/newview/tests/llsechandler_basic_test.cpp b/indra/newview/tests/llsechandler_basic_test.cpp index e5d226a2a4..02185316b2 100644 --- a/indra/newview/tests/llsechandler_basic_test.cpp +++ b/indra/newview/tests/llsechandler_basic_test.cpp @@ -121,6 +121,10 @@ S32 LLMachineID::getUniqueID(unsigned char *unique_id, size_t len) memcpy(unique_id, gMACAddress, len); return 1; } +S32 LLMachineID::getLegacyID(unsigned char *unique_id, size_t len) +{ + return 0; +} S32 LLMachineID::init() { return 1; } From 1884da366d1ec5a1d49df521f2bc639d7d72fd88 Mon Sep 17 00:00:00 2001 From: Mnikolenko Productengine Date: Mon, 7 Dec 2020 17:37:20 +0200 Subject: [PATCH 044/443] SL-1777 FIXED Uploading Image or Saving Snapshot while in Inventory Recent tab jumps to Main tab --- indra/newview/llinventorypanel.cpp | 3 +- indra/newview/llpanelmaininventory.cpp | 39 +++++++++++++------------- indra/newview/llpanelmaininventory.h | 2 ++ indra/newview/llviewerassetupload.cpp | 2 +- 4 files changed, 25 insertions(+), 21 deletions(-) diff --git a/indra/newview/llinventorypanel.cpp b/indra/newview/llinventorypanel.cpp index f96750fb0b..8adf682b37 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" @@ -1592,7 +1593,7 @@ void LLInventoryPanel::openInventoryPanelAndSetSelection(BOOL auto_open, const L bool in_inbox = (gInventory.isObjectDescendentOf(obj_id, gInventory.findCategoryUUIDForType(LLFolderType::FT_INBOX))); - if (main_panel && !in_inbox) + if (!in_inbox && (main_panel || !sidepanel_inventory->getMainInventoryPanel()->isRecentItemsPanelSelected())) { sidepanel_inventory->selectAllItemsPanel(); } diff --git a/indra/newview/llpanelmaininventory.cpp b/indra/newview/llpanelmaininventory.cpp index 02cd22c307..6412216ed0 100644 --- a/indra/newview/llpanelmaininventory.cpp +++ b/indra/newview/llpanelmaininventory.cpp @@ -62,15 +62,11 @@ 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 @@ -148,7 +144,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 @@ -158,7 +154,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 @@ -172,7 +168,7 @@ BOOL LLPanelMainInventory::postBuild() recent_items_panel->setSelectCallback(boost::bind(&LLPanelMainInventory::onSelectionChange, this, recent_items_panel, _1, _2)); } - mWornItemsPanel = getChild("Worn Items"); + mWornItemsPanel = getChild(WORN_ITEMS); if (mWornItemsPanel) { U32 filter_types = 0x0; @@ -254,7 +250,7 @@ LLPanelMainInventory::~LLPanelMainInventory( void ) { // Save the filters state. LLSD filterRoot; - LLInventoryPanel* all_items_panel = getChild("All Items"); + LLInventoryPanel* all_items_panel = getChild(ALL_ITEMS); if (all_items_panel) { LLSD filterState; @@ -268,7 +264,7 @@ LLPanelMainInventory::~LLPanelMainInventory( void ) } } - LLInventoryPanel* panel = findChild("Recent Items"); + LLInventoryPanel* panel = findChild(RECENT_ITEMS); if (panel) { LLSD filterState; @@ -299,7 +295,7 @@ LLPanelMainInventory::~LLPanelMainInventory( void ) LLInventoryPanel* LLPanelMainInventory::getAllItemsPanel() { - return getChild("All Items"); + return getChild(ALL_ITEMS); } void LLPanelMainInventory::selectAllItemsPanel() @@ -307,6 +303,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 @@ -422,7 +423,7 @@ void LLPanelMainInventory::setSortBy(const LLSD& userdata) } getActivePanel()->setSortOrder(sort_order_mask); - if ("Recent Items" == getActivePanel()->getName()) + if (isRecentItemsPanelSelected()) { gSavedSettings.setU32("RecentItemsSortOrder", sort_order_mask); } @@ -784,8 +785,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); } void LLPanelMainInventory::onSelectionChange(LLInventoryPanel *panel, const std::deque& items, BOOL user_action) @@ -1179,11 +1180,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 a6bdee233d..b8bf6c8b54 100644 --- a/indra/newview/llpanelmaininventory.h +++ b/indra/newview/llpanelmaininventory.h @@ -81,6 +81,8 @@ public: void selectAllItemsPanel(); const LLInventoryPanel* getActivePanel() const { return mActivePanel; } + bool isRecentItemsPanelSelected(); + const std::string& getFilterText() const { return mFilterText; } void setSelectCallback(const LLFolderView::signal_t::slot_type& cb); diff --git a/indra/newview/llviewerassetupload.cpp b/indra/newview/llviewerassetupload.cpp index d53cc3f745..d0e96944d5 100644 --- a/indra/newview/llviewerassetupload.cpp +++ b/indra/newview/llviewerassetupload.cpp @@ -792,7 +792,7 @@ void LLViewerAssetUpload::AssetInventoryUploadCoproc(LLCoreHttpUtil::HttpCorouti // Show the preview panel for textures and sounds to let // user know that the image (or snapshot) arrived intact. LLInventoryPanel* panel = LLInventoryPanel::getActiveInventoryPanel(FALSE); - LLInventoryPanel::openInventoryPanelAndSetSelection(TRUE, serverInventoryItem, TRUE, TAKE_FOCUS_NO, (panel == NULL)); + LLInventoryPanel::openInventoryPanelAndSetSelection(TRUE, serverInventoryItem, FALSE, TAKE_FOCUS_NO, (panel == NULL)); // restore keyboard focus gFocusMgr.setKeyboardFocus(focus); From c98795696f36ebfc11dee77a726770c2b7d4d66a Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Tue, 8 Dec 2020 00:18:01 +0200 Subject: [PATCH 045/443] SL-2363 Build fix --- indra/newview/tests/lllogininstance_test.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/indra/newview/tests/lllogininstance_test.cpp b/indra/newview/tests/lllogininstance_test.cpp index e0044c40ee..ba85729b87 100644 --- a/indra/newview/tests/lllogininstance_test.cpp +++ b/indra/newview/tests/lllogininstance_test.cpp @@ -302,7 +302,7 @@ S32 LLMachineID::getUniqueID(unsigned char *unique_id, size_t len) memcpy(unique_id, gMACAddress, len); return 1; } -S32 LLMachineID::getUniqueID(unsigned char *unique_id, size_t len) +S32 LLMachineID::getLegacyID(unsigned char *unique_id, size_t len) { return 0; } From 6b7ef8c8588e6788e16dc8026af87d139683cbcc Mon Sep 17 00:00:00 2001 From: Mnikolenko ProductEngine Date: Tue, 8 Dec 2020 18:21:05 +0200 Subject: [PATCH 046/443] SL-14481 Use serial number as unique key on Mac --- indra/newview/llmachineid.cpp | 82 ++++++++++++++++++++++++++++++++--- 1 file changed, 77 insertions(+), 5 deletions(-) diff --git a/indra/newview/llmachineid.cpp b/indra/newview/llmachineid.cpp index cfcf085876..c7a0665630 100644 --- a/indra/newview/llmachineid.cpp +++ b/indra/newview/llmachineid.cpp @@ -33,6 +33,9 @@ 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}; @@ -344,8 +347,51 @@ bool LLWMIMethods::getGenericSerialNumber(const BSTR &select, const LPCWSTR &var 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; + } -#endif //LL_WINDOWS + 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. @@ -394,11 +440,37 @@ S32 LLMachineID::init() } ret_code=0; -#else - unsigned char * staticPtr = (unsigned char *)(&static_unique_id[0]); - ret_code = LLUUID::getNodeID(staticPtr); +#elif LL_DARWIN + if (getSerialNumber(static_unique_id, len)) + { has_static_unique_id = true; - has_static_legacy_id = false; + 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_legacy_id[0]); + ret_code = LLUUID::getNodeID(staticPtr); + has_static_unique_id = true; + has_static_legacy_id = false; #endif LL_INFOS("AppInit") << "UniqueID: 0x"; From 985502756f3c897f9ae417d995bf29fc71e21656 Mon Sep 17 00:00:00 2001 From: Mnikolenko Productengine Date: Thu, 10 Dec 2020 18:10:22 +0200 Subject: [PATCH 047/443] SL-14463 Don't show "Taper" prim parameter value when multiple prims are selected --- indra/newview/llpanelobject.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/indra/newview/llpanelobject.cpp b/indra/newview/llpanelobject.cpp index 6bff95ab36..831c89b005 100644 --- a/indra/newview/llpanelobject.cpp +++ b/indra/newview/llpanelobject.cpp @@ -896,7 +896,7 @@ void LLPanelObject::getState( ) mSpinScaleY->setMaxValue(OBJECT_MAX_HOLE_SIZE_Y); break; default: - if (editable) + if (editable && single_volume) { mSpinScaleX->set( 1.f - scale_x ); mSpinScaleY->set( 1.f - scale_y ); From 83a9d09b41f1766626cfb389b877616498626ffd Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Fri, 11 Dec 2020 19:08:06 +0200 Subject: [PATCH 048/443] SL-14518 Trivial changes to settings.xml Contribution, move comments to their own lines to simplify parsing --- doc/contributions.txt | 1 + indra/newview/app_settings/settings.xml | 30 +++++++++++++++---------- 2 files changed, 19 insertions(+), 12 deletions(-) diff --git a/doc/contributions.txt b/doc/contributions.txt index bbdfaf655d..eabb051361 100755 --- a/doc/contributions.txt +++ b/doc/contributions.txt @@ -800,6 +800,7 @@ Jonathan Yap STORM-2104 STORM-2142 SL-10089 + BUG-229818 Kadah Coba STORM-1060 STORM-1843 diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index 52dc4744f2..68e175fd6b 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -1573,10 +1573,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 @@ -2494,10 +2495,11 @@ Value 0 - DEPRECATED: DebugShowPrivateMem + DebugShowPrivateMem + Comment - Show Private Mem Info + (Deprecated) Show Private Mem Info Persist 1 Type @@ -5775,7 +5777,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 @@ -6586,10 +6588,11 @@ Value 600.0 - MemoryPrivatePoolEnabled + MemoryPrivatePoolEnabled + Comment - DEPRECATED: Enable the private memory pool management + (Deprecated) Enable the private memory pool management Persist 1 Type @@ -6597,10 +6600,11 @@ Value 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 @@ -8293,7 +8297,7 @@ QAModeEventHostPort Comment - DEPRECATED: Port on which lleventhost should listen + (Deprecated) Port on which lleventhost should listen Persist 0 Type @@ -14027,10 +14031,11 @@ 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 @@ -14404,6 +14409,7 @@ 44125 VoiceCallsFriendsOnly + Comment (Deprecated) Only accept voice calls from residents on your friends list From 9dd9af129b67be184dd66e2ee4b46bd815877e70 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Fri, 11 Dec 2020 23:07:49 +0200 Subject: [PATCH 049/443] SL-14461 Parent set to no click action should not override child's 'touch' action. --- indra/newview/lltoolpie.cpp | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/indra/newview/lltoolpie.cpp b/indra/newview/lltoolpie.cpp index e9dda9a29c..c6ee0daffe 100644 --- a/indra/newview/lltoolpie.cpp +++ b/indra/newview/lltoolpie.cpp @@ -465,8 +465,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->getClickAction() && parent->getClickAction() != CLICK_ACTION_DISABLED)); } @@ -480,13 +481,17 @@ U8 final_click_action(LLViewerObject* obj) if (obj->getClickAction() || (parent && parent->getClickAction())) { - if (obj->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 = obj->getClickAction(); + // CLICK_ACTION_DISABLED ("None" in UI) is intended for child action to + // override parents action when assigned to parent or to child + click_action = object_action; } - else if (parent && parent->getClickAction()) + else if (parent_action) { - click_action = parent->getClickAction(); + click_action = parent_action; } } return click_action; @@ -692,7 +697,7 @@ BOOL LLToolPie::handleHover(S32 x, S32 y, MASK mask) } else if ((!object || !object->isAttachment() || object->getClickAction() != CLICK_ACTION_DISABLED) && ((object && object->flagHandleTouch()) || (parent && parent->flagHandleTouch())) - && (object && !object->isAvatar())) + && (!object || !object->isAvatar())) { show_highlight = true; gViewerWindow->setCursor(UI_CURSOR_HAND); From 9407637c5383bd0c3739f1ff4e0ac6ceeb579208 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Sun, 13 Dec 2020 13:06:47 +0200 Subject: [PATCH 050/443] SL-14461 Double click teleport should work on 'disabled' objects --- indra/newview/lltoolpie.cpp | 35 ++++++++++++++++------------------- 1 file changed, 16 insertions(+), 19 deletions(-) diff --git a/indra/newview/lltoolpie.cpp b/indra/newview/lltoolpie.cpp index c6ee0daffe..05ace54074 100644 --- a/indra/newview/lltoolpie.cpp +++ b/indra/newview/lltoolpie.cpp @@ -467,7 +467,7 @@ BOOL LLToolPie::useClickAction(MASK mask, && LLPrimitive::isPrimitive(object->getPCode()) // useClickAction does not handle Touch (0) or Disabled action && ((object->getClickAction() && object->getClickAction() != CLICK_ACTION_DISABLED) - || (parent->getClickAction() && parent->getClickAction() != CLICK_ACTION_DISABLED)); + || (parent && parent->getClickAction() && parent->getClickAction() != CLICK_ACTION_DISABLED)); } @@ -478,22 +478,18 @@ U8 final_click_action(LLViewerObject* obj) U8 click_action = CLICK_ACTION_TOUCH; LLViewerObject* parent = obj->getRootEdit(); - if (obj->getClickAction() - || (parent && 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 parents action when assigned to parent or to child - click_action = object_action; - } - else if (parent_action) - { - click_action = parent_action; - } - } + 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; } @@ -886,9 +882,10 @@ BOOL LLToolPie::handleDoubleClick(S32 x, S32 y, MASK mask) bool is_land = mPick.mPickType == LLPickInfo::PICK_LAND; bool pos_non_zero = !mPick.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); // deault action: 0 - touch + bool has_click_action = (click_action || has_touch_handler) && click_action != CLICK_ACTION_DISABLED; - 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))) { LLVector3d pos = mPick.mPosGlobal; pos.mdV[VZ] += gAgentAvatarp->getPelvisToFoot(); From dec231827b896d64e068b074d371774293cb8b37 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Sun, 13 Dec 2020 13:32:20 +0200 Subject: [PATCH 051/443] SL-14543 Fix reason in environments 'settings couldn't be applied' error --- indra/newview/llenvironment.cpp | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/indra/newview/llenvironment.cpp b/indra/newview/llenvironment.cpp index e56ed92d9e..13e29b90fc 100644 --- a/indra/newview/llenvironment.cpp +++ b/indra/newview/llenvironment.cpp @@ -2007,7 +2007,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 { @@ -2069,7 +2077,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 { From e3c2859e5549e1fb4e47cf2477241a5ba8cea595 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Mon, 14 Dec 2020 19:20:22 +0200 Subject: [PATCH 052/443] SL-11300 Camera distance to avatar in neighbouring region incorrect --- doc/contributions.txt | 1 + indra/newview/lldrawable.cpp | 10 +++------- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/doc/contributions.txt b/doc/contributions.txt index eabb051361..9522ea8a6c 100755 --- a/doc/contributions.txt +++ b/doc/contributions.txt @@ -267,6 +267,7 @@ Beth Walcher Beq Janus SL-10288 SL-13583 + SL-11300 Bezilon Kasei Biancaluce Robbiani CT-225 diff --git a/indra/newview/lldrawable.cpp b/indra/newview/lldrawable.cpp index 2219f20272..1da94f4698 100644 --- a/indra/newview/lldrawable.cpp +++ b/indra/newview/lldrawable.cpp @@ -912,22 +912,18 @@ void LLDrawable::updateDistance(LLCamera& camera, bool force_update) if (volume->getAvatar()) { const LLVector3* av_box = volume->getAvatar()->getLastAnimExtents(); - LLVector3d cam_pos = gAgent.getPosGlobalFromAgent(LLViewerCamera::getInstance()->getOrigin()); - LLVector3 cam_region_pos = LLVector3(cam_pos - volume->getRegion()->getOriginGlobal()); - - LLVector3 cam_to_box_offset = point_to_box_offset(cam_region_pos, av_box); + LLVector3 cam_pos_from_agent = LLViewerCamera::getInstance()->getOrigin(); + LLVector3 cam_to_box_offset = point_to_box_offset(cam_pos_from_agent, av_box); mDistanceWRTCamera = llmax(0.01f, ll_round(cam_to_box_offset.magVec(), 0.01f)); LL_DEBUGS("DynamicBox") << volume->getAvatar()->getFullname() << " pos (ignored) " << pos - << " cam pos " << cam_pos - << " cam region pos " << cam_region_pos + << " cam pos " << cam_pos_from_agent << " box " << av_box[0] << "," << av_box[1] << " -> dist " << mDistanceWRTCamera << LL_ENDL; mVObjp->updateLOD(); return; } - } else { From 851723656ebd6e6a1c020df6bf15c132fc29e096 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Thu, 17 Dec 2020 00:07:43 +0200 Subject: [PATCH 053/443] SL-14392 Fixed blocking UI behavior #2 --- indra/newview/llfloaterbuyland.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/indra/newview/llfloaterbuyland.cpp b/indra/newview/llfloaterbuyland.cpp index 5768b727f9..464e7ff4a2 100644 --- a/indra/newview/llfloaterbuyland.cpp +++ b/indra/newview/llfloaterbuyland.cpp @@ -996,7 +996,8 @@ void LLFloaterBuyLandUI::draw() // virtual BOOL LLFloaterBuyLandUI::canClose() { - bool can_close = (mTransaction ? FALSE : TRUE) && mTransactionType != TransactionBuy; + // 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 From 766a9f150ceb2a0ee16d9f40b830f63ff7aced10 Mon Sep 17 00:00:00 2001 From: Mnikolenko Productengine Date: Tue, 5 Jan 2021 13:27:01 +0200 Subject: [PATCH 054/443] SL-2141 Disable the ability to change pipelining setting without restarting the viewer --- indra/newview/llappcorehttp.cpp | 35 ++++++--------------------------- indra/newview/llappcorehttp.h | 1 - 2 files changed, 6 insertions(+), 30 deletions(-) diff --git a/indra/newview/llappcorehttp.cpp b/indra/newview/llappcorehttp.cpp index 134a34137b..287d1241cc 100644 --- a/indra/newview/llappcorehttp.cpp +++ b/indra/newview/llappcorehttp.cpp @@ -253,20 +253,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 @@ -355,7 +348,6 @@ void LLAppCoreHttp::cleanup() { mHttpClasses[i].mSettingsSignal.disconnect(); } - mPipelinedSignal.disconnect(); delete mRequest; mRequest = NULL; @@ -374,21 +366,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)); @@ -417,7 +394,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) @@ -460,7 +437,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/llappcorehttp.h b/indra/newview/llappcorehttp.h index 95c138d598..273646369e 100644 --- a/indra/newview/llappcorehttp.h +++ b/indra/newview/llappcorehttp.h @@ -255,7 +255,6 @@ private: bool mStopped; HttpClass mHttpClasses[AP_COUNT]; bool mPipelined; // Global setting - boost::signals2::connection mPipelinedSignal; // Signal for 'HttpPipelining' setting static LLCore::HttpStatus sslVerify(const std::string &uri, const LLCore::HttpHandler::ptr_t &handler, void *appdata); }; From 55267aab80c945da44587b62822095838ac4a6bc Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Fri, 8 Jan 2021 21:30:28 +0200 Subject: [PATCH 055/443] SL-14175 Restarting animation on new face, restarts old one as well Properly clean up animation when animation gets fully deleted. --- indra/newview/llvovolume.cpp | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp index 492d37edba..5cf7bac46c 100644 --- a/indra/newview/llvovolume.cpp +++ b/indra/newview/llvovolume.cpp @@ -377,6 +377,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; @@ -476,6 +488,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; From 03921adb1211c6def0ce5c791e2455643142a92a Mon Sep 17 00:00:00 2001 From: Mnikolenko Productengine Date: Mon, 11 Jan 2021 17:07:03 +0200 Subject: [PATCH 056/443] SL-2202 Add exception handling around boost::regex_match() calls in the viewer --- indra/llcommon/CMakeLists.txt | 2 +- indra/llcommon/llregex.h | 89 +++++++++++++++++++++++ indra/llcommon/llsys.cpp | 39 +--------- indra/llprimitive/llmediaentry.cpp | 5 +- indra/llui/llurlentry.cpp | 3 +- indra/llui/llurlregistry.cpp | 12 +-- indra/llvfs/lldiriterator.cpp | 4 +- indra/newview/llfloaterwindowsize.cpp | 6 +- indra/newview/llimprocessing.cpp | 4 +- indra/newview/llinventoryfilter.cpp | 5 +- indra/newview/lllogchat.cpp | 12 +-- indra/newview/llpanelexperiencepicker.cpp | 4 +- indra/newview/llpanelsnapshotpostcard.cpp | 3 +- indra/newview/llversioninfo.cpp | 10 +-- indra/newview/llweb.cpp | 7 +- 15 files changed, 126 insertions(+), 79 deletions(-) create mode 100644 indra/llcommon/llregex.h diff --git a/indra/llcommon/CMakeLists.txt b/indra/llcommon/CMakeLists.txt index eeb315ead6..0a22942dfd 100644 --- a/indra/llcommon/CMakeLists.txt +++ b/indra/llcommon/CMakeLists.txt @@ -207,9 +207,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 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 1f8d558fbe..f7461422f7 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 @@ -111,39 +111,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("") { @@ -387,7 +354,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; @@ -1116,7 +1083,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/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/llui/llurlentry.cpp b/indra/llui/llurlentry.cpp index e6835f73fb..ff742a9530 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" @@ -1388,7 +1389,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/llurlregistry.cpp b/indra/llui/llurlregistry.cpp index ba6fa1e2e9..5f44475bd7 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 // default dummy callback that ignores any label updates from the server void LLUrlRegistryNullCallback(const std::string &url, const std::string &label, const std::string& icon) @@ -107,15 +107,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/llvfs/lldiriterator.cpp b/indra/llvfs/lldiriterator.cpp index 3eb64e69d9..f57bf4ebc6 100644 --- a/indra/llvfs/lldiriterator.cpp +++ b/indra/llvfs/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/newview/llfloaterwindowsize.cpp b/indra/newview/llfloaterwindowsize.cpp index ec161018b8..863b7cbb12 100644 --- a/indra/newview/llfloaterwindowsize.cpp +++ b/indra/newview/llfloaterwindowsize.cpp @@ -34,18 +34,16 @@ #include "llcombobox.h" #include "llfloater.h" #include "llfloaterreg.h" +#include "llregex.h" #include "lluictrl.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/llimprocessing.cpp b/indra/newview/llimprocessing.cpp index 1e43e4ea3a..0524313a5c 100644 --- a/indra/newview/llimprocessing.cpp +++ b/indra/newview/llimprocessing.cpp @@ -42,6 +42,7 @@ #include "llnotificationsutil.h" #include "llnotificationmanager.h" #include "llpanelgroup.h" +#include "llregex.h" #include "llregionhandle.h" #include "llsdserialize.h" #include "llslurl.h" @@ -55,7 +56,6 @@ #include "llviewerregion.h" #include "llvoavatarself.h" -#include #include "boost/lexical_cast.hpp" #if LL_MSVC // disable boost::lexical_cast warning @@ -122,7 +122,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/llinventoryfilter.cpp b/indra/newview/llinventoryfilter.cpp index 72013f7396..c972b1dab7 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" @@ -800,7 +801,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/lllogchat.cpp b/indra/newview/lllogchat.cpp index 415781bc27..0ddcac44c9 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" @@ -40,7 +41,6 @@ #include #include -#include #include #include @@ -250,8 +250,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") ) @@ -815,7 +815,7 @@ bool LLLogChat::isTranscriptFileFound(std::string fullname) { //matching a timestamp boost::match_results matches; - if (boost::regex_match(remove_utf8_bom(buffer), matches, TIMESTAMP)) + if (ll_regex_match(remove_utf8_bom(buffer), matches, TIMESTAMP)) { result = true; } @@ -895,7 +895,7 @@ bool LLChatLogParser::parse(std::string& raw, LLSD& im, const LLSD& parse_params //matching a timestamp boost::match_results matches; - if (!boost::regex_match(raw, matches, TIMESTAMP_AND_STUFF)) return false; + if (!ll_regex_match(raw, matches, TIMESTAMP_AND_STUFF)) return false; bool has_timestamp = matches[IDX_TIMESTAMP].matched; if (has_timestamp) @@ -928,7 +928,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/llpanelexperiencepicker.cpp b/indra/newview/llpanelexperiencepicker.cpp index 80aeee6da1..6dfdbaf63f 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/llpanelsnapshotpostcard.cpp b/indra/newview/llpanelsnapshotpostcard.cpp index b8aa976657..05fa2b58b1 100644 --- a/indra/newview/llpanelsnapshotpostcard.cpp +++ b/indra/newview/llpanelsnapshotpostcard.cpp @@ -38,6 +38,7 @@ #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" @@ -229,7 +230,7 @@ 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; diff --git a/indra/newview/llversioninfo.cpp b/indra/newview/llversioninfo.cpp index 4720a989b0..376a7fce76 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 #if ! defined(LL_VIEWER_CHANNEL) \ || ! defined(LL_VIEWER_VERSION_MAJOR) \ @@ -139,19 +139,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/llweb.cpp b/indra/newview/llweb.cpp index 63257d6543..2618f9c719 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 ); @@ -239,13 +238,13 @@ bool LLWeb::useExternalBrowser(const std::string &url) boost::regex pattern = boost::regex("\\b(lindenlab.com|secondlife.com)$", 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 } From b3f0b0d955c7141a0cbe6852eeae36ba4b2eaa89 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Mon, 11 Jan 2021 20:23:52 +0200 Subject: [PATCH 057/443] SL-1028 Do not create dump folder for bugsplat based viewers --- indra/llvfs/lldir.cpp | 5 +++++ indra/llvfs/lldir.h | 1 + indra/newview/llappviewer.cpp | 13 ++++++++----- 3 files changed, 14 insertions(+), 5 deletions(-) diff --git a/indra/llvfs/lldir.cpp b/indra/llvfs/lldir.cpp index 10fbc06c61..3072be285f 100644 --- a/indra/llvfs/lldir.cpp +++ b/indra/llvfs/lldir.cpp @@ -340,6 +340,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; diff --git a/indra/llvfs/lldir.h b/indra/llvfs/lldir.h index 38e204ef04..9c8a1b1da8 100644 --- a/indra/llvfs/lldir.h +++ b/indra/llvfs/lldir.h @@ -95,6 +95,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. diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 515d6ffc14..2002e3c65f 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -3394,7 +3394,7 @@ void LLAppViewer::writeSystemInfo() if (! gDebugInfo.has("Dynamic") ) gDebugInfo["Dynamic"] = LLSD::emptyMap(); -#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. @@ -3896,10 +3896,13 @@ void LLAppViewer::removeMarkerFiles() 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()) + { + //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); + } } void LLAppViewer::forceQuit() From 663e45c7eade823e4eb88195057333cbd37e0b00 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Mon, 11 Jan 2021 20:40:47 +0200 Subject: [PATCH 058/443] SL-1028 Bugsplat based windows viewers should not overwrite log files from main instance --- indra/newview/llappviewer.cpp | 9 +++++++++ indra/newview/llappviewerwin32.cpp | 18 +++++++++++------- 2 files changed, 20 insertions(+), 7 deletions(-) diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 2002e3c65f..ac0b05c1c6 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -3066,6 +3066,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 diff --git a/indra/newview/llappviewerwin32.cpp b/indra/newview/llappviewerwin32.cpp index 9b1c0d1f8b..32548b7065 100644 --- a/indra/newview/llappviewerwin32.cpp +++ b/indra/newview/llappviewerwin32.cpp @@ -118,17 +118,21 @@ namespace { if (nCode == MDSCB_EXCEPTIONCODE) { - // send the main viewer log file - // widen to wstring, convert to __wchar_t, then pass c_str() - sBugSplatSender->sendAdditionalFile( - WCSTR(gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "SecondLife.log"))); + // second instance does not have own log files + if (!LLAppViewer::instance()->isSecondInstance()) + { + // send the main viewer log file + // widen to wstring, convert to __wchar_t, then pass c_str() + sBugSplatSender->sendAdditionalFile( + WCSTR(gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "SecondLife.log"))); + + sBugSplatSender->sendAdditionalFile( + WCSTR(*LLAppViewer::instance()->getStaticDebugFile())); + } 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( From 71ba69e82af5f8905e4199f9443c3766a5e4b482 Mon Sep 17 00:00:00 2001 From: Mnikolenko Productengine Date: Tue, 12 Jan 2021 16:22:17 +0200 Subject: [PATCH 059/443] SL-13313 Support RegionInfo5 block in RegionInfo message, and add log message --- indra/llmessage/message_prehash.cpp | 8 ++++++++ indra/llmessage/message_prehash.h | 8 ++++++++ indra/newview/llfloatergodtools.cpp | 23 +++++++++++++++++++++++ indra/newview/llfloaterregioninfo.cpp | 23 +++++++++++++++++++++++ indra/newview/llregioninfomodel.cpp | 23 +++++++++++++++++++++++ indra/newview/llviewerregion.cpp | 22 ++++++++++++++++++++++ scripts/messages/message_template.msg | 10 ++++++++++ 7 files changed, 117 insertions(+) diff --git a/indra/llmessage/message_prehash.cpp b/indra/llmessage/message_prehash.cpp index fba5b7453d..219b1855d2 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 4f72c01ddf..8f6ee5a327 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/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/llfloaterregioninfo.cpp b/indra/newview/llfloaterregioninfo.cpp index ec1909d02a..17e55b5f2c 100644 --- a/indra/newview/llfloaterregioninfo.cpp +++ b/indra/newview/llfloaterregioninfo.cpp @@ -470,6 +470,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/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/llviewerregion.cpp b/indra/newview/llviewerregion.cpp index 5c99e693d2..c0624ccc18 100644 --- a/indra/newview/llviewerregion.cpp +++ b/indra/newview/llviewerregion.cpp @@ -2806,6 +2806,28 @@ void LLViewerRegion::unpackRegionHandshake() mProductName = productName; } + 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; + } mCentralBakeVersion = region_protocols & 1; // was (S32)gSavedSettings.getBOOL("UseServerTextureBaking"); LLVLComposition *compp = getComposition(); diff --git a/scripts/messages/message_template.msg b/scripts/messages/message_template.msg index 635227ccf3..a3ddc6d336 100755 --- a/scripts/messages/message_template.msg +++ b/scripts/messages/message_template.msg @@ -2999,6 +2999,16 @@ version 2.0 RegionInfo3 Variable { RegionFlagsExtended U64 } } + { + RegionInfo5 Variable + { ChatWhisperRange F32 } + { ChatNormalRange F32 } + { ChatShoutRange F32 } + { ChatWhisperOffset F32 } + { ChatNormalOffset F32 } + { ChatShoutOffset F32 } + { ChatFlags U32 } + } } // GodUpdateRegionInfo From c85148a69bf2f1becb7051c0ae0894bbc5c429ec Mon Sep 17 00:00:00 2001 From: Mnikolenko Productengine Date: Wed, 13 Jan 2021 11:54:53 +0200 Subject: [PATCH 060/443] SL-13313 Remove changes from LLViewerRegion --- indra/newview/llviewerregion.cpp | 23 ----------------------- 1 file changed, 23 deletions(-) diff --git a/indra/newview/llviewerregion.cpp b/indra/newview/llviewerregion.cpp index c0624ccc18..317a959518 100644 --- a/indra/newview/llviewerregion.cpp +++ b/indra/newview/llviewerregion.cpp @@ -2806,29 +2806,6 @@ void LLViewerRegion::unpackRegionHandshake() mProductName = productName; } - 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; - } - mCentralBakeVersion = region_protocols & 1; // was (S32)gSavedSettings.getBOOL("UseServerTextureBaking"); LLVLComposition *compp = getComposition(); if (compp) From ebffbd3c9a41b7c44b719f76a054abfd38e19709 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Wed, 13 Jan 2021 20:47:20 +0200 Subject: [PATCH 061/443] SL-14575 Pass validation flags into EEP validators. --- indra/llinventory/llsettingsbase.cpp | 22 ++-- indra/llinventory/llsettingsbase.h | 20 ++-- indra/llinventory/llsettingsdaycycle.cpp | 28 ++--- indra/llinventory/llsettingssky.cpp | 128 +++++++++++------------ indra/llinventory/llsettingswater.cpp | 22 ++-- 5 files changed, 111 insertions(+), 109 deletions(-) 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 a687fd840d..2bb03e8391 100644 --- a/indra/llinventory/llsettingsdaycycle.cpp +++ b/indra/llinventory/llsettingsdaycycle.cpp @@ -460,7 +460,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) @@ -531,7 +531,7 @@ namespace return true; } - bool validateDayCycleFrames(LLSD &value) + bool validateDayCycleFrames(LLSD &value, U32 flags) { bool hasSky(false); bool hasWater(false); @@ -544,7 +544,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) { @@ -557,7 +557,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; @@ -573,18 +573,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 81937dbda5..1470edbf38 100644 --- a/indra/llinventory/llsettingssky.cpp +++ b/indra/llinventory/llsettingssky.cpp @@ -156,25 +156,25 @@ 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))))); 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_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; } @@ -185,19 +185,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; } @@ -208,19 +208,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; } @@ -231,31 +231,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; @@ -269,7 +269,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()) @@ -280,24 +280,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; @@ -311,7 +311,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()) @@ -322,24 +322,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; @@ -353,7 +353,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()) @@ -364,23 +364,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; @@ -559,80 +559,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))))); } From c92b44ab42ee4b5ba13c9803103387b186a46751 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Wed, 13 Jan 2021 21:17:46 +0200 Subject: [PATCH 062/443] SL-14580 Notify observers warnings with new accounts --- indra/newview/llinventorymodel.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp index 28db6a5808..e58d6f3a3a 100644 --- a/indra/newview/llinventorymodel.cpp +++ b/indra/newview/llinventorymodel.cpp @@ -2660,6 +2660,8 @@ 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); } From 03b1f6311ea4b09c839d3fa8250808480bd9ed6a Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Wed, 13 Jan 2021 22:07:00 +0200 Subject: [PATCH 063/443] SL-14580 Be a bit more forgiving about addChangedMask calls nested in notifyObservers --- indra/newview/llinventorymodel.cpp | 54 ++++++++++++++++++++++++------ indra/newview/llinventorymodel.h | 4 +++ 2 files changed, 48 insertions(+), 10 deletions(-) diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp index e58d6f3a3a..5af7c84628 100644 --- a/indra/newview/llinventorymodel.cpp +++ b/indra/newview/llinventorymodel.cpp @@ -1659,9 +1659,18 @@ void LLInventoryModel::notifyObservers() 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(); + mIsNotifyObservers = FALSE; } @@ -1673,8 +1682,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_INFOS(LOG_INV) << "Adding changed mask within notify observers! Change's processing will be performed on idle." << LL_ENDL; LLViewerInventoryItem *item = getItem(referent); if (item) { @@ -1689,17 +1700,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. diff --git a/indra/newview/llinventorymodel.h b/indra/newview/llinventorymodel.h index a4326aaeed..4dcd9332be 100644 --- a/indra/newview/llinventorymodel.h +++ b/indra/newview/llinventorymodel.h @@ -538,6 +538,10 @@ 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; //-------------------------------------------------------------------- From 8a9889ebd887152763195c3f5d59698241487728 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Thu, 14 Jan 2021 13:17:43 +0200 Subject: [PATCH 064/443] SL-14580 Fixed warnig level --- indra/newview/llinventorymodel.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp index 5af7c84628..d8452efa3e 100644 --- a/indra/newview/llinventorymodel.cpp +++ b/indra/newview/llinventorymodel.cpp @@ -1685,7 +1685,7 @@ void LLInventoryModel::addChangedMask(U32 mask, const LLUUID& referent) // 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_INFOS(LOG_INV) << "Adding changed mask within notify observers! Change's processing will be performed on idle." << LL_ENDL; + 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) { From 7cd921d97b3193786403f22be70ff07d95280dc3 Mon Sep 17 00:00:00 2001 From: Mnikolenko Productengine Date: Fri, 15 Jan 2021 14:33:23 +0200 Subject: [PATCH 065/443] SL-13313 Update links to master message_template.msg --- indra/cmake/Variables.cmake | 2 +- scripts/template_verifier.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/indra/cmake/Variables.cmake b/indra/cmake/Variables.cmake index a5770c5528..6cd3cd9278 100644 --- a/indra/cmake/Variables.cmake +++ b/indra/cmake/Variables.cmake @@ -61,7 +61,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 "http://bitbucket.org/lindenlab/master-message-template/raw/tip/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/scripts/template_verifier.py b/scripts/template_verifier.py index b44410cdd8..358931b13e 100755 --- a/scripts/template_verifier.py +++ b/scripts/template_verifier.py @@ -229,7 +229,7 @@ http://wiki.secondlife.com/wiki/Template_verifier.py """) parser.add_option( '-u', '--master_url', type='string', dest='master_url', - default='http://bitbucket.org/lindenlab/master-message-template/raw/tip/message_template.msg', + default='https://bitbucket.org/lindenlab/master-message-template-git/raw/master/message_template.msg', help="""The url of the master message template.""") parser.add_option( '-c', '--cache_master', action='store_true', dest='cache_master', From c8562a5477598d2d5ae6727f6fc64212d4e82080 Mon Sep 17 00:00:00 2001 From: Ansariel Date: Sun, 17 Jan 2021 13:36:02 +0100 Subject: [PATCH 066/443] Update message template hash --- scripts/messages/message_template.msg.sha1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/messages/message_template.msg.sha1 b/scripts/messages/message_template.msg.sha1 index e9f3d46777..d36178eee1 100755 --- a/scripts/messages/message_template.msg.sha1 +++ b/scripts/messages/message_template.msg.sha1 @@ -1 +1 @@ -9434f9f6c3e3bb35f130211ca2735f1b35d03365 \ No newline at end of file +e61fad776b4d494be0b901922fc75a3317af97ca \ No newline at end of file From 83127d22992e055b40298724d0cac0de108b6116 Mon Sep 17 00:00:00 2001 From: Mnikolenko ProductEngine Date: Thu, 21 Jan 2021 19:02:18 +0200 Subject: [PATCH 067/443] SL-14720 FIXED Undo function is incorrect on German Mac keyboard --- indra/llwindow/llopenglview-objc.mm | 5 +++-- indra/llwindow/llwindowmacosx-objc.h | 2 +- indra/llwindow/llwindowmacosx.cpp | 11 ++++++++++- 3 files changed, 14 insertions(+), 4 deletions(-) diff --git a/indra/llwindow/llopenglview-objc.mm b/indra/llwindow/llopenglview-objc.mm index d2c5b11c3d..f9b387b00b 100644 --- a/indra/llwindow/llopenglview-objc.mm +++ b/indra/llwindow/llopenglview-objc.mm @@ -494,7 +494,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 && @@ -537,7 +538,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 44fd4127ce..43edc0110d 100644 --- a/indra/llwindow/llwindowmacosx-objc.h +++ b/indra/llwindow/llwindowmacosx-objc.h @@ -131,7 +131,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 2604a23c85..d31ec6223c 100644 --- a/indra/llwindow/llwindowmacosx.cpp +++ b/indra/llwindow/llwindowmacosx.cpp @@ -207,8 +207,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; From eb042c2365a308c65ac3844c01741b0957bd3e1e Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Fri, 22 Jan 2021 22:34:55 +0200 Subject: [PATCH 068/443] SL-14697 Fix SSE2 warning --- indra/newview/installers/windows/lang_pl.nsi | Bin 12080 -> 12082 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/indra/newview/installers/windows/lang_pl.nsi b/indra/newview/installers/windows/lang_pl.nsi index 05977847b96a83993a201e58ef3298da74501720..865e8bdeeeddb6cb3f1c54171107eeddfbbe0601 100644 GIT binary patch delta 16 XcmdlGw<&G|m%`*LLK2%56a@GII%x%* delta 32 mcmdlKw;^r=mx8bxLncEJLn=ctLkUAZkd@1jxLIC7m>&R}cL+QH From 0d324bb24db49f6f28d7e7f14fd69e7676de8fe6 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Wed, 20 Jan 2021 20:19:28 +0200 Subject: [PATCH 069/443] SL-12422 Clear cert cache to enshure there is no carry-over between failed logins --- indra/newview/llsecapi.h | 4 +++- indra/newview/llsechandler_basic.h | 5 ++++- indra/newview/llstartup.cpp | 5 +++++ 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/indra/newview/llsecapi.h b/indra/newview/llsecapi.h index 14059f828a..3a7b06c55a 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; }; diff --git a/indra/newview/llsechandler_basic.h b/indra/newview/llsechandler_basic.h index 0bc7f5230f..3bfac3f056 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; diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index 17777c3ceb..194702e43e 100644 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -2824,6 +2824,11 @@ void reset_login() // Hide any other stuff 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(); } //--------------------------------------------------------------------------- From 63d9d378f49dc4d8018c0fcad4fcaa17024b21e3 Mon Sep 17 00:00:00 2001 From: Andrey Lihatskiy Date: Mon, 1 Feb 2021 03:14:11 +0200 Subject: [PATCH 070/443] DRTVWR-520 Updated 3p-libs to use signed versions Updated apr-suite to codeticket build 555520 Updated curl to codeticket build 555526 Updated glod to codeticket build 555522 Updated expat to codeticket build 555519 Updated libhunspell to codeticket build 555528 Updated libndofdev to codeticket build 555523 Updated nghttp2 to codeticket build 555524 --- autobuild.xml | 90 +++++++++++++++++++++++++-------------------------- 1 file changed, 45 insertions(+), 45 deletions(-) diff --git a/autobuild.xml b/autobuild.xml index e4b8f2e319..abdd3ec2d8 100644 --- a/autobuild.xml +++ b/autobuild.xml @@ -76,9 +76,9 @@ archive hash - 9b8bcc3be6dbe40a04c9c81c313f70dc + f3f49349055a525369a73139046a55a1 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/76345/727286/apr_suite-1.4.5.555520-darwin64-555520.tar.bz2 name darwin64 @@ -112,9 +112,9 @@ archive hash - 6bdf460c18ee004b41a46afc80041a92 + 0628a381c80cae621106e41a0b592bcd 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/76347/727295/apr_suite-1.4.5.555520-windows-555520.tar.bz2 name windows @@ -124,16 +124,16 @@ archive hash - 83104bfa4dabb77cd70d185e38a95b49 + 79fdb06371d6aeb29b52d593b2865f57 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/76346/727296/apr_suite-1.4.5.555520-windows64-555520.tar.bz2 name windows64 version - 1.4.5.548882 + 1.4.5.555520 boost @@ -398,9 +398,9 @@ archive hash - f5ae57117a6518d11f49ccfbfbe0969d + d4c8b00a88e879bd1a7e6805af2ccb1c 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/76361/727381/curl-7.54.1.555526-darwin64-555526.tar.bz2 name darwin64 @@ -434,11 +434,11 @@ archive hash - 2796ae7b09e730a55ac03f74ed669520 + 0bca1f79fc78b0045de18f69fea03093 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/76362/727375/curl-7.54.1.555526-windows-555526.tar.bz2 name windows @@ -448,16 +448,16 @@ archive hash - a8f96e5cdb8128b23d49ff4c3f2233a4 + cca8ff1d59fcfc64e99c79a950f3abc1 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/76360/727374/curl-7.54.1.555526-windows64-555526.tar.bz2 name windows64 version - 7.54.1.545369 + 7.54.1.555526 db @@ -670,9 +670,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 @@ -706,9 +706,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 @@ -718,16 +718,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 @@ -1078,9 +1078,9 @@ archive hash - 343913fe1434da228c2210c23d2e3a1a + a9eaa005ff9d387f946283fbcb69b3c8 url - http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/54850/510134/glod-1.0pre3.538980-darwin64-538980.tar.bz2 + https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/76353/727324/glod-1.0pre3.555522-darwin64-555522.tar.bz2 name darwin64 @@ -1139,7 +1139,7 @@ version - 1.0pre3.538980 + 1.0pre3.555522 google_breakpad @@ -1792,9 +1792,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 @@ -1828,9 +1828,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 @@ -1840,16 +1840,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 @@ -1882,9 +1882,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 @@ -1894,9 +1894,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 @@ -1906,16 +1906,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 @@ -2414,9 +2414,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 @@ -2450,9 +2450,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 @@ -2462,9 +2462,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 @@ -2473,7 +2473,7 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors source_type hg version - 1.40.0.545354 + 1.40.0.555524 nvapi From cbee72276dfee6d84175177b7132cd310912db33 Mon Sep 17 00:00:00 2001 From: Andrey Lihatskiy Date: Mon, 1 Feb 2021 03:27:52 +0200 Subject: [PATCH 071/443] DRTVWR-520 Updated xmlrpc-epi to codeticket build 555529 --- autobuild.xml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/autobuild.xml b/autobuild.xml index abdd3ec2d8..81a08e9462 100644 --- a/autobuild.xml +++ b/autobuild.xml @@ -3340,9 +3340,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 @@ -3376,9 +3376,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 @@ -3388,16 +3388,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 From 1fd44923b5e7f89fafe51471b7d83baf0339877d Mon Sep 17 00:00:00 2001 From: Andrey Lihatskiy Date: Mon, 1 Feb 2021 04:00:41 +0200 Subject: [PATCH 072/443] DRTVWR-520 Updated dullahan to codeticket build 555532 --- autobuild.xml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/autobuild.xml b/autobuild.xml index 81a08e9462..87bc308f85 100644 --- a/autobuild.xml +++ b/autobuild.xml @@ -580,9 +580,9 @@ archive hash - cc26af2ebfa241891caca829a6e46b88 + ecba88ae8fccfa5f52e51af596608c43 url - http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/65005/607316/dullahan-1.7.0.202008031101_81.3.10_gb223419_chromium-81.0.4044.138-darwin64-546064.tar.bz2 + https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/76379/727449/dullahan-1.7.0.202102010142_81.3.10_gb223419_chromium-81.0.4044.138-darwin64-555532.tar.bz2 name darwin64 @@ -592,9 +592,9 @@ archive hash - 4e5b9e2fe65d94e30a4f3d831c767199 + 612ce2190e068ac34dc76861b3762e4f url - http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/65004/607304/dullahan-1.7.0.202008031759_81.3.10_gb223419_chromium-81.0.4044.138-windows-546064.tar.bz2 + https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/76383/727462/dullahan-1.7.0.202102010146_81.3.10_gb223419_chromium-81.0.4044.138-windows-555532.tar.bz2 name windows @@ -604,16 +604,16 @@ archive hash - 6f7bf7f915f3d75dbdad08a2d41ca74e + 59468c3908a6e61e095cf7bc08023ef7 url - http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/65003/607308/dullahan-1.7.0.202008031800_81.3.10_gb223419_chromium-81.0.4044.138-windows64-546064.tar.bz2 + https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/76382/727466/dullahan-1.7.0.202102010146_81.3.10_gb223419_chromium-81.0.4044.138-windows64-555532.tar.bz2 name windows64 version - 1.7.0.202008031800_81.3.10_gb223419_chromium-81.0.4044.138 + 1.7.0.202102010146_81.3.10_gb223419_chromium-81.0.4044.138 elfio From 36064412c68468ebd6818c8409c7e59a72f050c8 Mon Sep 17 00:00:00 2001 From: Mnikolenko Productengine Date: Tue, 2 Feb 2021 17:28:10 +0200 Subject: [PATCH 073/443] SL-14800 Clarify message when maturity level exceeded --- .../skins/default/xui/en/notifications.xml | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml index 2f4da4f9b7..f2c56044b0 100644 --- a/indra/newview/skins/default/xui/en/notifications.xml +++ b/indra/newview/skins/default/xui/en/notifications.xml @@ -5058,7 +5058,9 @@ Do you wish to proceed? name="RegionEntryAccessBlocked" type="alertmodal"> fail - The region you're trying to visit contains content exceeding your current preferences. You can change your preferences using Me > Preferences > General. + The region you’re trying to visit has a maturity rating exceeding your maximum maturity preference. Change this preference using Me menu > Preferences > General. + +Complete information on maturity ratings can be found [https://community.secondlife.com/knowledgebase/english/maturity-ratings-r52/ here]. @@ -5145,7 +5147,9 @@ The region you're trying to visit contains [REGIONMATURITY] content, but your cu name="TeleportEntryAccessBlocked" type="alertmodal"> fail - The region you're trying to visit contains content exceeding your current preferences. You can change your preferences using Me > Preferences > General. + The region you’re trying to visit has a maturity rating exceeding your maximum maturity preference. Change this preference using Me menu > Preferences > General. + +Complete information on maturity ratings can be found [https://community.secondlife.com/knowledgebase/english/maturity-ratings-r52/ here]. @@ -5294,6 +5298,8 @@ You won't receive any more notifications that you're about to visit a region wit name="LandClaimAccessBlocked" type="alertmodal"> The land you're trying to claim has a maturity rating exceeding your current preferences. You can change your preferences using Me > Preferences > General. + +Complete information on maturity ratings can be found [https://community.secondlife.com/knowledgebase/english/maturity-ratings-r52/ here]. fail The land you're trying to buy has a maturity rating exceeding your current preferences. You can change your preferences using Me > Preferences > General. + +Complete information on maturity ratings can be found [https://community.secondlife.com/knowledgebase/english/maturity-ratings-r52/ here]. fail fail - The region you're trying to visit contains content exceeding your current preferences. You can change your preferences using Me > Preferences > General. - From 9d469bbb7cac8168a095f9ace5658f9d664c6593 Mon Sep 17 00:00:00 2001 From: Ansariel Date: Wed, 3 Feb 2021 23:39:57 +0100 Subject: [PATCH 074/443] Build fix --- indra/newview/llwearableitemslist.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/indra/newview/llwearableitemslist.cpp b/indra/newview/llwearableitemslist.cpp index be6c6f7ec4..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); From 2eea19876eb662d1cf29e6d1e3869b91abba14db Mon Sep 17 00:00:00 2001 From: Ansariel Date: Thu, 4 Feb 2021 00:01:53 +0100 Subject: [PATCH 075/443] Update German translation --- .../skins/default/xui/de/notifications.xml | 20 ++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/indra/newview/skins/default/xui/de/notifications.xml b/indra/newview/skins/default/xui/de/notifications.xml index 26c5d3fb04..6f4488c46d 100644 --- a/indra/newview/skins/default/xui/de/notifications.xml +++ b/indra/newview/skins/default/xui/de/notifications.xml @@ -2127,7 +2127,9 @@ Fortfahren? - Die Region, die Sie besuchen möchten, enthält Inhalte, die Ihre aktuellen Einstellungen überschreiten. Sie können Ihre Einstellungen unter „Avatar“ > „Einstellungen“ > „Allgemein“ ändern. + Die Region, die Sie besuchen möchten, besitzt eine Alterseinstufung, die Ihre aktuellen Einstellungen überschreiten. Sie können Ihre Einstellungen unter „Avatar“ > „Einstellungen“ > „Allgemein“ ändern. + +Vollständige Informationen zu Alterseinstufungen finden Sie [https://community.secondlife.com/knowledgebase/deutsche-knowledge-base/inhaltseinstufungen-r90/ hier]. @@ -2159,7 +2161,9 @@ Fortfahren? - Die Region, die Sie besuchen möchten, enthält Inhalte, die Ihre aktuellen Einstellungen überschreiten. Sie können Ihre Einstellungen unter „Avatar“ > „Einstellungen“ > „Allgemein“ ändern. + Die Region, die Sie besuchen möchten, besitzt eine Alterseinstufung, die Ihre aktuellen Einstellungen überschreiten. Sie können Ihre Einstellungen unter „Avatar“ > „Einstellungen“ > „Allgemein“ ändern. + +Vollständige Informationen zu Alterseinstufungen finden Sie [https://community.secondlife.com/knowledgebase/deutsche-knowledge-base/inhaltseinstufungen-r90/ hier]. @@ -2208,7 +2212,9 @@ Fortfahren? - Die Inhaltseinstufung des Landes, das Sie in Besitz nehmen möchten, überschreitet Ihre aktuellen Einstellungen. Sie können Ihre Einstellungen unter „Avatar“ > „Einstellungen“ > „Allgemein“ ändern. + Die Alterseinstufung des Landes, das Sie in Besitz nehmen möchten, überschreitet Ihre aktuellen Einstellungen. Sie können Ihre Einstellungen unter „Avatar“ > „Einstellungen“ > „Allgemein“ ändern. + +Vollständige Informationen zu Alterseinstufungen finden Sie [https://community.secondlife.com/knowledgebase/deutsche-knowledge-base/inhaltseinstufungen-r90/ hier]. @@ -2233,7 +2239,9 @@ Fortfahren? - Die Inhaltseinstufung des Landes, das Sie kaufen möchten, überschreitet Ihre aktuellen Einstellungen. Sie können Ihre Einstellungen unter „Avatar“ > „Einstellungen“ > „Allgemein“ ändern. + Die Alterseinstufung des Landes, das Sie kaufen möchten, überschreitet Ihre aktuellen Einstellungen. Sie können Ihre Einstellungen unter „Avatar“ > „Einstellungen“ > „Allgemein“ ändern. + +Vollständige Informationen zu Alterseinstufungen finden Sie [https://community.secondlife.com/knowledgebase/deutsche-knowledge-base/inhaltseinstufungen-r90/ hier]. @@ -2980,7 +2988,9 @@ Hier funktionieren nur Skripts, die dem Landeigentümer gehören. Öffentliches Land kann nur in der Region in Besitz genommen werden, in der Sie sich befinden. - Die Region, die Sie besuchen möchten, enthält Inhalte, die Ihre aktuellen Einstellungen überschreiten. Sie können Ihre Einstellungen unter „Avatar“ > „Einstellungen“ > „Allgemein“ ändern. + Die Region, die Sie besuchen möchten, besitzt eine Alterseinstufung, die Ihre aktuellen Einstellungen überschreiten. Sie können Ihre Einstellungen unter „Avatar“ > „Einstellungen“ > „Allgemein“ ändern. + +Vollständige Informationen zu Alterseinstufungen finden Sie [https://community.secondlife.com/knowledgebase/deutsche-knowledge-base/inhaltseinstufungen-r90/ hier]. Die Region, die Sie gerade betreten möchte, fährt gerade herunter. From fd8eab7e6126d5f92d0051bf551fa112dff198ac Mon Sep 17 00:00:00 2001 From: Andrey Lihatskiy Date: Wed, 10 Feb 2021 13:14:28 +0200 Subject: [PATCH 076/443] DRTVWR-520 Updated fmod to codeticket build 555876 --- autobuild.xml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/autobuild.xml b/autobuild.xml index 23ad979779..1f65879d77 100644 --- a/autobuild.xml +++ b/autobuild.xml @@ -748,9 +748,9 @@ archive hash - 89c37441a806ed80c0102d380eec6fd0 + 2995f0347fb20ae00a907c42ea5b4610 url - http://s3-proxy.lindenlab.com/private-builds-secondlife-com/ct2/65400/612632/fmodstudio-2.00.11.546392-darwin64-546392.tar.bz2 + https://s3-proxy.lindenlab.com/private-builds-secondlife-com/ct2/76852/730658/fmodstudio-2.01.07.555876-darwin64-555876.tar.bz2 name darwin64 @@ -784,9 +784,9 @@ archive hash - 0f44323b0d03b7d0d8a17eec83e103ce + d2d07717252e41f93afa4d6e5a4fee82 url - http://s3-proxy.lindenlab.com/private-builds-secondlife-com/ct2/65401/612647/fmodstudio-2.00.11.546392-windows-546392.tar.bz2 + https://s3-proxy.lindenlab.com/private-builds-secondlife-com/ct2/76854/730670/fmodstudio-2.01.07.555876-windows-555876.tar.bz2 name windows @@ -796,16 +796,16 @@ archive hash - 462d28eacf731a5d36ab031e7071c32a + 88c9e27c6b69e1833dadf4f23686f34a url - http://s3-proxy.lindenlab.com/private-builds-secondlife-com/ct2/65402/612648/fmodstudio-2.00.11.546392-windows64-546392.tar.bz2 + https://s3-proxy.lindenlab.com/private-builds-secondlife-com/ct2/76853/730669/fmodstudio-2.01.07.555876-windows64-555876.tar.bz2 name windows64 version - 2.00.11.546392 + 2.01.07.555876 fontconfig From 127446d9c84609aa2740f2987371999057753781 Mon Sep 17 00:00:00 2001 From: Andrey Lihatskiy Date: Wed, 10 Feb 2021 13:39:10 +0200 Subject: [PATCH 077/443] xcode buildfix --- indra/llplugin/llpluginprocessparent.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/indra/llplugin/llpluginprocessparent.cpp b/indra/llplugin/llpluginprocessparent.cpp index 7d18bae947..e5b4dec1bd 100644 --- a/indra/llplugin/llpluginprocessparent.cpp +++ b/indra/llplugin/llpluginprocessparent.cpp @@ -154,9 +154,9 @@ void LLPluginProcessParent::shutdown() { EState state = (*it).second->mState; if (state != STATE_CLEANUP - || state != STATE_EXITING - || state != STATE_DONE - || state != STATE_ERROR) + && state != STATE_EXITING + && state != STATE_DONE + && state != STATE_ERROR) { (*it).second->setState(STATE_GOODBYE); } From fc166dabc08d44b0956a43130cd2bd2e6722b854 Mon Sep 17 00:00:00 2001 From: Andrey Lihatskiy Date: Wed, 10 Feb 2021 15:59:04 +0200 Subject: [PATCH 078/443] DRTVWR-520 Updated fmod to codeticket build 555883 --- autobuild.xml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/autobuild.xml b/autobuild.xml index 1f65879d77..31f0a4e3cb 100644 --- a/autobuild.xml +++ b/autobuild.xml @@ -748,9 +748,9 @@ archive hash - 2995f0347fb20ae00a907c42ea5b4610 + d5528538e67c710387ae0c061a90cb23 url - https://s3-proxy.lindenlab.com/private-builds-secondlife-com/ct2/76852/730658/fmodstudio-2.01.07.555876-darwin64-555876.tar.bz2 + https://s3-proxy.lindenlab.com/private-builds-secondlife-com/ct2/76868/730756/fmodstudio-2.01.07.555883-darwin64-555883.tar.bz2 name darwin64 @@ -784,9 +784,9 @@ archive hash - d2d07717252e41f93afa4d6e5a4fee82 + a2bb6eaf51f933993b26a5fe7503a761 url - https://s3-proxy.lindenlab.com/private-builds-secondlife-com/ct2/76854/730670/fmodstudio-2.01.07.555876-windows-555876.tar.bz2 + https://s3-proxy.lindenlab.com/private-builds-secondlife-com/ct2/76869/730763/fmodstudio-2.01.07.555883-windows-555883.tar.bz2 name windows @@ -796,16 +796,16 @@ archive hash - 88c9e27c6b69e1833dadf4f23686f34a + 138d07dd516a9ad5b9787192fe6134dd url - https://s3-proxy.lindenlab.com/private-builds-secondlife-com/ct2/76853/730669/fmodstudio-2.01.07.555876-windows64-555876.tar.bz2 + https://s3-proxy.lindenlab.com/private-builds-secondlife-com/ct2/76867/730751/fmodstudio-2.01.07.555883-windows64-555883.tar.bz2 name windows64 version - 2.01.07.555876 + 2.01.07.555883 fontconfig From e320a463ac20cd064707f66f95d7e91531c7bb29 Mon Sep 17 00:00:00 2001 From: Andrey Lihatskiy Date: Wed, 10 Feb 2021 22:02:59 +0200 Subject: [PATCH 079/443] DRTVWR-520 Updated dullahan to codeticket build 555904 --- autobuild.xml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/autobuild.xml b/autobuild.xml index 31f0a4e3cb..61ea281b99 100644 --- a/autobuild.xml +++ b/autobuild.xml @@ -580,9 +580,9 @@ archive hash - ecba88ae8fccfa5f52e51af596608c43 + 46124156a4148d61c849d328c8659f78 url - https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/76379/727449/dullahan-1.7.0.202102010142_81.3.10_gb223419_chromium-81.0.4044.138-darwin64-555532.tar.bz2 + https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/76900/730915/dullahan-1.7.0.202102101914_81.3.10_gb223419_chromium-81.0.4044.138-darwin64-555904.tar.bz2 name darwin64 @@ -592,9 +592,9 @@ archive hash - 612ce2190e068ac34dc76861b3762e4f + d801e6c21333c94a7a04177aa91d5c1c url - https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/76383/727462/dullahan-1.7.0.202102010146_81.3.10_gb223419_chromium-81.0.4044.138-windows-555532.tar.bz2 + https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/76901/730924/dullahan-1.7.0.202102101918_81.3.10_gb223419_chromium-81.0.4044.138-windows-555904.tar.bz2 name windows @@ -604,16 +604,16 @@ archive hash - 59468c3908a6e61e095cf7bc08023ef7 + dde4748dca0a75c6af30eca584e43352 url - https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/76382/727466/dullahan-1.7.0.202102010146_81.3.10_gb223419_chromium-81.0.4044.138-windows64-555532.tar.bz2 + https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/76902/730930/dullahan-1.7.0.202102101918_81.3.10_gb223419_chromium-81.0.4044.138-windows64-555904.tar.bz2 name windows64 version - 1.7.0.202102010146_81.3.10_gb223419_chromium-81.0.4044.138 + 1.7.0.202102101918_81.3.10_gb223419_chromium-81.0.4044.138 elfio From 8f717b988ad6a1bc7156d0779b5c7e424c6bf932 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Fri, 19 Feb 2021 00:01:15 +0200 Subject: [PATCH 080/443] build fix --- indra/newview/llwearableitemslist.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/indra/newview/llwearableitemslist.cpp b/indra/newview/llwearableitemslist.cpp index a5b81d92e6..bf4db81475 100644 --- a/indra/newview/llwearableitemslist.cpp +++ b/indra/newview/llwearableitemslist.cpp @@ -820,7 +820,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); From c2660c152fd5b86d6b8d2fc9053799ad0102962d Mon Sep 17 00:00:00 2001 From: Andrey Lihatskiy Date: Tue, 23 Feb 2021 23:07:12 +0200 Subject: [PATCH 081/443] DRTVWR-520 Updated boost to codeticket build 556301 --- autobuild.xml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/autobuild.xml b/autobuild.xml index 61ea281b99..01e471813a 100644 --- a/autobuild.xml +++ b/autobuild.xml @@ -166,9 +166,9 @@ archive hash - 3cc73623c9a976b4f8346a3837f7a916 + 3c0e9cfeb2a1c099a068aa999a54a1ce 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/77456/734789/boost-1.72-darwin64-556301.tar.bz2 name darwin64 @@ -202,9 +202,9 @@ archive hash - 7d4b2511976449e9a4ec7be41dc8310f + 2f5b314539617871e9d104f1f83f0ccd 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/77458/734770/boost-1.72-windows-556301.tar.bz2 name windows @@ -214,9 +214,9 @@ archive hash - 4ad8df0700745201cddf6b71d7b0949f + e8cdfffa30c85229befb0c901fedb7e3 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/77459/734776/boost-1.72-windows64-556301.tar.bz2 name windows64 From a0335671d527d40c3be50bf877837da2dc979096 Mon Sep 17 00:00:00 2001 From: Andrey Lihatskiy Date: Tue, 23 Feb 2021 23:34:25 +0200 Subject: [PATCH 082/443] DRTVWR-520 Updated googlemock to codeticket build 556304 --- autobuild.xml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/autobuild.xml b/autobuild.xml index 01e471813a..2d1e68afa5 100644 --- a/autobuild.xml +++ b/autobuild.xml @@ -1262,9 +1262,9 @@ archive hash - f9831360ced94943ab9dfb3fbf5256d3 + e280519baadf8369b4d7d1cd00506b49 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/77465/734807/googlemock-1.7.0.556304-darwin64-556304.tar.bz2 name darwin64 @@ -1298,9 +1298,9 @@ archive hash - 8149e46b4f7abb3ac284415cfe1366e1 + d4d5b681cb2d0a214bba2ad54a36dea9 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/77466/734805/googlemock-1.7.0.556304-windows-556304.tar.bz2 name windows @@ -1310,16 +1310,16 @@ archive hash - f3851eba809ead2810d702041569d36d + 5dfc8cc3160a6954757cebdeaaa30376 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/77467/734815/googlemock-1.7.0.556304-windows64-556304.tar.bz2 name windows64 version - 1.7.0.545363 + 1.7.0.556304 gstreamer From 5f4f0d2936d8ca5f58be4be7572c3207b304a3b0 Mon Sep 17 00:00:00 2001 From: Andrey Lihatskiy Date: Tue, 23 Feb 2021 23:59:11 +0200 Subject: [PATCH 083/443] DRTVWR-520 Updated colladadom to codeticket build 556305 --- autobuild.xml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/autobuild.xml b/autobuild.xml index 2d1e68afa5..c3d7c03121 100644 --- a/autobuild.xml +++ b/autobuild.xml @@ -308,9 +308,9 @@ archive hash - 02e6a8207dcdaf243dcb6da19b8c3534 + 3250ad7a5e12e8656b0aa4701b38ad3a 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/77469/734822/colladadom-2.3.556305-darwin64-556305.tar.bz2 name darwin64 @@ -344,9 +344,9 @@ archive hash - 8a02a10fc69c8f504dc5335644db184a + 20b8a8395bbd8e86f48c75bf8fc2e642 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/77468/734828/colladadom-2.3.556305-windows-556305.tar.bz2 name windows @@ -356,16 +356,16 @@ archive hash - 742180324fca7ab92b6a61a36aab4f9d + bc88fdd32fd7d005c7dfc58c82260a29 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/77470/734834/colladadom-2.3.556305-windows64-556305.tar.bz2 name windows64 version - 2.3.545362 + 2.3.556305 curl From 2d4a894b706d0dcbdc753318c2c400b0d3ee92b7 Mon Sep 17 00:00:00 2001 From: Mnikolenko Productengine Date: Thu, 25 Feb 2021 16:55:11 +0200 Subject: [PATCH 084/443] SL-14901 Add a button on the Landmarks bar to open the Places floater --- indra/newview/llfavoritesbar.cpp | 2 +- indra/newview/llnavigationbar.cpp | 10 +++++++ indra/newview/llnavigationbar.h | 2 ++ indra/newview/llpanellandmarks.cpp | 11 ++++++-- indra/newview/llpanellandmarks.h | 3 +++ indra/newview/llpanelplaces.cpp | 4 +++ .../default/xui/en/panel_navigation_bar.xml | 26 ++++++++++++++----- 7 files changed, 49 insertions(+), 9 deletions(-) diff --git a/indra/newview/llfavoritesbar.cpp b/indra/newview/llfavoritesbar.cpp index c76920c9ce..6e01c82fe1 100644 --- a/indra/newview/llfavoritesbar.cpp +++ b/indra/newview/llfavoritesbar.cpp @@ -847,7 +847,7 @@ void LLFavoritesBarCtrl::updateButtons(bool force_update) int j = first_changed_item_index; for (; j < mItems.size(); j++) { - last_new_button = createButton(mItems[j], button_params, last_right_edge); + last_new_button = createButton(mItems[j], button_params, j == 0? last_right_edge + 4 : last_right_edge); if (!last_new_button) { break; diff --git a/indra/newview/llnavigationbar.cpp b/indra/newview/llnavigationbar.cpp index 179c64b5c5..19dbbeb60e 100644 --- a/indra/newview/llnavigationbar.cpp +++ b/indra/newview/llnavigationbar.cpp @@ -58,6 +58,7 @@ #include "llweb.h" #include "llhints.h" +#include "llfloatersidepanelcontainer.h" #include "llinventorymodel.h" #include "lllandmarkactions.h" @@ -290,6 +291,7 @@ BOOL LLNavigationBar::postBuild() mBtnBack = getChild("back_btn"); mBtnForward = getChild("forward_btn"); mBtnHome = getChild("home_btn"); + mBtnLandmarks = getChild("landmarks_btn"); mCmbLocation= getChild("location_combo"); @@ -305,6 +307,8 @@ BOOL LLNavigationBar::postBuild() mBtnHome->setClickedCallback(boost::bind(&LLNavigationBar::onHomeButtonClicked, this)); + mBtnLandmarks->setClickedCallback(boost::bind(&LLNavigationBar::onLandmarksButtonClicked, this)); + mCmbLocation->setCommitCallback(boost::bind(&LLNavigationBar::onLocationSelection, this)); mTeleportFinishConnection = LLViewerParcelMgr::getInstance()-> @@ -401,6 +405,12 @@ void LLNavigationBar::onHomeButtonClicked() gAgent.teleportHome(); } +void LLNavigationBar::onLandmarksButtonClicked() +{ + LLFloaterReg::toggleInstanceOrBringToFront("places"); + LLFloaterSidePanelContainer::showPanel("places", LLSD().with("type", "open_landmark_tab")); +} + void LLNavigationBar::onTeleportHistoryMenuItemClicked(const LLSD& userdata) { int idx = userdata.asInteger(); diff --git a/indra/newview/llnavigationbar.h b/indra/newview/llnavigationbar.h index a44c6dd699..646911a62c 100755 --- a/indra/newview/llnavigationbar.h +++ b/indra/newview/llnavigationbar.h @@ -119,6 +119,7 @@ private: void onNavigationButtonHeldUp(LLButton* nav_button); void onForwardButtonClicked(); void onHomeButtonClicked(); + void onLandmarksButtonClicked(); void onLocationSelection(); void onLocationPrearrange(const LLSD& data); void onTeleportFinished(const LLVector3d& global_agent_pos); @@ -144,6 +145,7 @@ private: LLPullButton* mBtnBack; LLPullButton* mBtnForward; LLButton* mBtnHome; + LLButton* mBtnLandmarks; LLLocationInputCtrl* mCmbLocation; LLRect mDefaultNbRect; LLRect mDefaultFpRect; diff --git a/indra/newview/llpanellandmarks.cpp b/indra/newview/llpanellandmarks.cpp index ccd8497484..d763a6e1ec 100644 --- a/indra/newview/llpanellandmarks.cpp +++ b/indra/newview/llpanellandmarks.cpp @@ -65,6 +65,7 @@ static const std::string ADD_BUTTON_NAME = "add_btn"; static const std::string ADD_FOLDER_BUTTON_NAME = "add_folder_btn"; static const std::string TRASH_BUTTON_NAME = "trash_btn"; +static const std::string TAB_FAVORITES = "tab_favorites"; // helper functions static void filter_list(LLPlacesInventoryPanel* inventory_list, const std::string& string); @@ -383,7 +384,7 @@ void LLLandmarksPanel::updateShowFolderState() void LLLandmarksPanel::setItemSelected(const LLUUID& obj_id, BOOL take_keyboard_focus) { - if (selectItemInAccordionTab(mFavoritesInventoryPanel, "tab_favorites", obj_id, take_keyboard_focus)) + if (selectItemInAccordionTab(mFavoritesInventoryPanel, TAB_FAVORITES, obj_id, take_keyboard_focus)) { return; } @@ -506,6 +507,12 @@ void LLLandmarksPanel::updateSortOrder(LLInventoryPanel* panel, bool byDate) } } +void LLLandmarksPanel::resetSelection() +{ + getChild(TAB_FAVORITES)->setDisplayChildren(true); + getChild(TAB_FAVORITES)->showAndFocusHeader(); +} + // virtual void LLLandmarksPanel::processParcelInfo(const LLParcelData& parcel_data) { @@ -550,7 +557,7 @@ void LLLandmarksPanel::initFavoritesInventoryPanel() initLandmarksPanel(mFavoritesInventoryPanel); mFavoritesInventoryPanel->getFilter().setEmptyLookupMessage("FavoritesNoMatchingItems"); - initAccordion("tab_favorites", mFavoritesInventoryPanel, true); + initAccordion(TAB_FAVORITES, mFavoritesInventoryPanel, true); } void LLLandmarksPanel::initLandmarksInventoryPanel() diff --git a/indra/newview/llpanellandmarks.h b/indra/newview/llpanellandmarks.h index c11cbe05ae..2031501f5d 100644 --- a/indra/newview/llpanellandmarks.h +++ b/indra/newview/llpanellandmarks.h @@ -82,6 +82,8 @@ public: void updateMenuVisibility(LLUICtrl* menu); + void resetSelection(); + protected: /** * @return true - if current selected panel is not null and selected item is a landmark @@ -105,6 +107,7 @@ protected: void updateSortOrder(LLInventoryPanel* panel, bool byDate); + //LLRemoteParcelInfoObserver interface /*virtual*/ void processParcelInfo(const LLParcelData& parcel_data); /*virtual*/ void setParcelID(const LLUUID& parcel_id); diff --git a/indra/newview/llpanelplaces.cpp b/indra/newview/llpanelplaces.cpp index 53870fb5c7..1f3f58ffa3 100644 --- a/indra/newview/llpanelplaces.cpp +++ b/indra/newview/llpanelplaces.cpp @@ -1056,6 +1056,10 @@ void LLPanelPlaces::togglePlaceInfoPanel(BOOL visible) { landmarks_panel->setItemSelected(mItem->getUUID(), TRUE); } + else + { + landmarks_panel->resetSelection(); + } } } } diff --git a/indra/newview/skins/default/xui/en/panel_navigation_bar.xml b/indra/newview/skins/default/xui/en/panel_navigation_bar.xml index c7edba21f8..2d5f22d0d8 100644 --- a/indra/newview/skins/default/xui/en/panel_navigation_bar.xml +++ b/indra/newview/skins/default/xui/en/panel_navigation_bar.xml @@ -151,7 +151,7 @@ layout="topleft" auto_resize="true" user_resize="true" - min_width="185" + min_width="237" name="favorites_layout_panel" width="320"> - + + width="268"> Date: Thu, 25 Feb 2021 20:25:56 +0200 Subject: [PATCH 085/443] Revert "SL-14901 Add a button on the Landmarks bar to open the Places floater" This reverts commit 2d4a894b706d0dcbdc753318c2c400b0d3ee92b7. --- indra/newview/llfavoritesbar.cpp | 2 +- indra/newview/llnavigationbar.cpp | 10 ------- indra/newview/llnavigationbar.h | 2 -- indra/newview/llpanellandmarks.cpp | 11 ++------ indra/newview/llpanellandmarks.h | 3 --- indra/newview/llpanelplaces.cpp | 4 --- .../default/xui/en/panel_navigation_bar.xml | 26 +++++-------------- 7 files changed, 9 insertions(+), 49 deletions(-) diff --git a/indra/newview/llfavoritesbar.cpp b/indra/newview/llfavoritesbar.cpp index 6e01c82fe1..c76920c9ce 100644 --- a/indra/newview/llfavoritesbar.cpp +++ b/indra/newview/llfavoritesbar.cpp @@ -847,7 +847,7 @@ void LLFavoritesBarCtrl::updateButtons(bool force_update) int j = first_changed_item_index; for (; j < mItems.size(); j++) { - last_new_button = createButton(mItems[j], button_params, j == 0? last_right_edge + 4 : last_right_edge); + last_new_button = createButton(mItems[j], button_params, last_right_edge); if (!last_new_button) { break; diff --git a/indra/newview/llnavigationbar.cpp b/indra/newview/llnavigationbar.cpp index 19dbbeb60e..179c64b5c5 100644 --- a/indra/newview/llnavigationbar.cpp +++ b/indra/newview/llnavigationbar.cpp @@ -58,7 +58,6 @@ #include "llweb.h" #include "llhints.h" -#include "llfloatersidepanelcontainer.h" #include "llinventorymodel.h" #include "lllandmarkactions.h" @@ -291,7 +290,6 @@ BOOL LLNavigationBar::postBuild() mBtnBack = getChild("back_btn"); mBtnForward = getChild("forward_btn"); mBtnHome = getChild("home_btn"); - mBtnLandmarks = getChild("landmarks_btn"); mCmbLocation= getChild("location_combo"); @@ -307,8 +305,6 @@ BOOL LLNavigationBar::postBuild() mBtnHome->setClickedCallback(boost::bind(&LLNavigationBar::onHomeButtonClicked, this)); - mBtnLandmarks->setClickedCallback(boost::bind(&LLNavigationBar::onLandmarksButtonClicked, this)); - mCmbLocation->setCommitCallback(boost::bind(&LLNavigationBar::onLocationSelection, this)); mTeleportFinishConnection = LLViewerParcelMgr::getInstance()-> @@ -405,12 +401,6 @@ void LLNavigationBar::onHomeButtonClicked() gAgent.teleportHome(); } -void LLNavigationBar::onLandmarksButtonClicked() -{ - LLFloaterReg::toggleInstanceOrBringToFront("places"); - LLFloaterSidePanelContainer::showPanel("places", LLSD().with("type", "open_landmark_tab")); -} - void LLNavigationBar::onTeleportHistoryMenuItemClicked(const LLSD& userdata) { int idx = userdata.asInteger(); diff --git a/indra/newview/llnavigationbar.h b/indra/newview/llnavigationbar.h index 646911a62c..a44c6dd699 100755 --- a/indra/newview/llnavigationbar.h +++ b/indra/newview/llnavigationbar.h @@ -119,7 +119,6 @@ private: void onNavigationButtonHeldUp(LLButton* nav_button); void onForwardButtonClicked(); void onHomeButtonClicked(); - void onLandmarksButtonClicked(); void onLocationSelection(); void onLocationPrearrange(const LLSD& data); void onTeleportFinished(const LLVector3d& global_agent_pos); @@ -145,7 +144,6 @@ private: LLPullButton* mBtnBack; LLPullButton* mBtnForward; LLButton* mBtnHome; - LLButton* mBtnLandmarks; LLLocationInputCtrl* mCmbLocation; LLRect mDefaultNbRect; LLRect mDefaultFpRect; diff --git a/indra/newview/llpanellandmarks.cpp b/indra/newview/llpanellandmarks.cpp index d763a6e1ec..ccd8497484 100644 --- a/indra/newview/llpanellandmarks.cpp +++ b/indra/newview/llpanellandmarks.cpp @@ -65,7 +65,6 @@ static const std::string ADD_BUTTON_NAME = "add_btn"; static const std::string ADD_FOLDER_BUTTON_NAME = "add_folder_btn"; static const std::string TRASH_BUTTON_NAME = "trash_btn"; -static const std::string TAB_FAVORITES = "tab_favorites"; // helper functions static void filter_list(LLPlacesInventoryPanel* inventory_list, const std::string& string); @@ -384,7 +383,7 @@ void LLLandmarksPanel::updateShowFolderState() void LLLandmarksPanel::setItemSelected(const LLUUID& obj_id, BOOL take_keyboard_focus) { - if (selectItemInAccordionTab(mFavoritesInventoryPanel, TAB_FAVORITES, obj_id, take_keyboard_focus)) + if (selectItemInAccordionTab(mFavoritesInventoryPanel, "tab_favorites", obj_id, take_keyboard_focus)) { return; } @@ -507,12 +506,6 @@ void LLLandmarksPanel::updateSortOrder(LLInventoryPanel* panel, bool byDate) } } -void LLLandmarksPanel::resetSelection() -{ - getChild(TAB_FAVORITES)->setDisplayChildren(true); - getChild(TAB_FAVORITES)->showAndFocusHeader(); -} - // virtual void LLLandmarksPanel::processParcelInfo(const LLParcelData& parcel_data) { @@ -557,7 +550,7 @@ void LLLandmarksPanel::initFavoritesInventoryPanel() initLandmarksPanel(mFavoritesInventoryPanel); mFavoritesInventoryPanel->getFilter().setEmptyLookupMessage("FavoritesNoMatchingItems"); - initAccordion(TAB_FAVORITES, mFavoritesInventoryPanel, true); + initAccordion("tab_favorites", mFavoritesInventoryPanel, true); } void LLLandmarksPanel::initLandmarksInventoryPanel() diff --git a/indra/newview/llpanellandmarks.h b/indra/newview/llpanellandmarks.h index 2031501f5d..c11cbe05ae 100644 --- a/indra/newview/llpanellandmarks.h +++ b/indra/newview/llpanellandmarks.h @@ -82,8 +82,6 @@ public: void updateMenuVisibility(LLUICtrl* menu); - void resetSelection(); - protected: /** * @return true - if current selected panel is not null and selected item is a landmark @@ -107,7 +105,6 @@ protected: void updateSortOrder(LLInventoryPanel* panel, bool byDate); - //LLRemoteParcelInfoObserver interface /*virtual*/ void processParcelInfo(const LLParcelData& parcel_data); /*virtual*/ void setParcelID(const LLUUID& parcel_id); diff --git a/indra/newview/llpanelplaces.cpp b/indra/newview/llpanelplaces.cpp index 1f3f58ffa3..53870fb5c7 100644 --- a/indra/newview/llpanelplaces.cpp +++ b/indra/newview/llpanelplaces.cpp @@ -1056,10 +1056,6 @@ void LLPanelPlaces::togglePlaceInfoPanel(BOOL visible) { landmarks_panel->setItemSelected(mItem->getUUID(), TRUE); } - else - { - landmarks_panel->resetSelection(); - } } } } diff --git a/indra/newview/skins/default/xui/en/panel_navigation_bar.xml b/indra/newview/skins/default/xui/en/panel_navigation_bar.xml index 2d5f22d0d8..c7edba21f8 100644 --- a/indra/newview/skins/default/xui/en/panel_navigation_bar.xml +++ b/indra/newview/skins/default/xui/en/panel_navigation_bar.xml @@ -151,7 +151,7 @@ layout="topleft" auto_resize="true" user_resize="true" - min_width="237" + min_width="185" name="favorites_layout_panel" width="320"> - + + width="320"> Date: Mon, 22 Feb 2021 23:42:48 +0200 Subject: [PATCH 086/443] xcode buildfix --- indra/llcommon/llsingleton.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/indra/llcommon/llsingleton.cpp b/indra/llcommon/llsingleton.cpp index 83a4b64e8f..ad933154c2 100644 --- a/indra/llcommon/llsingleton.cpp +++ b/indra/llcommon/llsingleton.cpp @@ -388,7 +388,7 @@ LLSingletonBase::vec_t LLSingletonBase::dep_sort() // extracts just the first (key) element from each sorted_iterator, then // uses vec_t's range constructor... but frankly this is more // straightforward, as long as we remember the above reserve() call! - for (const SingletonDeps::sorted_iterator::value_type& pair : sdeps.sort()) + for (const SingletonDeps::sorted_iterator::value_type pair : sdeps.sort()) { ret.push_back(pair.first); } From 925feaaf95b43f2380a4f375ac9b6419d05732f6 Mon Sep 17 00:00:00 2001 From: Mnikolenko Productengine Date: Thu, 4 Mar 2021 12:06:12 +0200 Subject: [PATCH 087/443] SL-14941 FIXED Cannot upload large images on the Simplified Cache Viewer. --- doc/contributions.txt | 1 + indra/newview/llviewerassetstorage.cpp | 2 +- indra/newview/llviewerassetupload.cpp | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/doc/contributions.txt b/doc/contributions.txt index bbdfaf655d..120c737d7a 100755 --- a/doc/contributions.txt +++ b/doc/contributions.txt @@ -226,6 +226,7 @@ Ansariel Hiller SL-13364 SL-13858 SL-13697 + SL-14941 Aralara Rajal Arare Chantilly CHUIBUG-191 diff --git a/indra/newview/llviewerassetstorage.cpp b/indra/newview/llviewerassetstorage.cpp index 5b76d57196..0f2901406a 100644 --- a/indra/newview/llviewerassetstorage.cpp +++ b/indra/newview/llviewerassetstorage.cpp @@ -291,7 +291,7 @@ void LLViewerAssetStorage::storeAssetData( legacy->mUpCallback = callback; legacy->mUserData = user_data; - 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]; diff --git a/indra/newview/llviewerassetupload.cpp b/indra/newview/llviewerassetupload.cpp index 1923e7d6ff..7b5229d312 100644 --- a/indra/newview/llviewerassetupload.cpp +++ b/indra/newview/llviewerassetupload.cpp @@ -473,7 +473,7 @@ LLSD LLNewFileResourceUploadInfo::exportTempFile() infile.open(filename, LL_APR_RB, NULL, &file_size); if (infile.getFileHandle()) { - LLFileSystem file(getAssetId(), assetType, LLFileSystem::WRITE); + LLFileSystem file(getAssetId(), assetType, LLFileSystem::APPEND); const S32 buf_size = 65536; U8 copy_buf[buf_size]; From 87908bab6d7a0283e7195566dd99926a4c8401b1 Mon Sep 17 00:00:00 2001 From: Mnikolenko Productengine Date: Thu, 4 Mar 2021 12:23:57 +0200 Subject: [PATCH 088/443] SL-14939 Fixed the log spam --- doc/contributions.txt | 1 + indra/llfilesystem/llfilesystem.cpp | 6 +++--- indra/llfilesystem/llfilesystem.h | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/doc/contributions.txt b/doc/contributions.txt index 120c737d7a..877d38c2a1 100755 --- a/doc/contributions.txt +++ b/doc/contributions.txt @@ -226,6 +226,7 @@ Ansariel Hiller SL-13364 SL-13858 SL-13697 + SL-14939 SL-14941 Aralara Rajal Arare Chantilly diff --git a/indra/llfilesystem/llfilesystem.cpp b/indra/llfilesystem/llfilesystem.cpp index 64e0b9f193..053b52014e 100644 --- a/indra/llfilesystem/llfilesystem.cpp +++ b/indra/llfilesystem/llfilesystem.cpp @@ -72,14 +72,14 @@ bool LLFileSystem::getExists(const LLUUID& file_id, const LLAssetType::EType fil } // static -bool LLFileSystem::removeFile(const LLUUID& file_id, const LLAssetType::EType file_type) +bool LLFileSystem::removeFile(const LLUUID& file_id, const LLAssetType::EType file_type, int suppress_error /*= 0*/) { std::string id_str; file_id.toString(id_str); const std::string extra_info = ""; const std::string filename = LLDiskCache::getInstance()->metaDataToFilepath(id_str, file_type, extra_info); - LLFile::remove(filename.c_str()); + LLFile::remove(filename.c_str(), suppress_error); return true; } @@ -98,7 +98,7 @@ bool LLFileSystem::renameFile(const LLUUID& old_file_id, const LLAssetType::ETyp const std::string new_filename = LLDiskCache::getInstance()->metaDataToFilepath(new_id_str, new_file_type, extra_info); // Rename needs the new file to not exist. - LLFileSystem::removeFile(new_file_id, new_file_type); + LLFileSystem::removeFile(new_file_id, new_file_type, ENOENT); if (LLFile::rename(old_filename, new_filename) != 0) { diff --git a/indra/llfilesystem/llfilesystem.h b/indra/llfilesystem/llfilesystem.h index 89bfff5798..d934a408c2 100644 --- a/indra/llfilesystem/llfilesystem.h +++ b/indra/llfilesystem/llfilesystem.h @@ -54,7 +54,7 @@ class LLFileSystem BOOL remove(); static bool getExists(const LLUUID& file_id, const LLAssetType::EType file_type); - static bool removeFile(const LLUUID& file_id, const LLAssetType::EType file_type); + static bool removeFile(const LLUUID& file_id, const LLAssetType::EType file_type, int suppress_error = 0); static bool renameFile(const LLUUID& old_file_id, const LLAssetType::EType old_file_type, const LLUUID& new_file_id, const LLAssetType::EType new_file_type); static S32 getFileSize(const LLUUID& file_id, const LLAssetType::EType file_type); From ada8ad1bc21665631f030c3194a567ea6f6a2a72 Mon Sep 17 00:00:00 2001 From: Mnikolenko Productengine Date: Thu, 4 Mar 2021 12:49:48 +0200 Subject: [PATCH 089/443] SL-14940 Fixed ignoring custom cache path --- doc/contributions.txt | 1 + indra/newview/llappviewer.cpp | 5 +++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/doc/contributions.txt b/doc/contributions.txt index 877d38c2a1..bf95989f19 100755 --- a/doc/contributions.txt +++ b/doc/contributions.txt @@ -227,6 +227,7 @@ Ansariel Hiller SL-13858 SL-13697 SL-14939 + SL-14940 SL-14941 Aralara Rajal Arare Chantilly diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index ea0b950e62..6ede9ec0e7 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -4132,8 +4132,6 @@ bool LLAppViewer::initCache() const unsigned int disk_cache_mb = cache_total_size_mb * disk_cache_percent / 100; const unsigned int disk_cache_bytes = disk_cache_mb * 1024 * 1024; const bool enable_cache_debug_info = gSavedSettings.getBOOL("EnableDiskCacheDebugInfo"); - const std::string cache_dir = gDirUtilp->getExpandedFilename(LL_PATH_CACHE, cache_dir_name); - LLDiskCache::initParamSingleton(cache_dir, disk_cache_bytes, enable_cache_debug_info); bool texture_cache_mismatch = false; if (gSavedSettings.getS32("LocalCacheVersion") != LLAppViewer::getTextureCacheVersion()) @@ -4181,6 +4179,9 @@ bool LLAppViewer::initCache() gSavedSettings.setString("CacheLocationTopFolder", ""); } + const std::string cache_dir = gDirUtilp->getExpandedFilename(LL_PATH_CACHE, cache_dir_name); + LLDiskCache::initParamSingleton(cache_dir, disk_cache_bytes, enable_cache_debug_info); + if (!read_only) { if (mPurgeCache) From 168d177197bd7558bbe0ca13d01c984ad8638da7 Mon Sep 17 00:00:00 2001 From: Callum Prentice Date: Tue, 9 Mar 2021 14:39:51 -0800 Subject: [PATCH 090/443] This set of changes reverts the merge with master (git revert c83e740) and results in a version of the DRTVWR-519 that matches what was presemt before it was deployed as a release viewer *plus* 3 small fixes from Maxim (See commits). This branch can now be used for additional fixes before eventually being used to release D-519 as normal --- README.md | 1 + indra/CMakeLists.txt | 2 +- indra/cmake/00-Common.cmake | 3 +- indra/cmake/CMakeLists.txt | 2 +- indra/cmake/LLFileSystem.cmake | 7 + indra/cmake/LLVFS.cmake | 7 - .../llimage_libtest/CMakeLists.txt | 6 +- .../llui_libtest/CMakeLists.txt | 4 +- indra/linux_crash_logger/CMakeLists.txt | 7 +- indra/llappearance/CMakeLists.txt | 20 +- indra/llappearance/lltexlayer.cpp | 2 - indra/llaudio/CMakeLists.txt | 6 +- indra/llaudio/llaudiodecodemgr.cpp | 58 +- indra/llaudio/llaudiodecodemgr.h | 1 - indra/llaudio/llaudioengine.cpp | 15 +- indra/llaudio/llaudioengine.h | 13 +- indra/llcharacter/CMakeLists.txt | 18 +- indra/llcharacter/llkeyframefallmotion.cpp | 5 + indra/llcharacter/llkeyframemotion.cpp | 21 +- indra/llcharacter/llkeyframemotion.h | 12 +- indra/llcommon/llerror.cpp | 61 +- indra/llcrashlogger/CMakeLists.txt | 4 +- indra/llcrashlogger/llcrashlock.h | 2 +- indra/{llvfs => llfilesystem}/CMakeLists.txt | 57 +- indra/{llvfs => llfilesystem}/lldir.cpp | 0 indra/{llvfs => llfilesystem}/lldir.h | 0 indra/{llvfs => llfilesystem}/lldir_linux.cpp | 0 indra/{llvfs => llfilesystem}/lldir_linux.h | 0 indra/{llvfs => llfilesystem}/lldir_mac.cpp | 2 +- indra/{llvfs => llfilesystem}/lldir_mac.h | 0 .../{llvfs => llfilesystem}/lldir_solaris.cpp | 0 indra/{llvfs => llfilesystem}/lldir_solaris.h | 0 .../lldir_utils_objc.h} | 12 +- .../lldir_utils_objc.mm} | 8 +- indra/{llvfs => llfilesystem}/lldir_win32.cpp | 0 indra/{llvfs => llfilesystem}/lldir_win32.h | 0 indra/{llvfs => llfilesystem}/lldirguard.h | 0 .../{llvfs => llfilesystem}/lldiriterator.cpp | 0 indra/{llvfs => llfilesystem}/lldiriterator.h | 0 indra/llfilesystem/lldiskcache.cpp | 327 +++ indra/llfilesystem/lldiskcache.h | 183 ++ indra/llfilesystem/llfilesystem.cpp | 283 +++ indra/llfilesystem/llfilesystem.h | 78 + indra/{llvfs => llfilesystem}/lllfsthread.cpp | 0 indra/{llvfs => llfilesystem}/lllfsthread.h | 0 .../tests/lldir_test.cpp | 0 .../tests/lldiriterator_test.cpp | 0 indra/llimage/CMakeLists.txt | 6 +- indra/llimage/llimage.cpp | 9 - indra/llinventory/CMakeLists.txt | 4 +- indra/llmessage/CMakeLists.txt | 12 +- indra/llmessage/llassetstorage.cpp | 97 +- indra/llmessage/llassetstorage.h | 26 +- indra/llmessage/llcorehttputil.cpp | 4 +- indra/llmessage/llextendedstatus.h | 14 +- indra/llmessage/lltransfersourceasset.cpp | 8 +- indra/llmessage/lltransfersourceasset.h | 4 +- indra/llmessage/lltransfertargetvfile.cpp | 9 +- indra/llmessage/lltransfertargetvfile.h | 4 +- indra/llmessage/llxfer_vfile.cpp | 57 +- indra/llmessage/llxfer_vfile.h | 12 +- indra/llmessage/llxfermanager.cpp | 35 +- indra/llmessage/llxfermanager.h | 12 +- indra/llrender/CMakeLists.txt | 12 +- indra/llui/CMakeLists.txt | 6 +- indra/llui/llviewereventrecorder.h | 1 - indra/llvfs/llpidlock.cpp | 276 -- indra/llvfs/llpidlock.h | 60 - indra/llvfs/llvfile.cpp | 437 ---- indra/llvfs/llvfile.h | 90 - indra/llvfs/llvfs.cpp | 2220 ----------------- indra/llvfs/llvfs.h | 183 -- indra/llvfs/llvfsthread.cpp | 300 --- indra/llvfs/llvfsthread.h | 140 -- indra/llwindow/CMakeLists.txt | 8 +- indra/llxml/CMakeLists.txt | 6 +- indra/mac_crash_logger/CMakeLists.txt | 7 +- indra/mac_crash_logger/mac_crash_logger.cpp | 1 - indra/newview/CMakeLists.txt | 10 +- indra/newview/app_settings/settings.xml | 81 +- indra/newview/app_settings/static_data.db2 | Bin 576578 -> 0 bytes indra/newview/app_settings/static_index.db2 | Bin 9894 -> 0 bytes indra/newview/llappviewer.cpp | 294 +-- indra/newview/llappviewer.h | 9 +- indra/newview/llappviewerwin32.cpp | 2 +- indra/newview/llcompilequeue.cpp | 12 +- indra/newview/llcompilequeue.h | 2 +- indra/newview/llfilepicker.h | 2 +- indra/newview/llfloaterauction.cpp | 11 +- indra/newview/llfloaterbvhpreview.cpp | 5 +- indra/newview/llfloatermodelpreview.cpp | 1 + indra/newview/llfloaterpreference.h | 2 +- indra/newview/llfloaterregioninfo.cpp | 11 +- indra/newview/llfloaterregioninfo.h | 4 +- indra/newview/llfloaterreporter.cpp | 12 +- indra/newview/llfloatertos.cpp | 2 +- indra/newview/llfloatertos.h | 1 - indra/newview/llgesturemgr.cpp | 20 +- indra/newview/llgesturemgr.h | 11 +- indra/newview/lllandmarklist.cpp | 5 +- indra/newview/lllandmarklist.h | 1 - indra/newview/llmeshrepository.cpp | 73 +- indra/newview/llmeshrepository.h | 1 - indra/newview/lloutfitgallery.cpp | 2 +- indra/newview/lloutfitgallery.h | 1 - indra/newview/llpostcard.cpp | 3 +- indra/newview/llpreviewgesture.cpp | 16 +- indra/newview/llpreviewgesture.h | 4 +- indra/newview/llpreviewnotecard.cpp | 16 +- indra/newview/llpreviewnotecard.h | 3 +- indra/newview/llpreviewscript.cpp | 30 +- indra/newview/llpreviewscript.h | 11 +- indra/newview/llsettingsvo.cpp | 10 +- indra/newview/llsettingsvo.h | 3 +- indra/newview/llsnapshotlivepreview.cpp | 6 +- indra/newview/llstartup.cpp | 16 +- indra/newview/lltexturecache.cpp | 46 +- indra/newview/llviewerassetstorage.cpp | 53 +- indra/newview/llviewerassetstorage.h | 8 +- indra/newview/llviewerassetupload.cpp | 19 +- indra/newview/llviewerassetupload.h | 2 +- .../newview/llviewermedia_streamingaudio.cpp | 2 - indra/newview/llviewermenufile.cpp | 2 - indra/newview/llviewermessage.cpp | 12 +- indra/newview/llviewermessage.h | 4 +- indra/newview/llviewerprecompiledheaders.h | 1 - indra/newview/llviewerstats.cpp | 3 - indra/newview/llviewerstats.h | 1 - indra/newview/llviewertexlayer.cpp | 2 - indra/newview/llviewertexture.cpp | 2 - indra/newview/llviewertexture.h | 2 +- indra/newview/llviewertexturelist.cpp | 4 +- indra/newview/llviewerwearable.cpp | 1 - indra/newview/llvoavatar.cpp | 1 - indra/newview/llvovolume.h | 7 +- .../skins/default/xui/da/floater_stats.xml | 1 - .../newview/skins/default/xui/da/strings.xml | 3 - .../xui/de/floater_scene_load_stats.xml | 1 - .../skins/default/xui/de/floater_stats.xml | 1 - .../newview/skins/default/xui/de/strings.xml | 4 - .../xui/en/floater_scene_load_stats.xml | 6 - .../skins/default/xui/en/floater_stats.xml | 4 - .../newview/skins/default/xui/en/strings.xml | 5 +- .../xui/es/floater_scene_load_stats.xml | 1 - .../skins/default/xui/es/floater_stats.xml | 1 - .../newview/skins/default/xui/es/strings.xml | 4 - .../xui/fr/floater_scene_load_stats.xml | 1 - .../skins/default/xui/fr/floater_stats.xml | 1 - .../newview/skins/default/xui/fr/strings.xml | 4 - .../xui/it/floater_scene_load_stats.xml | 1 - .../skins/default/xui/it/floater_stats.xml | 1 - .../newview/skins/default/xui/it/strings.xml | 4 - .../xui/ja/floater_scene_load_stats.xml | 1 - .../skins/default/xui/ja/floater_stats.xml | 1 - .../newview/skins/default/xui/ja/strings.xml | 4 - .../xui/pl/floater_scene_load_stats.xml | 1 - .../skins/default/xui/pl/floater_stats.xml | 1 - .../newview/skins/default/xui/pl/strings.xml | 3 - .../xui/pt/floater_scene_load_stats.xml | 1 - .../skins/default/xui/pt/floater_stats.xml | 1 - .../newview/skins/default/xui/pt/strings.xml | 4 - .../xui/ru/floater_scene_load_stats.xml | 1 - .../skins/default/xui/ru/floater_stats.xml | 1 - .../newview/skins/default/xui/ru/strings.xml | 4 - .../xui/tr/floater_scene_load_stats.xml | 1 - .../skins/default/xui/tr/floater_stats.xml | 1 - .../newview/skins/default/xui/tr/strings.xml | 4 - .../xui/zh/floater_scene_load_stats.xml | 1 - .../skins/default/xui/zh/floater_stats.xml | 1 - .../newview/skins/default/xui/zh/strings.xml | 4 - indra/newview/viewer_manifest.py | 1 - indra/test/CMakeLists.txt | 7 +- indra/win_crash_logger/CMakeLists.txt | 6 +- 173 files changed, 1455 insertions(+), 4789 deletions(-) create mode 100644 indra/cmake/LLFileSystem.cmake delete mode 100644 indra/cmake/LLVFS.cmake rename indra/{llvfs => llfilesystem}/CMakeLists.txt (51%) rename indra/{llvfs => llfilesystem}/lldir.cpp (100%) rename indra/{llvfs => llfilesystem}/lldir.h (100%) rename indra/{llvfs => llfilesystem}/lldir_linux.cpp (100%) rename indra/{llvfs => llfilesystem}/lldir_linux.h (100%) rename indra/{llvfs => llfilesystem}/lldir_mac.cpp (99%) rename indra/{llvfs => llfilesystem}/lldir_mac.h (100%) rename indra/{llvfs => llfilesystem}/lldir_solaris.cpp (100%) rename indra/{llvfs => llfilesystem}/lldir_solaris.h (100%) rename indra/{llvfs/llvfs_objc.h => llfilesystem/lldir_utils_objc.h} (85%) rename indra/{llvfs/llvfs_objc.mm => llfilesystem/lldir_utils_objc.mm} (95%) rename indra/{llvfs => llfilesystem}/lldir_win32.cpp (100%) rename indra/{llvfs => llfilesystem}/lldir_win32.h (100%) rename indra/{llvfs => llfilesystem}/lldirguard.h (100%) rename indra/{llvfs => llfilesystem}/lldiriterator.cpp (100%) rename indra/{llvfs => llfilesystem}/lldiriterator.h (100%) create mode 100644 indra/llfilesystem/lldiskcache.cpp create mode 100644 indra/llfilesystem/lldiskcache.h create mode 100644 indra/llfilesystem/llfilesystem.cpp create mode 100644 indra/llfilesystem/llfilesystem.h rename indra/{llvfs => llfilesystem}/lllfsthread.cpp (100%) rename indra/{llvfs => llfilesystem}/lllfsthread.h (100%) rename indra/{llvfs => llfilesystem}/tests/lldir_test.cpp (100%) rename indra/{llvfs => llfilesystem}/tests/lldiriterator_test.cpp (100%) delete mode 100644 indra/llvfs/llpidlock.cpp delete mode 100644 indra/llvfs/llpidlock.h delete mode 100644 indra/llvfs/llvfile.cpp delete mode 100644 indra/llvfs/llvfile.h delete mode 100644 indra/llvfs/llvfs.cpp delete mode 100644 indra/llvfs/llvfs.h delete mode 100644 indra/llvfs/llvfsthread.cpp delete mode 100644 indra/llvfs/llvfsthread.h delete mode 100644 indra/newview/app_settings/static_data.db2 delete mode 100644 indra/newview/app_settings/static_index.db2 diff --git a/README.md b/README.md index e4078770f3..729c0ae368 100644 --- a/README.md +++ b/README.md @@ -13,3 +13,4 @@ To download the current default version, visit [the download page](https://secondlife.com/support/downloads). For even newer versions try [the Alternate Viewers page](https://wiki.secondlife.com/wiki/Linden_Lab_Official:Alternate_Viewers) + diff --git a/indra/CMakeLists.txt b/indra/CMakeLists.txt index 53e5d7b6a5..4b39bfe332 100644 --- a/indra/CMakeLists.txt +++ b/indra/CMakeLists.txt @@ -40,7 +40,7 @@ add_subdirectory(${LIBS_OPEN_PREFIX}llmath) add_subdirectory(${LIBS_OPEN_PREFIX}llmessage) add_subdirectory(${LIBS_OPEN_PREFIX}llprimitive) add_subdirectory(${LIBS_OPEN_PREFIX}llrender) -add_subdirectory(${LIBS_OPEN_PREFIX}llvfs) +add_subdirectory(${LIBS_OPEN_PREFIX}llfilesystem) add_subdirectory(${LIBS_OPEN_PREFIX}llwindow) add_subdirectory(${LIBS_OPEN_PREFIX}llxml) diff --git a/indra/cmake/00-Common.cmake b/indra/cmake/00-Common.cmake index 8aea50e02b..f4071793d5 100644 --- a/indra/cmake/00-Common.cmake +++ b/indra/cmake/00-Common.cmake @@ -66,11 +66,10 @@ if (WINDOWS) # CP changed to only append the flag for 32bit builds - on 64bit builds, # locally at least, the build output is spammed with 1000s of 'D9002' # warnings about this switch being ignored. - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /MP") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /MP") if( ADDRESS_SIZE EQUAL 32 ) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /p:PreferredToolArchitecture=x64") endif() - set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} /Zo" CACHE STRING "C++ compiler release-with-debug options" FORCE) diff --git a/indra/cmake/CMakeLists.txt b/indra/cmake/CMakeLists.txt index a17e37cd32..352dfc0641 100644 --- a/indra/cmake/CMakeLists.txt +++ b/indra/cmake/CMakeLists.txt @@ -69,7 +69,7 @@ set(cmake_SOURCE_FILES LLSharedLibs.cmake LLTestCommand.cmake LLUI.cmake - LLVFS.cmake + LLFileSystem.cmake LLWindow.cmake LLXML.cmake Linking.cmake diff --git a/indra/cmake/LLFileSystem.cmake b/indra/cmake/LLFileSystem.cmake new file mode 100644 index 0000000000..2e6c42c30c --- /dev/null +++ b/indra/cmake/LLFileSystem.cmake @@ -0,0 +1,7 @@ +# -*- cmake -*- + +set(LLFILESYSTEM_INCLUDE_DIRS + ${LIBS_OPEN_DIR}/llfilesystem + ) + +set(LLFILESYSTEM_LIBRARIES llfilesystem) diff --git a/indra/cmake/LLVFS.cmake b/indra/cmake/LLVFS.cmake deleted file mode 100644 index 0fe87cdea6..0000000000 --- a/indra/cmake/LLVFS.cmake +++ /dev/null @@ -1,7 +0,0 @@ -# -*- cmake -*- - -set(LLVFS_INCLUDE_DIRS - ${LIBS_OPEN_DIR}/llvfs - ) - -set(LLVFS_LIBRARIES llvfs) diff --git a/indra/integration_tests/llimage_libtest/CMakeLists.txt b/indra/integration_tests/llimage_libtest/CMakeLists.txt index 5787d4d600..bd59f57e49 100644 --- a/indra/integration_tests/llimage_libtest/CMakeLists.txt +++ b/indra/integration_tests/llimage_libtest/CMakeLists.txt @@ -10,11 +10,11 @@ include(LLImage) include(LLMath) include(LLImageJ2COJ) include(LLKDU) -include(LLVFS) +include(LLFileSystem) include_directories( ${LLCOMMON_INCLUDE_DIRS} - ${LLVFS_INCLUDE_DIRS} + ${LLFILESYSTEM_INCLUDE_DIRS} ${LLIMAGE_INCLUDE_DIRS} ${LLMATH_INCLUDE_DIRS} ) @@ -66,7 +66,7 @@ endif (DARWIN) target_link_libraries(llimage_libtest ${LEGACY_STDIO_LIBS} ${LLCOMMON_LIBRARIES} - ${LLVFS_LIBRARIES} + ${LLFILESYSTEM_LIBRARIES} ${LLMATH_LIBRARIES} ${LLIMAGE_LIBRARIES} ${LLKDU_LIBRARIES} diff --git a/indra/integration_tests/llui_libtest/CMakeLists.txt b/indra/integration_tests/llui_libtest/CMakeLists.txt index 1cec660eb0..d7706e73b2 100644 --- a/indra/integration_tests/llui_libtest/CMakeLists.txt +++ b/indra/integration_tests/llui_libtest/CMakeLists.txt @@ -16,7 +16,7 @@ include(LLMessage) include(LLRender) include(LLWindow) include(LLUI) -include(LLVFS) # ugh, needed for LLDir +include(LLFileSystem) include(LLXML) include(Hunspell) include(Linking) @@ -29,7 +29,7 @@ include_directories( ${LLMATH_INCLUDE_DIRS} ${LLRENDER_INCLUDE_DIRS} ${LLUI_INCLUDE_DIRS} - ${LLVFS_INCLUDE_DIRS} + ${LLFILESYSTEM_INCLUDE_DIRS} ${LLWINDOW_INCLUDE_DIRS} ${LLXML_INCLUDE_DIRS} ${LIBS_PREBUILD_DIR}/include/hunspell diff --git a/indra/linux_crash_logger/CMakeLists.txt b/indra/linux_crash_logger/CMakeLists.txt index d789c850a0..aa82ed12cc 100644 --- a/indra/linux_crash_logger/CMakeLists.txt +++ b/indra/linux_crash_logger/CMakeLists.txt @@ -9,7 +9,7 @@ include(LLCommon) include(LLCrashLogger) include(LLMath) include(LLMessage) -include(LLVFS) +include(LLFileSystem) include(LLXML) include(Linking) include(UI) @@ -21,7 +21,7 @@ include_directories( ${LLCOMMON_INCLUDE_DIRS} ${LLCRASHLOGGER_INCLUDE_DIRS} ${LLMATH_INCLUDE_DIRS} - ${LLVFS_INCLUDE_DIRS} + ${LLFILESYSTEM_INCLUDE_DIRS} ${LLXML_INCLUDE_DIRS} ${FREETYPE_INCLUDE_DIRS} ) @@ -62,10 +62,9 @@ set(LIBRT_LIBRARY rt) target_link_libraries(linux-crash-logger ${LLCRASHLOGGER_LIBRARIES} - ${LLVFS_LIBRARIES} + ${LLFILESYSTEM_LIBRARIES} ${LLXML_LIBRARIES} ${LLMESSAGE_LIBRARIES} - ${LLVFS_LIBRARIES} ${LLMATH_LIBRARIES} ${LLCOREHTTP_LIBRARIES} ${LLCOMMON_LIBRARIES} diff --git a/indra/llappearance/CMakeLists.txt b/indra/llappearance/CMakeLists.txt index 20eb4678dd..268849ad74 100644 --- a/indra/llappearance/CMakeLists.txt +++ b/indra/llappearance/CMakeLists.txt @@ -11,7 +11,7 @@ include(LLMath) include(LLMessage) include(LLCoreHttp) include(LLRender) -include(LLVFS) +include(LLFileSystem) include(LLWindow) include(LLXML) include(Linking) @@ -23,7 +23,7 @@ include_directories( ${LLINVENTORY_INCLUDE_DIRS} ${LLMATH_INCLUDE_DIRS} ${LLRENDER_INCLUDE_DIRS} - ${LLVFS_INCLUDE_DIRS} + ${LLFILESYSTEM_INCLUDE_DIRS} ${LLWINDOW_INCLUDE_DIRS} ${LLXML_INCLUDE_DIRS} ) @@ -83,7 +83,7 @@ target_link_libraries(llappearance ${LLINVENTORY_LIBRARIES} ${LLIMAGE_LIBRARIES} ${LLRENDER_LIBRARIES} - ${LLVFS_LIBRARIES} + ${LLFILESYSTEM_LIBRARIES} ${LLMATH_LIBRARIES} ${LLXML_LIBRARIES} ${LLMATH_LIBRARIES} @@ -100,7 +100,7 @@ if (BUILD_HEADLESS) ${LLINVENTORY_LIBRARIES} ${LLIMAGE_LIBRARIES} ${LLRENDERHEADLESS_LIBRARIES} - ${LLVFS_LIBRARIES} + ${LLFILESYSTEM_LIBRARIES} ${LLMATH_LIBRARIES} ${LLXML_LIBRARIES} ${LLMATH_LIBRARIES} @@ -109,15 +109,3 @@ if (BUILD_HEADLESS) ${LLCOMMON_LIBRARIES} ) endif (BUILD_HEADLESS) - -#add unit tests -#if (LL_TESTS) -# INCLUDE(LLAddBuildTest) -# SET(llappearance_TEST_SOURCE_FILES -# # no real unit tests yet! -# ) -# LL_ADD_PROJECT_UNIT_TESTS(llappearance "${llappearance_TEST_SOURCE_FILES}") - - #set(TEST_DEBUG on) -# set(test_libs llappearance ${LLCOMMON_LIBRARIES}) -#endif (LL_TESTS) diff --git a/indra/llappearance/lltexlayer.cpp b/indra/llappearance/lltexlayer.cpp index e5039141de..a4600069ce 100644 --- a/indra/llappearance/lltexlayer.cpp +++ b/indra/llappearance/lltexlayer.cpp @@ -33,8 +33,6 @@ #include "llimagej2c.h" #include "llimagetga.h" #include "lldir.h" -#include "llvfile.h" -#include "llvfs.h" #include "lltexlayerparams.h" #include "lltexturemanagerbridge.h" #include "lllocaltextureobject.h" diff --git a/indra/llaudio/CMakeLists.txt b/indra/llaudio/CMakeLists.txt index 558ede7bf6..92a5cfe22f 100644 --- a/indra/llaudio/CMakeLists.txt +++ b/indra/llaudio/CMakeLists.txt @@ -9,14 +9,14 @@ include(OPENAL) include(LLCommon) include(LLMath) include(LLMessage) -include(LLVFS) +include(LLFileSystem) include_directories( ${LLAUDIO_INCLUDE_DIRS} ${LLCOMMON_INCLUDE_DIRS} ${LLMATH_INCLUDE_DIRS} ${LLMESSAGE_INCLUDE_DIRS} - ${LLVFS_INCLUDE_DIRS} + ${LLFILESYSTEM_INCLUDE_DIRS} ${OGG_INCLUDE_DIRS} ${VORBISENC_INCLUDE_DIRS} ${VORBISFILE_INCLUDE_DIRS} @@ -86,7 +86,7 @@ target_link_libraries( ${LLCOMMON_LIBRARIES} ${LLMATH_LIBRARIES} ${LLMESSAGE_LIBRARIES} - ${LLVFS_LIBRARIES} + ${LLFILESYSTEM_LIBRARIES} ${VORBISENC_LIBRARIES} ${VORBISFILE_LIBRARIES} ${VORBIS_LIBRARIES} diff --git a/indra/llaudio/llaudiodecodemgr.cpp b/indra/llaudio/llaudiodecodemgr.cpp index e7db84f6ab..ff0aa6e76e 100644 --- a/indra/llaudio/llaudiodecodemgr.cpp +++ b/indra/llaudio/llaudiodecodemgr.cpp @@ -29,7 +29,7 @@ #include "llaudioengine.h" #include "lllfsthread.h" -#include "llvfile.h" +#include "llfilesystem.h" #include "llstring.h" #include "lldir.h" #include "llendianswizzle.h" @@ -90,19 +90,17 @@ protected: LLUUID mUUID; std::vector mWAVBuffer; -#if !defined(USE_WAV_VFILE) std::string mOutFilename; LLLFSThread::handle_t mFileHandle; -#endif - LLVFile *mInFilep; + LLFileSystem *mInFilep; OggVorbis_File mVF; S32 mCurrentSection; }; -size_t vfs_read(void *ptr, size_t size, size_t nmemb, void *datasource) +size_t cache_read(void *ptr, size_t size, size_t nmemb, void *datasource) { - LLVFile *file = (LLVFile *)datasource; + LLFileSystem *file = (LLFileSystem *)datasource; if (file->read((U8*)ptr, (S32)(size * nmemb))) /*Flawfinder: ignore*/ { @@ -115,11 +113,11 @@ size_t vfs_read(void *ptr, size_t size, size_t nmemb, void *datasource) } } -S32 vfs_seek(void *datasource, ogg_int64_t offset, S32 whence) +S32 cache_seek(void *datasource, ogg_int64_t offset, S32 whence) { - LLVFile *file = (LLVFile *)datasource; + LLFileSystem *file = (LLFileSystem *)datasource; - // vfs has 31-bit files + // cache has 31-bit files if (offset > S32_MAX) { return -1; @@ -137,7 +135,7 @@ S32 vfs_seek(void *datasource, ogg_int64_t offset, S32 whence) origin = -1; break; default: - LL_ERRS("AudioEngine") << "Invalid whence argument to vfs_seek" << LL_ENDL; + LL_ERRS("AudioEngine") << "Invalid whence argument to cache_seek" << LL_ENDL; return -1; } @@ -151,16 +149,16 @@ S32 vfs_seek(void *datasource, ogg_int64_t offset, S32 whence) } } -S32 vfs_close (void *datasource) +S32 cache_close (void *datasource) { - LLVFile *file = (LLVFile *)datasource; + LLFileSystem *file = (LLFileSystem *)datasource; delete file; return 0; } -long vfs_tell (void *datasource) +long cache_tell (void *datasource) { - LLVFile *file = (LLVFile *)datasource; + LLFileSystem *file = (LLFileSystem *)datasource; return file->tell(); } @@ -172,11 +170,10 @@ LLVorbisDecodeState::LLVorbisDecodeState(const LLUUID &uuid, const std::string & mUUID = uuid; mInFilep = NULL; mCurrentSection = 0; -#if !defined(USE_WAV_VFILE) mOutFilename = out_filename; mFileHandle = LLLFSThread::nullHandle(); -#endif - // No default value for mVF, it's an ogg structure? + + // No default value for mVF, it's an ogg structure? // Hey, let's zero it anyway, for predictability. memset(&mVF, 0, sizeof(mVF)); } @@ -193,15 +190,15 @@ LLVorbisDecodeState::~LLVorbisDecodeState() BOOL LLVorbisDecodeState::initDecode() { - ov_callbacks vfs_callbacks; - vfs_callbacks.read_func = vfs_read; - vfs_callbacks.seek_func = vfs_seek; - vfs_callbacks.close_func = vfs_close; - vfs_callbacks.tell_func = vfs_tell; + ov_callbacks cache_callbacks; + cache_callbacks.read_func = cache_read; + cache_callbacks.seek_func = cache_seek; + cache_callbacks.close_func = cache_close; + cache_callbacks.tell_func = cache_tell; LL_DEBUGS("AudioEngine") << "Initing decode from vfile: " << mUUID << LL_ENDL; - mInFilep = new LLVFile(gVFS, mUUID, LLAssetType::AT_SOUND); + mInFilep = new LLFileSystem(mUUID, LLAssetType::AT_SOUND); if (!mInFilep || !mInFilep->getSize()) { LL_WARNS("AudioEngine") << "unable to open vorbis source vfile for reading" << LL_ENDL; @@ -210,7 +207,7 @@ BOOL LLVorbisDecodeState::initDecode() return FALSE; } - S32 r = ov_open_callbacks(mInFilep, &mVF, NULL, 0, vfs_callbacks); + S32 r = ov_open_callbacks(mInFilep, &mVF, NULL, 0, cache_callbacks); if(r < 0) { LL_WARNS("AudioEngine") << r << " Input to vorbis decode does not appear to be an Ogg bitstream: " << mUUID << LL_ENDL; @@ -370,7 +367,7 @@ BOOL LLVorbisDecodeState::decodeSection() { if (!mInFilep) { - LL_WARNS("AudioEngine") << "No VFS file to decode in vorbis!" << LL_ENDL; + LL_WARNS("AudioEngine") << "No cache file to decode in vorbis!" << LL_ENDL; return TRUE; } if (mDone) @@ -420,9 +417,7 @@ BOOL LLVorbisDecodeState::finishDecode() return TRUE; // We've finished } -#if !defined(USE_WAV_VFILE) if (mFileHandle == LLLFSThread::nullHandle()) -#endif { ov_clear(&mVF); @@ -495,11 +490,9 @@ BOOL LLVorbisDecodeState::finishDecode() mValid = FALSE; return TRUE; // we've finished } -#if !defined(USE_WAV_VFILE) mBytesRead = -1; mFileHandle = LLLFSThread::sLocal->write(mOutFilename, &mWAVBuffer[0], 0, mWAVBuffer.size(), new WriteResponder(this)); -#endif } if (mFileHandle != LLLFSThread::nullHandle()) @@ -521,11 +514,6 @@ BOOL LLVorbisDecodeState::finishDecode() mDone = TRUE; -#if defined(USE_WAV_VFILE) - // write the data. - LLVFile output(gVFS, mUUID, LLAssetType::AT_SOUND_WAV); - output.write(&mWAVBuffer[0], mWAVBuffer.size()); -#endif LL_DEBUGS("AudioEngine") << "Finished decode for " << getUUID() << LL_ENDL; return TRUE; @@ -535,7 +523,7 @@ void LLVorbisDecodeState::flushBadFile() { if (mInFilep) { - LL_WARNS("AudioEngine") << "Flushing bad vorbis file from VFS for " << mUUID << LL_ENDL; + LL_WARNS("AudioEngine") << "Flushing bad vorbis file from cache for " << mUUID << LL_ENDL; mInFilep->remove(); } } diff --git a/indra/llaudio/llaudiodecodemgr.h b/indra/llaudio/llaudiodecodemgr.h index 8228e20e8c..ceaff3f2d8 100644 --- a/indra/llaudio/llaudiodecodemgr.h +++ b/indra/llaudio/llaudiodecodemgr.h @@ -33,7 +33,6 @@ #include "llassettype.h" #include "llframetimer.h" -class LLVFS; class LLVorbisDecodeState; class LLAudioDecodeMgr diff --git a/indra/llaudio/llaudioengine.cpp b/indra/llaudio/llaudioengine.cpp index 1d447f32ae..d35f249973 100644 --- a/indra/llaudio/llaudioengine.cpp +++ b/indra/llaudio/llaudioengine.cpp @@ -35,7 +35,7 @@ #include "sound_ids.h" // temporary hack for min/max distances -#include "llvfs.h" +#include "llfilesystem.h" #include "lldir.h" #include "llaudiodecodemgr.h" #include "llassetstorage.h" @@ -684,13 +684,9 @@ bool LLAudioEngine::preloadSound(const LLUUID &uuid) return true; } - // At some point we need to have the audio/asset system check the static VFS - // before it goes off and fetches stuff from the server. - //LL_WARNS() << "Used internal preload for non-local sound" << LL_ENDL; return false; } - bool LLAudioEngine::isWindEnabled() { return mEnableWind; @@ -1018,13 +1014,12 @@ bool LLAudioEngine::hasDecodedFile(const LLUUID &uuid) bool LLAudioEngine::hasLocalFile(const LLUUID &uuid) { - // See if it's in the VFS. - bool have_local = gVFS->getExists(uuid, LLAssetType::AT_SOUND); - LL_DEBUGS("AudioEngine") << "sound uuid "<getNumJointMotions(); jm++) { if (!mJointStates[jm]->getJoint()) diff --git a/indra/llcharacter/llkeyframemotion.cpp b/indra/llcharacter/llkeyframemotion.cpp index cde38c8091..fe9de30f0a 100644 --- a/indra/llcharacter/llkeyframemotion.cpp +++ b/indra/llcharacter/llkeyframemotion.cpp @@ -39,14 +39,13 @@ #include "llendianswizzle.h" #include "llkeyframemotion.h" #include "llquantize.h" -#include "llvfile.h" #include "m3math.h" #include "message.h" +#include "llfilesystem.h" //----------------------------------------------------------------------------- // Static Definitions //----------------------------------------------------------------------------- -LLVFS* LLKeyframeMotion::sVFS = NULL; LLKeyframeDataCache::keyframe_data_map_t LLKeyframeDataCache::sKeyframeDataMap; //----------------------------------------------------------------------------- @@ -515,7 +514,7 @@ LLMotion::LLMotionInitStatus LLKeyframeMotion::onInitialize(LLCharacter *charact return STATUS_SUCCESS; default: // we don't know what state the asset is in yet, so keep going - // check keyframe cache first then static vfs then asset request + // check keyframe cache first then file cache then asset request break; } @@ -559,13 +558,8 @@ LLMotion::LLMotionInitStatus LLKeyframeMotion::onInitialize(LLCharacter *charact U8 *anim_data; S32 anim_file_size; - if (!sVFS) - { - LL_ERRS() << "Must call LLKeyframeMotion::setVFS() first before loading a keyframe file!" << LL_ENDL; - } - BOOL success = FALSE; - LLVFile* anim_file = new LLVFile(sVFS, mID, LLAssetType::AT_ANIMATION); + LLFileSystem* anim_file = new LLFileSystem(mID, LLAssetType::AT_ANIMATION); if (!anim_file || !anim_file->getSize()) { delete anim_file; @@ -2296,10 +2290,9 @@ void LLKeyframeMotion::setLoopOut(F32 out_point) //----------------------------------------------------------------------------- // onLoadComplete() //----------------------------------------------------------------------------- -void LLKeyframeMotion::onLoadComplete(LLVFS *vfs, - const LLUUID& asset_uuid, - LLAssetType::EType type, - void* user_data, S32 status, LLExtStat ext_status) +void LLKeyframeMotion::onLoadComplete(const LLUUID& asset_uuid, + LLAssetType::EType type, + void* user_data, S32 status, LLExtStat ext_status) { LLUUID* id = (LLUUID*)user_data; @@ -2331,7 +2324,7 @@ void LLKeyframeMotion::onLoadComplete(LLVFS *vfs, // asset already loaded return; } - LLVFile file(vfs, asset_uuid, type, LLVFile::READ); + LLFileSystem file(asset_uuid, type, LLFileSystem::READ); S32 size = file.getSize(); U8* buffer = new U8[size]; diff --git a/indra/llcharacter/llkeyframemotion.h b/indra/llcharacter/llkeyframemotion.h index 15c5c7c6c0..d640556090 100644 --- a/indra/llcharacter/llkeyframemotion.h +++ b/indra/llcharacter/llkeyframemotion.h @@ -44,7 +44,6 @@ #include "llbvhconsts.h" class LLKeyframeDataCache; -class LLVFS; class LLDataPacker; #define MIN_REQUIRED_PIXEL_AREA_KEYFRAME (40.f) @@ -141,10 +140,7 @@ public: virtual void setStopTime(F32 time); - static void setVFS(LLVFS* vfs) { sVFS = vfs; } - - static void onLoadComplete(LLVFS *vfs, - const LLUUID& asset_uuid, + static void onLoadComplete(const LLUUID& asset_uuid, LLAssetType::EType type, void* user_data, S32 status, LLExtStat ext_status); @@ -416,13 +412,7 @@ public: U32 getNumJointMotions() const { return mJointMotionArray.size(); } }; - protected: - static LLVFS* sVFS; - - //------------------------------------------------------------------------- - // Member Data - //------------------------------------------------------------------------- JointMotionList* mJointMotionList; std::vector > mJointStates; LLJoint* mPelvisp; diff --git a/indra/llcommon/llerror.cpp b/indra/llcommon/llerror.cpp index f876b8ee4a..6e8b9efaf7 100644 --- a/indra/llcommon/llerror.cpp +++ b/indra/llcommon/llerror.cpp @@ -194,23 +194,64 @@ namespace { { return LLError::getEnabledLogTypesMask() & 0x04; } - + + LL_FORCE_INLINE std::string createBoldANSI() + { + std::string ansi_code; + ansi_code += '\033'; + ansi_code += "["; + ansi_code += "1"; + ansi_code += "m"; + + return ansi_code; + } + + LL_FORCE_INLINE std::string createResetANSI() + { + std::string ansi_code; + ansi_code += '\033'; + ansi_code += "["; + ansi_code += "0"; + ansi_code += "m"; + + return ansi_code; + } + LL_FORCE_INLINE std::string createANSI(const std::string& color) { std::string ansi_code; - ansi_code += '\033'; - ansi_code += "["; - ansi_code += color; + ansi_code += '\033'; + ansi_code += "["; + ansi_code += "38;5;"; + ansi_code += color; ansi_code += "m"; + return ansi_code; } virtual void recordMessage(LLError::ELevel level, const std::string& message) override { - static std::string s_ansi_error = createANSI("31"); // red - static std::string s_ansi_warn = createANSI("34"); // blue - static std::string s_ansi_debug = createANSI("35"); // magenta + // The default colors for error, warn and debug are now a bit more pastel + // and easier to read on the default (black) terminal background but you + // now have the option to set the color of each via an environment variables: + // LL_ANSI_ERROR_COLOR_CODE (default is red) + // LL_ANSI_WARN_COLOR_CODE (default is blue) + // LL_ANSI_DEBUG_COLOR_CODE (default is magenta) + // The list of color codes can be found in many places but I used this page: + // https://www.lihaoyi.com/post/BuildyourownCommandLinewithANSIescapecodes.html#256-colors + // (Note: you may need to restart Visual Studio to pick environment changes) + char* val = nullptr; + std::string s_ansi_error_code = "160"; + if ((val = getenv("LL_ANSI_ERROR_COLOR_CODE")) != nullptr) s_ansi_error_code = std::string(val); + std::string s_ansi_warn_code = "33"; + if ((val = getenv("LL_ANSI_WARN_COLOR_CODE")) != nullptr) s_ansi_warn_code = std::string(val); + std::string s_ansi_debug_code = "177"; + if ((val = getenv("LL_ANSI_DEBUG_COLOR_CODE")) != nullptr) s_ansi_debug_code = std::string(val); + + static std::string s_ansi_error = createANSI(s_ansi_error_code); // default is red + static std::string s_ansi_warn = createANSI(s_ansi_warn_code); // default is blue + static std::string s_ansi_debug = createANSI(s_ansi_debug_code); // default is magenta if (mUseANSI) { @@ -229,11 +270,11 @@ namespace { LL_FORCE_INLINE void writeANSI(const std::string& ansi_code, const std::string& message) { - static std::string s_ansi_bold = createANSI("1"); // bold - static std::string s_ansi_reset = createANSI("0"); // reset + static std::string s_ansi_bold = createBoldANSI(); // bold text + static std::string s_ansi_reset = createResetANSI(); // reset // ANSI color code escape sequence, message, and reset in one fprintf call // Default all message levels to bold so we can distinguish our own messages from those dumped by subprocesses and libraries. - fprintf(stderr, "%s%s%s\n%s", s_ansi_bold.c_str(), ansi_code.c_str(), message.c_str(), s_ansi_reset.c_str() ); + fprintf(stderr, "%s%s\n%s", ansi_code.c_str(), message.c_str(), s_ansi_reset.c_str() ); } static bool checkANSI(void) diff --git a/indra/llcrashlogger/CMakeLists.txt b/indra/llcrashlogger/CMakeLists.txt index da23b46b7b..d70a1e0fb0 100644 --- a/indra/llcrashlogger/CMakeLists.txt +++ b/indra/llcrashlogger/CMakeLists.txt @@ -7,7 +7,7 @@ include(LLCoreHttp) include(LLCommon) include(LLMath) include(LLMessage) -include(LLVFS) +include(LLFileSystem) include(LLXML) include_directories( @@ -15,7 +15,7 @@ include_directories( ${LLCOMMON_INCLUDE_DIRS} ${LLMATH_INCLUDE_DIRS} ${LLMESSAGE_INCLUDE_DIRS} - ${LLVFS_INCLUDE_DIRS} + ${LLFILESYSTEM_INCLUDE_DIRS} ${LLXML_INCLUDE_DIRS} ) include_directories(SYSTEM diff --git a/indra/llcrashlogger/llcrashlock.h b/indra/llcrashlogger/llcrashlock.h index cde183272f..60b060b736 100644 --- a/indra/llcrashlogger/llcrashlock.h +++ b/indra/llcrashlogger/llcrashlock.h @@ -1,5 +1,5 @@ /** - * @file llpidlock.h + * @file llcrashlock.h * @brief Maintainence of disk locking files for crash reporting * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ diff --git a/indra/llvfs/CMakeLists.txt b/indra/llfilesystem/CMakeLists.txt similarity index 51% rename from indra/llvfs/CMakeLists.txt rename to indra/llfilesystem/CMakeLists.txt index 67dce8c073..09c4c33ebf 100644 --- a/indra/llvfs/CMakeLists.txt +++ b/indra/llfilesystem/CMakeLists.txt @@ -1,6 +1,6 @@ # -*- cmake -*- -project(llvfs) +project(llfilesystem) include(00-Common) include(LLCommon) @@ -11,39 +11,34 @@ include_directories( ${LLCOMMON_SYSTEM_INCLUDE_DIRS} ) -set(llvfs_SOURCE_FILES +set(llfilesystem_SOURCE_FILES lldir.cpp lldiriterator.cpp lllfsthread.cpp - llpidlock.cpp - llvfile.cpp - llvfs.cpp - llvfsthread.cpp + lldiskcache.cpp + llfilesystem.cpp ) -set(llvfs_HEADER_FILES +set(llfilesystem_HEADER_FILES CMakeLists.txt - lldir.h lldirguard.h lldiriterator.h lllfsthread.h - llpidlock.h - llvfile.h - llvfs.h - llvfsthread.h + lldiskcache.h + llfilesystem.h ) if (DARWIN) - LIST(APPEND llvfs_SOURCE_FILES lldir_mac.cpp) - LIST(APPEND llvfs_HEADER_FILES lldir_mac.h) - LIST(APPEND llvfs_SOURCE_FILES llvfs_objc.mm) - LIST(APPEND llvfs_HEADER_FILES llvfs_objc.h) + LIST(APPEND llfilesystem_SOURCE_FILES lldir_utils_objc.mm) + LIST(APPEND llfilesystem_SOURCE_FILES lldir_utils_objc.h) + LIST(APPEND llfilesystem_SOURCE_FILES lldir_mac.cpp) + LIST(APPEND llfilesystem_HEADER_FILES lldir_mac.h) endif (DARWIN) if (LINUX) - LIST(APPEND llvfs_SOURCE_FILES lldir_linux.cpp) - LIST(APPEND llvfs_HEADER_FILES lldir_linux.h) + LIST(APPEND llfilesystem_SOURCE_FILES lldir_linux.cpp) + LIST(APPEND llfilesystem_HEADER_FILES lldir_linux.h) if (INSTALL) set_source_files_properties(lldir_linux.cpp @@ -54,31 +49,31 @@ if (LINUX) endif (LINUX) if (WINDOWS) - LIST(APPEND llvfs_SOURCE_FILES lldir_win32.cpp) - LIST(APPEND llvfs_HEADER_FILES lldir_win32.h) + LIST(APPEND llfilesystem_SOURCE_FILES lldir_win32.cpp) + LIST(APPEND llfilesystem_HEADER_FILES lldir_win32.h) endif (WINDOWS) -set_source_files_properties(${llvfs_HEADER_FILES} +set_source_files_properties(${llfilesystem_HEADER_FILES} PROPERTIES HEADER_FILE_ONLY TRUE) -list(APPEND llvfs_SOURCE_FILES ${llvfs_HEADER_FILES}) +list(APPEND llfilesystem_SOURCE_FILES ${llfilesystem_HEADER_FILES}) -add_library (llvfs ${llvfs_SOURCE_FILES}) +add_library (llfilesystem ${llfilesystem_SOURCE_FILES}) -set(vfs_BOOST_LIBRARIES +set(cache_BOOST_LIBRARIES ${BOOST_FILESYSTEM_LIBRARY} ${BOOST_SYSTEM_LIBRARY} ) -target_link_libraries(llvfs +target_link_libraries(llfilesystem ${LLCOMMON_LIBRARIES} - ${vfs_BOOST_LIBRARIES} + ${cache_BOOST_LIBRARIES} ) if (DARWIN) include(CMakeFindFrameworks) find_library(COCOA_LIBRARY Cocoa) - target_link_libraries(llvfs ${COCOA_LIBRARY}) + target_link_libraries(llfilesystem ${COCOA_LIBRARY}) endif (DARWIN) @@ -86,18 +81,18 @@ endif (DARWIN) if (LL_TESTS) include(LLAddBuildTest) # UNIT TESTS - SET(llvfs_TEST_SOURCE_FILES + SET(llfilesystem_TEST_SOURCE_FILES lldiriterator.cpp ) set_source_files_properties(lldiriterator.cpp PROPERTIES - LL_TEST_ADDITIONAL_LIBRARIES "${vfs_BOOST_LIBRARIES}" + LL_TEST_ADDITIONAL_LIBRARIES "${cache_BOOST_LIBRARIES}" ) - LL_ADD_PROJECT_UNIT_TESTS(llvfs "${llvfs_TEST_SOURCE_FILES}") + LL_ADD_PROJECT_UNIT_TESTS(llfilesystem "${llfilesystem_TEST_SOURCE_FILES}") # INTEGRATION TESTS - set(test_libs llmath llcommon llvfs ${LLCOMMON_LIBRARIES} ${WINDOWS_LIBRARIES}) + set(test_libs llmath llcommon llfilesystem ${LLCOMMON_LIBRARIES} ${WINDOWS_LIBRARIES}) # TODO: Some of these need refactoring to be proper Unit tests rather than Integration tests. LL_ADD_INTEGRATION_TEST(lldir "" "${test_libs}") diff --git a/indra/llvfs/lldir.cpp b/indra/llfilesystem/lldir.cpp similarity index 100% rename from indra/llvfs/lldir.cpp rename to indra/llfilesystem/lldir.cpp diff --git a/indra/llvfs/lldir.h b/indra/llfilesystem/lldir.h similarity index 100% rename from indra/llvfs/lldir.h rename to indra/llfilesystem/lldir.h diff --git a/indra/llvfs/lldir_linux.cpp b/indra/llfilesystem/lldir_linux.cpp similarity index 100% rename from indra/llvfs/lldir_linux.cpp rename to indra/llfilesystem/lldir_linux.cpp diff --git a/indra/llvfs/lldir_linux.h b/indra/llfilesystem/lldir_linux.h similarity index 100% rename from indra/llvfs/lldir_linux.h rename to indra/llfilesystem/lldir_linux.h diff --git a/indra/llvfs/lldir_mac.cpp b/indra/llfilesystem/lldir_mac.cpp similarity index 99% rename from indra/llvfs/lldir_mac.cpp rename to indra/llfilesystem/lldir_mac.cpp index 87dc1b9795..3bc4ee844e 100644 --- a/indra/llvfs/lldir_mac.cpp +++ b/indra/llfilesystem/lldir_mac.cpp @@ -36,7 +36,7 @@ #include #include #include -#include "llvfs_objc.h" +#include "lldir_utils_objc.h" // -------------------------------------------------------------------------------- diff --git a/indra/llvfs/lldir_mac.h b/indra/llfilesystem/lldir_mac.h similarity index 100% rename from indra/llvfs/lldir_mac.h rename to indra/llfilesystem/lldir_mac.h diff --git a/indra/llvfs/lldir_solaris.cpp b/indra/llfilesystem/lldir_solaris.cpp similarity index 100% rename from indra/llvfs/lldir_solaris.cpp rename to indra/llfilesystem/lldir_solaris.cpp diff --git a/indra/llvfs/lldir_solaris.h b/indra/llfilesystem/lldir_solaris.h similarity index 100% rename from indra/llvfs/lldir_solaris.h rename to indra/llfilesystem/lldir_solaris.h diff --git a/indra/llvfs/llvfs_objc.h b/indra/llfilesystem/lldir_utils_objc.h similarity index 85% rename from indra/llvfs/llvfs_objc.h rename to indra/llfilesystem/lldir_utils_objc.h index 56cdbebfc5..12019c4284 100644 --- a/indra/llvfs/llvfs_objc.h +++ b/indra/llfilesystem/lldir_utils_objc.h @@ -1,10 +1,10 @@ /** - * @file llvfs_objc.h + * @file lldir_utils_objc.h * @brief Definition of directory utilities class for Mac OS X * - * $LicenseInfo:firstyear=2000&license=viewerlgpl$ + * $LicenseInfo:firstyear=2020&license=viewerlgpl$ * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. + * Copyright (C) 2020, Linden Research, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -28,8 +28,8 @@ #error This header must not be included when compiling for any target other than Mac OS. Consider including lldir.h instead. #endif // !LL_DARWIN -#ifndef LL_LLVFS_OBJC_H -#define LL_LLVFS_OBJC_H +#ifndef LL_LLDIR_UTILS_OBJC_H +#define LL_LLDIR_UTILS_OBJC_H #include @@ -40,4 +40,4 @@ std::string* getSystemResourceFolder(); std::string* getSystemExecutableFolder(); -#endif // LL_LLVFS_OBJC_H +#endif // LL_LLDIR_UTILS_OBJC_H diff --git a/indra/llvfs/llvfs_objc.mm b/indra/llfilesystem/lldir_utils_objc.mm similarity index 95% rename from indra/llvfs/llvfs_objc.mm rename to indra/llfilesystem/lldir_utils_objc.mm index 282ea41339..da55a2f897 100644 --- a/indra/llvfs/llvfs_objc.mm +++ b/indra/llfilesystem/lldir_utils_objc.mm @@ -1,10 +1,10 @@ /** - * @file llvfs_objc.cpp + * @file lldir_utils_objc.mm * @brief Cocoa implementation of directory utilities for Mac OS X * - * $LicenseInfo:firstyear=2002&license=viewerlgpl$ + * $LicenseInfo:firstyear=2020&license=viewerlgpl$ * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. + * Copyright (C) 2020, Linden Research, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -27,7 +27,7 @@ //WARNING: This file CANNOT use standard linden includes due to conflicts between definitions of BOOL -#include "llvfs_objc.h" +#include "lldir_utils_objc.h" #import std::string* getSystemTempFolder() diff --git a/indra/llvfs/lldir_win32.cpp b/indra/llfilesystem/lldir_win32.cpp similarity index 100% rename from indra/llvfs/lldir_win32.cpp rename to indra/llfilesystem/lldir_win32.cpp diff --git a/indra/llvfs/lldir_win32.h b/indra/llfilesystem/lldir_win32.h similarity index 100% rename from indra/llvfs/lldir_win32.h rename to indra/llfilesystem/lldir_win32.h diff --git a/indra/llvfs/lldirguard.h b/indra/llfilesystem/lldirguard.h similarity index 100% rename from indra/llvfs/lldirguard.h rename to indra/llfilesystem/lldirguard.h diff --git a/indra/llvfs/lldiriterator.cpp b/indra/llfilesystem/lldiriterator.cpp similarity index 100% rename from indra/llvfs/lldiriterator.cpp rename to indra/llfilesystem/lldiriterator.cpp diff --git a/indra/llvfs/lldiriterator.h b/indra/llfilesystem/lldiriterator.h similarity index 100% rename from indra/llvfs/lldiriterator.h rename to indra/llfilesystem/lldiriterator.h diff --git a/indra/llfilesystem/lldiskcache.cpp b/indra/llfilesystem/lldiskcache.cpp new file mode 100644 index 0000000000..c9f7684b5a --- /dev/null +++ b/indra/llfilesystem/lldiskcache.cpp @@ -0,0 +1,327 @@ +/** + * @file lldiskcache.cpp + * @brief The disk cache implementation. + * + * Note: Rather than keep the top level function comments up + * to date in both the source and header files, I elected to + * only have explicit comments about each function and variable + * in the header - look there for details. The same is true for + * description of how this code is supposed to work. + * + * $LicenseInfo:firstyear=2009&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2020, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "linden_common.h" +#include "llassettype.h" +#include "lldir.h" +#include +#include +#include + +#include "lldiskcache.h" + +LLDiskCache::LLDiskCache(const std::string cache_dir, + const int max_size_bytes, + const bool enable_cache_debug_info) : + mCacheDir(cache_dir), + mMaxSizeBytes(max_size_bytes), + mEnableCacheDebugInfo(enable_cache_debug_info) +{ + mCacheFilenamePrefix = "sl_cache"; + + LLFile::mkdir(cache_dir); +} + +void LLDiskCache::purge() +{ + if (mEnableCacheDebugInfo) + { + LL_INFOS() << "Total dir size before purge is " << dirFileSize(mCacheDir) << LL_ENDL; + } + + auto start_time = std::chrono::high_resolution_clock::now(); + + typedef std::pair> file_info_t; + std::vector file_info; + +#if LL_WINDOWS + std::wstring cache_path(utf8str_to_utf16str(mCacheDir)); +#else + std::string cache_path(mCacheDir); +#endif + if (boost::filesystem::is_directory(cache_path)) + { + for (auto& entry : boost::make_iterator_range(boost::filesystem::directory_iterator(cache_path), {})) + { + if (boost::filesystem::is_regular_file(entry)) + { + if (entry.path().string().find(mCacheFilenamePrefix) != std::string::npos) + { + uintmax_t file_size = boost::filesystem::file_size(entry); + const std::string file_path = entry.path().string(); + const std::time_t file_time = boost::filesystem::last_write_time(entry); + + file_info.push_back(file_info_t(file_time, { file_size, file_path })); + } + } + } + } + + std::sort(file_info.begin(), file_info.end(), [](file_info_t& x, file_info_t& y) + { + return x.first > y.first; + }); + + LL_INFOS() << "Purging cache to a maximum of " << mMaxSizeBytes << " bytes" << LL_ENDL; + + uintmax_t file_size_total = 0; + for (file_info_t& entry : file_info) + { + file_size_total += entry.second.first; + + std::string action = ""; + if (file_size_total > mMaxSizeBytes) + { + action = "DELETE:"; + boost::filesystem::remove(entry.second.second); + } + else + { + action = " KEEP:"; + } + + if (mEnableCacheDebugInfo) + { + // have to do this because of LL_INFO/LL_END weirdness + std::ostringstream line; + + line << action << " "; + line << entry.first << " "; + line << entry.second.first << " "; + line << entry.second.second; + line << " (" << file_size_total << "/" << mMaxSizeBytes << ")"; + LL_INFOS() << line.str() << LL_ENDL; + } + } + + if (mEnableCacheDebugInfo) + { + auto end_time = std::chrono::high_resolution_clock::now(); + auto execute_time = std::chrono::duration_cast(end_time - start_time).count(); + LL_INFOS() << "Total dir size after purge is " << dirFileSize(mCacheDir) << LL_ENDL; + LL_INFOS() << "Cache purge took " << execute_time << " ms to execute for " << file_info.size() << " files" << LL_ENDL; + } +} + +const std::string LLDiskCache::assetTypeToString(LLAssetType::EType at) +{ + /** + * Make use of the handy C++17 feature that allows + * for inline initialization of an std::map<> + */ + typedef std::map asset_type_to_name_t; + asset_type_to_name_t asset_type_to_name = + { + { LLAssetType::AT_TEXTURE, "TEXTURE" }, + { LLAssetType::AT_SOUND, "SOUND" }, + { LLAssetType::AT_CALLINGCARD, "CALLINGCARD" }, + { LLAssetType::AT_LANDMARK, "LANDMARK" }, + { LLAssetType::AT_SCRIPT, "SCRIPT" }, + { LLAssetType::AT_CLOTHING, "CLOTHING" }, + { LLAssetType::AT_OBJECT, "OBJECT" }, + { LLAssetType::AT_NOTECARD, "NOTECARD" }, + { LLAssetType::AT_CATEGORY, "CATEGORY" }, + { LLAssetType::AT_LSL_TEXT, "LSL_TEXT" }, + { LLAssetType::AT_LSL_BYTECODE, "LSL_BYTECODE" }, + { LLAssetType::AT_TEXTURE_TGA, "TEXTURE_TGA" }, + { LLAssetType::AT_BODYPART, "BODYPART" }, + { LLAssetType::AT_SOUND_WAV, "SOUND_WAV" }, + { LLAssetType::AT_IMAGE_TGA, "IMAGE_TGA" }, + { LLAssetType::AT_IMAGE_JPEG, "IMAGE_JPEG" }, + { LLAssetType::AT_ANIMATION, "ANIMATION" }, + { LLAssetType::AT_GESTURE, "GESTURE" }, + { LLAssetType::AT_SIMSTATE, "SIMSTATE" }, + { LLAssetType::AT_LINK, "LINK" }, + { LLAssetType::AT_LINK_FOLDER, "LINK_FOLDER" }, + { LLAssetType::AT_MARKETPLACE_FOLDER, "MARKETPLACE_FOLDER" }, + { LLAssetType::AT_WIDGET, "WIDGET" }, + { LLAssetType::AT_PERSON, "PERSON" }, + { LLAssetType::AT_MESH, "MESH" }, + { LLAssetType::AT_SETTINGS, "SETTINGS" }, + { LLAssetType::AT_UNKNOWN, "UNKNOWN" } + }; + + asset_type_to_name_t::iterator iter = asset_type_to_name.find(at); + if (iter != asset_type_to_name.end()) + { + return iter->second; + } + + return std::string("UNKNOWN"); +} + +const std::string LLDiskCache::metaDataToFilepath(const std::string id, + LLAssetType::EType at, + const std::string extra_info) +{ + std::ostringstream file_path; + + file_path << mCacheDir; + file_path << gDirUtilp->getDirDelimiter(); + file_path << mCacheFilenamePrefix; + file_path << "_"; + file_path << id; + file_path << "_"; + file_path << (extra_info.empty() ? "0" : extra_info); + //file_path << "_"; + //file_path << assetTypeToString(at); // see SL-14210 Prune descriptive tag from new cache filenames + // for details of why it was removed. Note that if you put it + // back or change the format of the filename, the cache files + // files will be invalidated (and perhaps, more importantly, + // never deleted unless you delete them manually). + file_path << ".asset"; + + return file_path.str(); +} + +void LLDiskCache::updateFileAccessTime(const std::string file_path) +{ + /** + * Threshold in time_t units that is used to decide if the last access time + * time of the file is updated or not. Added as a precaution for the concern + * outlined in SL-14582 about frequent writes on older SSDs reducing their + * lifespan. I think this is the right place for the threshold value - rather + * than it being a pref - do comment on that Jira if you disagree... + * + * Let's start with 1 hour in time_t units and see how that unfolds + */ + const std::time_t time_threshold = 1 * 60 * 60; + + // current time + const std::time_t cur_time = std::time(nullptr); + +#if LL_WINDOWS + // file last write time + const std::time_t last_write_time = boost::filesystem::last_write_time(utf8str_to_utf16str(file_path)); + + // delta between cur time and last time the file was written + const std::time_t delta_time = cur_time - last_write_time; + + // we only write the new value if the time in time_threshold has elapsed + // before the last one + if (delta_time > time_threshold) + { + boost::filesystem::last_write_time(utf8str_to_utf16str(file_path), cur_time); + } +#else + // file last write time + const std::time_t last_write_time = boost::filesystem::last_write_time(file_path); + + // delta between cur time and last time the file was written + const std::time_t delta_time = cur_time - last_write_time; + + // we only write the new value if the time in time_threshold has elapsed + // before the last one + if (delta_time > time_threshold) + { + boost::filesystem::last_write_time(file_path, cur_time); + } +#endif +} + +const std::string LLDiskCache::getCacheInfo() +{ + std::ostringstream cache_info; + + F32 max_in_mb = (F32)mMaxSizeBytes / (1024.0 * 1024.0); + F32 percent_used = ((F32)dirFileSize(mCacheDir) / (F32)mMaxSizeBytes) * 100.0; + + cache_info << std::fixed; + cache_info << std::setprecision(1); + cache_info << "Max size " << max_in_mb << " MB "; + cache_info << "(" << percent_used << "% used)"; + + return cache_info.str(); +} + +void LLDiskCache::clearCache() +{ + /** + * See notes on performance in dirFileSize(..) - there may be + * a quicker way to do this by operating on the parent dir vs + * the component files but it's called infrequently so it's + * likely just fine + */ +#if LL_WINDOWS + std::wstring cache_path(utf8str_to_utf16str(mCacheDir)); +#else + std::string cache_path(mCacheDir); +#endif + if (boost::filesystem::is_directory(cache_path)) + { + for (auto& entry : boost::make_iterator_range(boost::filesystem::directory_iterator(cache_path), {})) + { + if (boost::filesystem::is_regular_file(entry)) + { + if (entry.path().string().find(mCacheFilenamePrefix) != std::string::npos) + { + boost::filesystem::remove(entry); + } + } + } + } +} + +uintmax_t LLDiskCache::dirFileSize(const std::string dir) +{ + uintmax_t total_file_size = 0; + + /** + * There may be a better way that works directly on the folder (similar to + * right clicking on a folder in the OS and asking for size vs right clicking + * on all files and adding up manually) but this is very fast - less than 100ms + * for 10,000 files in my testing so, so long as it's not called frequently, + * it should be okay. Note that's it's only currently used for logging/debugging + * so if performance is ever an issue, optimizing this or removing it altogether, + * is an easy win. + */ +#if LL_WINDOWS + std::wstring dir_path(utf8str_to_utf16str(dir)); +#else + std::string dir_path(dir); +#endif + if (boost::filesystem::is_directory(dir_path)) + { + for (auto& entry : boost::make_iterator_range(boost::filesystem::directory_iterator(dir_path), {})) + { + if (boost::filesystem::is_regular_file(entry)) + { + if (entry.path().string().find(mCacheFilenamePrefix) != std::string::npos) + { + total_file_size += boost::filesystem::file_size(entry); + } + } + } + } + + return total_file_size; +} diff --git a/indra/llfilesystem/lldiskcache.h b/indra/llfilesystem/lldiskcache.h new file mode 100644 index 0000000000..997884da31 --- /dev/null +++ b/indra/llfilesystem/lldiskcache.h @@ -0,0 +1,183 @@ +/** + * @file lldiskcache.h + * @brief The disk cache implementation declarations. + * + * @Description: + * This code implements a disk cache using the following ideas: + * 1/ The metadata for a file can be encapsulated in the filename. + The filenames will be composed of the following fields: + Prefix: Used to identify the file as a part of the cache. + An additional reason for using a prefix is that it + might be possible, either accidentally or maliciously + to end up with the cache dir set to a non-cache + location such as your OS system dir or a work folder. + Purging files from that would obviously be a disaster + so this is an extra step to help avoid that scenario. + ID: Typically the asset ID (UUID) of the asset being + saved but can be anything valid for a filename + Extra Info: A field for use in the future that can be used + to store extra identifiers - e.g. the discard + level of a JPEG2000 file + Asset Type: A text string created from the LLAssetType enum + that identifies the type of asset being stored. + .asset A file extension of .asset is used to help + identify this as a Viewer asset file + * 2/ The time of last access for a file can be updated instantly + * for file reads and automatically as part of the file writes. + * 3/ The purge algorithm collects a list of all files in the + * directory, sorts them by date of last access (write) and then + * deletes any files based on age until the total size of all + * the files is less than the maximum size specified. + * 4/ An LLSingleton idiom is used since there will only ever be + * a single cache and we want to access it from numerous places. + * 5/ Performance on my modest system seems very acceptable. For + * example, in testing, I was able to purge a directory of + * 10,000 files, deleting about half of them in ~ 1700ms. For + * the same sized directory of files, writing the last updated + * time to each took less than 600ms indicating that this + * important part of the mechanism has almost no overhead. + * + * $LicenseInfo:firstyear=2009&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2020, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef _LLDISKCACHE +#define _LLDISKCACHE + +#include "llsingleton.h" + +class LLDiskCache : + public LLParamSingleton +{ + public: + /** + * Since this is using the LLSingleton pattern but we + * want to allow the constructor to be called first + * with various parameters, we also invoke the + * LLParamSingleton idiom and use it to initialize + * the class via a call in LLAppViewer. + */ + LLSINGLETON(LLDiskCache, + /** + * The full name of the cache folder - typically a + * a child of the main Viewer cache directory. Defined + * by the setting at 'DiskCacheDirName' + */ + const std::string cache_dir, + /** + * The maximum size of the cache in bytes - Based on the + * setting at 'CacheSize' and 'DiskCachePercentOfTotal' + */ + const int max_size_bytes, + /** + * A flag that enables extra cache debugging so that + * if there are bugs, we can ask uses to enable this + * setting and send us their logs + */ + const bool enable_cache_debug_info); + + virtual ~LLDiskCache() = default; + + public: + /** + * Construct a filename and path to it based on the file meta data + * (id, asset type, additional 'extra' info like discard level perhaps) + * Worth pointing out that this function used to be in LLFileSystem but + * so many things had to be pushed back there to accomodate it, that I + * decided to move it here. Still not sure that's completely right. + */ + const std::string metaDataToFilepath(const std::string id, + LLAssetType::EType at, + const std::string extra_info); + + /** + * Update the "last write time" of a file to "now". This must be called whenever a + * file in the cache is read (not written) so that the last time the file was + * accessed is up to date (This is used in the mechanism for purging the cache) + */ + void updateFileAccessTime(const std::string file_path); + + /** + * Purge the oldest items in the cache so that the combined size of all files + * is no bigger than mMaxSizeBytes. + */ + void purge(); + + /** + * Clear the cache by removing all the files in the specified cache + * directory individually. Only the files that contain a prefix defined + * by mCacheFilenamePrefix will be removed. + */ + void clearCache(); + + /** + * Return some information about the cache for use in About Box etc. + */ + const std::string getCacheInfo(); + + private: + /** + * Utility function to gather the total size the files in a given + * directory. Primarily used here to determine the directory size + * before and after the cache purge + */ + uintmax_t dirFileSize(const std::string dir); + + /** + * Utility function to convert an LLAssetType enum into a + * string that we use as part of the cache file filename + */ + const std::string assetTypeToString(LLAssetType::EType at); + + private: + /** + * The maximum size of the cache in bytes. After purge is called, the + * total size of the cache files in the cache directory will be + * less than this value + */ + uintmax_t mMaxSizeBytes; + + /** + * The folder that holds the cached files. The consumer of this + * class must avoid letting the user set this location as a malicious + * setting could potentially point it at a non-cache directory (for example, + * the Windows System dir) with disastrous results. + */ + std::string mCacheDir; + + /** + * The prefix inserted at the start of a cache file filename to + * help identify it as a cache file. It's probably not required + * (just the presence in the cache folder is enough) but I am + * paranoid about the cache folder being set to something bad + * like the users' OS system dir by mistake or maliciously and + * this will help to offset any damage if that happens. + */ + std::string mCacheFilenamePrefix; + + /** + * When enabled, displays additional debugging information in + * various parts of the code + */ + bool mEnableCacheDebugInfo; +}; + +#endif // _LLDISKCACHE diff --git a/indra/llfilesystem/llfilesystem.cpp b/indra/llfilesystem/llfilesystem.cpp new file mode 100644 index 0000000000..053b52014e --- /dev/null +++ b/indra/llfilesystem/llfilesystem.cpp @@ -0,0 +1,283 @@ +/** + * @file filesystem.h + * @brief Simulate local file system operations. + * @Note The initial implementation does actually use standard C++ + * file operations but eventually, there will be another + * layer that caches and manages file meta data too. + * + * $LicenseInfo:firstyear=2002&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "linden_common.h" + +#include "lldir.h" +#include "llfilesystem.h" +#include "llfasttimer.h" +#include "lldiskcache.h" + +const S32 LLFileSystem::READ = 0x00000001; +const S32 LLFileSystem::WRITE = 0x00000002; +const S32 LLFileSystem::READ_WRITE = 0x00000003; // LLFileSystem::READ & LLFileSystem::WRITE +const S32 LLFileSystem::APPEND = 0x00000006; // 0x00000004 & LLFileSystem::WRITE + +static LLTrace::BlockTimerStatHandle FTM_VFILE_WAIT("VFile Wait"); + +LLFileSystem::LLFileSystem(const LLUUID& file_id, const LLAssetType::EType file_type, S32 mode) +{ + mFileType = file_type; + mFileID = file_id; + mPosition = 0; + mBytesRead = 0; + mMode = mode; +} + +LLFileSystem::~LLFileSystem() +{ +} + +// static +bool LLFileSystem::getExists(const LLUUID& file_id, const LLAssetType::EType file_type) +{ + std::string id_str; + file_id.toString(id_str); + const std::string extra_info = ""; + const std::string filename = LLDiskCache::getInstance()->metaDataToFilepath(id_str, file_type, extra_info); + + llifstream file(filename, std::ios::binary); + if (file.is_open()) + { + file.seekg(0, std::ios::end); + return file.tellg() > 0; + } + return false; +} + +// static +bool LLFileSystem::removeFile(const LLUUID& file_id, const LLAssetType::EType file_type, int suppress_error /*= 0*/) +{ + std::string id_str; + file_id.toString(id_str); + const std::string extra_info = ""; + const std::string filename = LLDiskCache::getInstance()->metaDataToFilepath(id_str, file_type, extra_info); + + LLFile::remove(filename.c_str(), suppress_error); + + return true; +} + +// static +bool LLFileSystem::renameFile(const LLUUID& old_file_id, const LLAssetType::EType old_file_type, + const LLUUID& new_file_id, const LLAssetType::EType new_file_type) +{ + std::string old_id_str; + old_file_id.toString(old_id_str); + const std::string extra_info = ""; + const std::string old_filename = LLDiskCache::getInstance()->metaDataToFilepath(old_id_str, old_file_type, extra_info); + + std::string new_id_str; + new_file_id.toString(new_id_str); + const std::string new_filename = LLDiskCache::getInstance()->metaDataToFilepath(new_id_str, new_file_type, extra_info); + + // Rename needs the new file to not exist. + LLFileSystem::removeFile(new_file_id, new_file_type, ENOENT); + + if (LLFile::rename(old_filename, new_filename) != 0) + { + // We would like to return FALSE here indicating the operation + // failed but the original code does not and doing so seems to + // break a lot of things so we go with the flow... + //return FALSE; + LL_WARNS() << "Failed to rename " << old_file_id << " to " << new_id_str << " reason: " << strerror(errno) << LL_ENDL; + } + + return TRUE; +} + +// static +S32 LLFileSystem::getFileSize(const LLUUID& file_id, const LLAssetType::EType file_type) +{ + std::string id_str; + file_id.toString(id_str); + const std::string extra_info = ""; + const std::string filename = LLDiskCache::getInstance()->metaDataToFilepath(id_str, file_type, extra_info); + + S32 file_size = 0; + llifstream file(filename, std::ios::binary); + if (file.is_open()) + { + file.seekg(0, std::ios::end); + file_size = file.tellg(); + } + + return file_size; +} + +BOOL LLFileSystem::read(U8* buffer, S32 bytes) +{ + BOOL success = TRUE; + + std::string id; + mFileID.toString(id); + const std::string extra_info = ""; + const std::string filename = LLDiskCache::getInstance()->metaDataToFilepath(id, mFileType, extra_info); + + llifstream file(filename, std::ios::binary); + if (file.is_open()) + { + file.seekg(mPosition, std::ios::beg); + + file.read((char*)buffer, bytes); + + if (file) + { + mBytesRead = bytes; + } + else + { + mBytesRead = file.gcount(); + } + + file.close(); + + mPosition += mBytesRead; + if (!mBytesRead) + { + success = FALSE; + } + } + + // 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; +} + +S32 LLFileSystem::getLastBytesRead() +{ + return mBytesRead; +} + +BOOL LLFileSystem::eof() +{ + return mPosition >= getSize(); +} + +BOOL LLFileSystem::write(const U8* buffer, S32 bytes) +{ + std::string id_str; + mFileID.toString(id_str); + const std::string extra_info = ""; + const std::string filename = LLDiskCache::getInstance()->metaDataToFilepath(id_str, mFileType, extra_info); + + BOOL success = FALSE; + + if (mMode == APPEND) + { + llofstream ofs(filename, std::ios::app | std::ios::binary); + if (ofs) + { + ofs.write((const char*)buffer, bytes); + + success = TRUE; + } + } + else + { + llofstream ofs(filename, std::ios::binary); + if (ofs) + { + ofs.write((const char*)buffer, bytes); + + mPosition += bytes; + + success = TRUE; + } + } + + return success; +} + +BOOL LLFileSystem::seek(S32 offset, S32 origin) +{ + if (-1 == origin) + { + origin = mPosition; + } + + S32 new_pos = origin + offset; + + S32 size = getSize(); + + if (new_pos > size) + { + LL_WARNS() << "Attempt to seek past end of file" << LL_ENDL; + + mPosition = size; + return FALSE; + } + else if (new_pos < 0) + { + LL_WARNS() << "Attempt to seek past beginning of file" << LL_ENDL; + + mPosition = 0; + return FALSE; + } + + mPosition = new_pos; + return TRUE; +} + +S32 LLFileSystem::tell() const +{ + return mPosition; +} + +S32 LLFileSystem::getSize() +{ + return LLFileSystem::getFileSize(mFileID, mFileType); +} + +S32 LLFileSystem::getMaxSize() +{ + // offer up a huge size since we don't care what the max is + return INT_MAX; +} + +BOOL LLFileSystem::rename(const LLUUID& new_id, const LLAssetType::EType new_type) +{ + LLFileSystem::renameFile(mFileID, mFileType, new_id, new_type); + + mFileID = new_id; + mFileType = new_type; + + return TRUE; +} + +BOOL LLFileSystem::remove() +{ + LLFileSystem::removeFile(mFileID, mFileType); + + return TRUE; +} diff --git a/indra/llfilesystem/llfilesystem.h b/indra/llfilesystem/llfilesystem.h new file mode 100644 index 0000000000..d934a408c2 --- /dev/null +++ b/indra/llfilesystem/llfilesystem.h @@ -0,0 +1,78 @@ +/** + * @file filesystem.h + * @brief Simulate local file system operations. + * @Note The initial implementation does actually use standard C++ + * file operations but eventually, there will be another + * layer that caches and manages file meta data too. + * + * $LicenseInfo:firstyear=2002&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LL_FILESYSTEM_H +#define LL_FILESYSTEM_H + +#include "lluuid.h" +#include "llassettype.h" +#include "lldiskcache.h" + +class LLFileSystem +{ + public: + LLFileSystem(const LLUUID& file_id, const LLAssetType::EType file_type, S32 mode = LLFileSystem::READ); + ~LLFileSystem(); + + BOOL read(U8* buffer, S32 bytes); + S32 getLastBytesRead(); + BOOL eof(); + + BOOL write(const U8* buffer, S32 bytes); + BOOL seek(S32 offset, S32 origin = -1); + S32 tell() const; + + S32 getSize(); + S32 getMaxSize(); + BOOL rename(const LLUUID& new_id, const LLAssetType::EType new_type); + BOOL remove(); + + static bool getExists(const LLUUID& file_id, const LLAssetType::EType file_type); + static bool removeFile(const LLUUID& file_id, const LLAssetType::EType file_type, int suppress_error = 0); + static bool renameFile(const LLUUID& old_file_id, const LLAssetType::EType old_file_type, + const LLUUID& new_file_id, const LLAssetType::EType new_file_type); + static S32 getFileSize(const LLUUID& file_id, const LLAssetType::EType file_type); + + public: + static const S32 READ; + static const S32 WRITE; + static const S32 READ_WRITE; + static const S32 APPEND; + + protected: + LLAssetType::EType mFileType; + LLUUID mFileID; + S32 mPosition; + S32 mMode; + S32 mBytesRead; +//private: +// static const std::string idToFilepath(const std::string id, LLAssetType::EType at); +}; + +#endif // LL_FILESYSTEM_H diff --git a/indra/llvfs/lllfsthread.cpp b/indra/llfilesystem/lllfsthread.cpp similarity index 100% rename from indra/llvfs/lllfsthread.cpp rename to indra/llfilesystem/lllfsthread.cpp diff --git a/indra/llvfs/lllfsthread.h b/indra/llfilesystem/lllfsthread.h similarity index 100% rename from indra/llvfs/lllfsthread.h rename to indra/llfilesystem/lllfsthread.h diff --git a/indra/llvfs/tests/lldir_test.cpp b/indra/llfilesystem/tests/lldir_test.cpp similarity index 100% rename from indra/llvfs/tests/lldir_test.cpp rename to indra/llfilesystem/tests/lldir_test.cpp diff --git a/indra/llvfs/tests/lldiriterator_test.cpp b/indra/llfilesystem/tests/lldiriterator_test.cpp similarity index 100% rename from indra/llvfs/tests/lldiriterator_test.cpp rename to indra/llfilesystem/tests/lldiriterator_test.cpp diff --git a/indra/llimage/CMakeLists.txt b/indra/llimage/CMakeLists.txt index 293ada7548..dc8e9f7c2f 100644 --- a/indra/llimage/CMakeLists.txt +++ b/indra/llimage/CMakeLists.txt @@ -6,7 +6,7 @@ include(00-Common) include(LLCommon) include(LLImage) include(LLMath) -include(LLVFS) +include(LLFileSystem) include(LLKDU) include(LLImageJ2COJ) include(ZLIB) @@ -17,7 +17,7 @@ include_directories( ${LLCOMMON_INCLUDE_DIRS} ${LLCOMMON_SYSTEM_INCLUDE_DIRS} ${LLMATH_INCLUDE_DIRS} - ${LLVFS_INCLUDE_DIRS} + ${LLFILESYSTEM_INCLUDE_DIRS} ${PNG_INCLUDE_DIRS} ${ZLIB_INCLUDE_DIRS} ) @@ -68,7 +68,7 @@ else (USE_KDU) endif (USE_KDU) target_link_libraries(llimage - ${LLVFS_LIBRARIES} + ${LLFILESYSTEM_LIBRARIES} ${LLMATH_LIBRARIES} ${LLCOMMON_LIBRARIES} ${JPEG_LIBRARIES} diff --git a/indra/llimage/llimage.cpp b/indra/llimage/llimage.cpp index aed8943439..350a8eb120 100644 --- a/indra/llimage/llimage.cpp +++ b/indra/llimage/llimage.cpp @@ -2219,20 +2219,11 @@ bool LLImageFormatted::save(const std::string &filename) return true; } -// bool LLImageFormatted::save(LLVFS *vfs, const LLUUID &uuid, LLAssetType::EType type) -// Depricated to remove VFS dependency. -// Use: -// LLVFile::writeFile(image->getData(), image->getDataSize(), vfs, uuid, type); - -//---------------------------------------------------------------------------- - S8 LLImageFormatted::getCodec() const { return mCodec; } -//============================================================================ - static void avg4_colors4(const U8* a, const U8* b, const U8* c, const U8* d, U8* dst) { dst[0] = (U8)(((U32)(a[0]) + b[0] + c[0] + d[0])>>2); diff --git a/indra/llinventory/CMakeLists.txt b/indra/llinventory/CMakeLists.txt index e829788c91..04975940aa 100644 --- a/indra/llinventory/CMakeLists.txt +++ b/indra/llinventory/CMakeLists.txt @@ -7,7 +7,7 @@ include(LLCommon) include(LLCoreHttp) include(LLMath) include(LLMessage) -include(LLVFS) +include(LLFileSystem) include(LLXML) include_directories( @@ -81,7 +81,7 @@ if (LL_TESTS) LL_ADD_PROJECT_UNIT_TESTS(llinventory "${llinventory_TEST_SOURCE_FILES}") #set(TEST_DEBUG on) - set(test_libs llinventory ${LLMESSAGE_LIBRARIES} ${LLVFS_LIBRARIES} ${LLCOREHTTP_LIBRARIES} ${LLMATH_LIBRARIES} ${LLCOMMON_LIBRARIES} ${WINDOWS_LIBRARIES}) + set(test_libs llinventory ${LLMESSAGE_LIBRARIES} ${LLFILESYSTEM_LIBRARIES} ${LLCOREHTTP_LIBRARIES} ${LLMATH_LIBRARIES} ${LLCOMMON_LIBRARIES} ${WINDOWS_LIBRARIES}) LL_ADD_INTEGRATION_TEST(inventorymisc "" "${test_libs}") LL_ADD_INTEGRATION_TEST(llparcel "" "${test_libs}") endif (LL_TESTS) diff --git a/indra/llmessage/CMakeLists.txt b/indra/llmessage/CMakeLists.txt index 2f99ca069e..f0a1dfe940 100644 --- a/indra/llmessage/CMakeLists.txt +++ b/indra/llmessage/CMakeLists.txt @@ -9,7 +9,7 @@ include(LLCommon) include(LLCoreHttp) include(LLMath) include(LLMessage) -include(LLVFS) +include(LLFileSystem) include(LLAddBuildTest) include(Python) include(Tut) @@ -23,7 +23,7 @@ include_directories( ${LLCOREHTTP_INCLUDE_DIRS} ${LLMATH_INCLUDE_DIRS} ${LLMESSAGE_INCLUDE_DIRS} - ${LLVFS_INCLUDE_DIRS} + ${LLFILESYSTEM_INCLUDE_DIRS} ${JSONCPP_INCLUDE_DIR} ) @@ -209,7 +209,7 @@ target_link_libraries( llmessage ${CURL_LIBRARIES} ${LLCOMMON_LIBRARIES} - ${LLVFS_LIBRARIES} + ${LLFILESYSTEM_LIBRARIES} ${LLMATH_LIBRARIES} ${JSONCPP_LIBRARIES} ${OPENSSL_LIBRARIES} @@ -227,7 +227,7 @@ target_link_libraries( llmessage ${CURL_LIBRARIES} ${LLCOMMON_LIBRARIES} - ${LLVFS_LIBRARIES} + ${LLFILESYSTEM_LIBRARIES} ${LLMATH_LIBRARIES} ${JSONCPP_LIBRARIES} ${OPENSSL_LIBRARIES} @@ -257,7 +257,7 @@ if (LL_TESTS) if (LINUX) set(test_libs ${WINDOWS_LIBRARIES} - ${LLVFS_LIBRARIES} + ${LLFILESYSTEM_LIBRARIES} ${LLMATH_LIBRARIES} ${CURL_LIBRARIES} ${NGHTTP2_LIBRARIES} @@ -273,7 +273,7 @@ if (LINUX) else (LINUX) set(test_libs ${WINDOWS_LIBRARIES} - ${LLVFS_LIBRARIES} + ${LLFILESYSTEM_LIBRARIES} ${LLMATH_LIBRARIES} ${CURL_LIBRARIES} ${NGHTTP2_LIBRARIES} diff --git a/indra/llmessage/llassetstorage.cpp b/indra/llmessage/llassetstorage.cpp index d7801b6ddc..f38a5e663e 100644 --- a/indra/llmessage/llassetstorage.cpp +++ b/indra/llmessage/llassetstorage.cpp @@ -42,8 +42,7 @@ // this library includes #include "message.h" #include "llxfermanager.h" -#include "llvfile.h" -#include "llvfs.h" +#include "llfilesystem.h" #include "lldbstrings.h" #include "lltransfersourceasset.h" @@ -202,7 +201,7 @@ LLBaseDownloadRequest::LLBaseDownloadRequest(const LLUUID &uuid, const LLAssetTy mIsTemp(FALSE), mIsPriority(FALSE), mDataSentInFirstPacket(FALSE), - mDataIsInVFS(FALSE) + mDataIsInCache(FALSE) { // Need to guarantee that this time is up to date, we may be creating a circuit even though we haven't been // running a message system loop. @@ -266,7 +265,8 @@ LLSD LLAssetRequest::getFullDetails() const sd["is_local"] = mIsLocal; sd["is_priority"] = mIsPriority; sd["data_send_in_first_packet"] = mDataSentInFirstPacket; - sd["data_is_in_vfs"] = mDataIsInVFS; + // Note: cannot change this (easily) since it is consumed by server + sd["data_is_in_vfs"] = mDataIsInCache; return sd; } @@ -330,28 +330,23 @@ LLBaseDownloadRequest* LLEstateAssetRequest::getCopy() // TODO: rework tempfile handling? -LLAssetStorage::LLAssetStorage(LLMessageSystem *msg, LLXferManager *xfer, LLVFS *vfs, LLVFS *static_vfs, const LLHost &upstream_host) +LLAssetStorage::LLAssetStorage(LLMessageSystem *msg, LLXferManager *xfer, const LLHost &upstream_host) { - _init(msg, xfer, vfs, static_vfs, upstream_host); + _init(msg, xfer, upstream_host); } -LLAssetStorage::LLAssetStorage(LLMessageSystem *msg, LLXferManager *xfer, - LLVFS *vfs, LLVFS *static_vfs) +LLAssetStorage::LLAssetStorage(LLMessageSystem *msg, LLXferManager *xfer) { - _init(msg, xfer, vfs, static_vfs, LLHost()); + _init(msg, xfer, LLHost()); } void LLAssetStorage::_init(LLMessageSystem *msg, LLXferManager *xfer, - LLVFS *vfs, - LLVFS *static_vfs, const LLHost &upstream_host) { mShutDown = FALSE; mMessageSys = msg; mXferManager = xfer; - mVFS = vfs; - mStaticVFS = static_vfs; setUpstream(upstream_host); msg->setHandlerFuncFast(_PREHASH_AssetUploadComplete, processUploadComplete, (void **)this); @@ -430,7 +425,7 @@ void LLAssetStorage::_cleanupRequests(BOOL all, S32 error) } if (tmp->mDownCallback) { - tmp->mDownCallback(mVFS, tmp->getUUID(), tmp->getType(), tmp->mUserData, error, LLExtStat::NONE); + tmp->mDownCallback(tmp->getUUID(), tmp->getType(), tmp->mUserData, error, LLExtStat::NONE); } if (tmp->mInfoCallback) { @@ -443,10 +438,10 @@ void LLAssetStorage::_cleanupRequests(BOOL all, S32 error) BOOL LLAssetStorage::hasLocalAsset(const LLUUID &uuid, const LLAssetType::EType type) { - return mStaticVFS->getExists(uuid, type) || mVFS->getExists(uuid, type); + return LLFileSystem::getExists(uuid, type); } -bool LLAssetStorage::findInStaticVFSAndInvokeCallback(const LLUUID& uuid, LLAssetType::EType type, +bool LLAssetStorage::findInCacheAndInvokeCallback(const LLUUID& uuid, LLAssetType::EType type, LLGetAssetCallback callback, void *user_data) { if (user_data) @@ -455,17 +450,17 @@ bool LLAssetStorage::findInStaticVFSAndInvokeCallback(const LLUUID& uuid, LLAsse llassert(callback != NULL); } - BOOL exists = mStaticVFS->getExists(uuid, type); + BOOL exists = LLFileSystem::getExists(uuid, type); if (exists) { - LLVFile file(mStaticVFS, uuid, type); + LLFileSystem file(uuid, type); U32 size = file.getSize(); if (size > 0) { // we've already got the file if (callback) { - callback(mStaticVFS, uuid, type, user_data, LL_ERR_NOERR, LLExtStat::VFS_CACHED); + callback(uuid, type, user_data, LL_ERR_NOERR, LLExtStat::CACHE_CACHED); } return true; } @@ -506,7 +501,7 @@ void LLAssetStorage::getAssetData(const LLUUID uuid, if (callback) { add(sFailedDownloadCount, 1); - callback(mVFS, uuid, type, user_data, LL_ERR_ASSET_REQUEST_FAILED, LLExtStat::NONE); + callback(uuid, type, user_data, LL_ERR_ASSET_REQUEST_FAILED, LLExtStat::NONE); } return; } @@ -517,20 +512,19 @@ void LLAssetStorage::getAssetData(const LLUUID uuid, if (callback) { add(sFailedDownloadCount, 1); - callback(mVFS, uuid, type, user_data, LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE, LLExtStat::NULL_UUID); + callback(uuid, type, user_data, LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE, LLExtStat::NULL_UUID); } return; } - // Try static VFS first. - if (findInStaticVFSAndInvokeCallback(uuid,type,callback,user_data)) + if (findInCacheAndInvokeCallback(uuid,type,callback,user_data)) { - LL_DEBUGS("AssetStorage") << "ASSET_TRACE asset " << uuid << " found in static VFS" << LL_ENDL; + LL_DEBUGS("AssetStorage") << "ASSET_TRACE asset " << uuid << " found in cache" << LL_ENDL; return; } - BOOL exists = mVFS->getExists(uuid, type); - LLVFile file(mVFS, uuid, type); + BOOL exists = LLFileSystem::getExists(uuid, type); + LLFileSystem file(uuid, type); U32 size = exists ? file.getSize() : 0; if (size > 0) @@ -540,10 +534,10 @@ void LLAssetStorage::getAssetData(const LLUUID uuid, // unless there's a weird error if (callback) { - callback(mVFS, uuid, type, user_data, LL_ERR_NOERR, LLExtStat::VFS_CACHED); + callback(uuid, type, user_data, LL_ERR_NOERR, LLExtStat::CACHE_CACHED); } - LL_DEBUGS("AssetStorage") << "ASSET_TRACE asset " << uuid << " found in VFS" << LL_ENDL; + LL_DEBUGS("AssetStorage") << "ASSET_TRACE asset " << uuid << " found in cache" << LL_ENDL; } else { @@ -616,7 +610,7 @@ void LLAssetStorage::removeAndCallbackPendingDownloads(const LLUUID& file_id, LL { add(sFailedDownloadCount, 1); } - tmp->mDownCallback(gAssetStorage->mVFS, callback_id, callback_type, tmp->mUserData, result_code, ext_status); + tmp->mDownCallback(callback_id, callback_type, tmp->mUserData, result_code, ext_status); } delete tmp; } @@ -670,7 +664,7 @@ void LLAssetStorage::downloadCompleteCallback( if (LL_ERR_NOERR == result) { // we might have gotten a zero-size file - LLVFile vfile(gAssetStorage->mVFS, callback_id, callback_type); + LLFileSystem vfile(callback_id, callback_type); if (vfile.getSize() <= 0) { LL_WARNS("AssetStorage") << "downloadCompleteCallback has non-existent or zero-size asset " << callback_id << LL_ENDL; @@ -719,19 +713,19 @@ void LLAssetStorage::getEstateAsset( if (callback) { add(sFailedDownloadCount, 1); - callback(mVFS, asset_id, atype, user_data, LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE, LLExtStat::NULL_UUID); + callback(asset_id, atype, user_data, LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE, LLExtStat::NULL_UUID); } return; } - // Try static VFS first. - if (findInStaticVFSAndInvokeCallback(asset_id,atype,callback,user_data)) + // Try static first. + if (findInCacheAndInvokeCallback(asset_id,atype,callback,user_data)) { return; } - BOOL exists = mVFS->getExists(asset_id, atype); - LLVFile file(mVFS, asset_id, atype); + BOOL exists = LLFileSystem::getExists(asset_id, atype); + LLFileSystem file(asset_id, atype); U32 size = exists ? file.getSize() : 0; if (size > 0) @@ -741,7 +735,7 @@ void LLAssetStorage::getEstateAsset( // unless there's a weird error if (callback) { - callback(mVFS, asset_id, atype, user_data, LL_ERR_NOERR, LLExtStat::VFS_CACHED); + callback(asset_id, atype, user_data, LL_ERR_NOERR, LLExtStat::CACHE_CACHED); } } else @@ -792,7 +786,7 @@ void LLAssetStorage::getEstateAsset( if (callback) { add(sFailedDownloadCount, 1); - callback(mVFS, asset_id, atype, user_data, LL_ERR_CIRCUIT_GONE, LLExtStat::NO_UPSTREAM); + callback(asset_id, atype, user_data, LL_ERR_CIRCUIT_GONE, LLExtStat::NO_UPSTREAM); } } } @@ -824,7 +818,7 @@ void LLAssetStorage::downloadEstateAssetCompleteCallback( if (LL_ERR_NOERR == result) { // we might have gotten a zero-size file - LLVFile vfile(gAssetStorage->mVFS, req->getUUID(), req->getAType()); + LLFileSystem vfile(req->getUUID(), req->getAType()); if (vfile.getSize() <= 0) { LL_WARNS("AssetStorage") << "downloadCompleteCallback has non-existent or zero-size asset!" << LL_ENDL; @@ -838,7 +832,7 @@ void LLAssetStorage::downloadEstateAssetCompleteCallback( { add(sFailedDownloadCount, 1); } - req->mDownCallback(gAssetStorage->mVFS, req->getUUID(), req->getAType(), req->mUserData, result, ext_status); + req->mDownCallback(req->getUUID(), req->getAType(), req->mUserData, result, ext_status); } void LLAssetStorage::getInvItemAsset( @@ -861,14 +855,13 @@ void LLAssetStorage::getInvItemAsset( if(asset_id.notNull()) { - // Try static VFS first. - if (findInStaticVFSAndInvokeCallback( asset_id, atype, callback, user_data)) + if (findInCacheAndInvokeCallback( asset_id, atype, callback, user_data)) { return; } - exists = mVFS->getExists(asset_id, atype); - LLVFile file(mVFS, asset_id, atype); + exists = LLFileSystem::getExists(asset_id, atype); + LLFileSystem file(asset_id, atype); size = exists ? file.getSize() : 0; if(exists && size < 1) { @@ -885,7 +878,7 @@ void LLAssetStorage::getInvItemAsset( // unless there's a weird error if (callback) { - callback(mVFS, asset_id, atype, user_data, LL_ERR_NOERR, LLExtStat::VFS_CACHED); + callback(asset_id, atype, user_data, LL_ERR_NOERR, LLExtStat::CACHE_CACHED); } } else @@ -936,7 +929,7 @@ void LLAssetStorage::getInvItemAsset( if (callback) { add(sFailedDownloadCount, 1); - callback(mVFS, asset_id, atype, user_data, LL_ERR_CIRCUIT_GONE, LLExtStat::NO_UPSTREAM); + callback(asset_id, atype, user_data, LL_ERR_CIRCUIT_GONE, LLExtStat::NO_UPSTREAM); } } } @@ -968,7 +961,7 @@ void LLAssetStorage::downloadInvItemCompleteCallback( if (LL_ERR_NOERR == result) { // we might have gotten a zero-size file - LLVFile vfile(gAssetStorage->mVFS, req->getUUID(), req->getType()); + LLFileSystem vfile(req->getUUID(), req->getType()); if (vfile.getSize() <= 0) { LL_WARNS("AssetStorage") << "downloadCompleteCallback has non-existent or zero-size asset!" << LL_ENDL; @@ -982,7 +975,7 @@ void LLAssetStorage::downloadInvItemCompleteCallback( { add(sFailedDownloadCount, 1); } - req->mDownCallback(gAssetStorage->mVFS, req->getUUID(), req->getType(), req->mUserData, result, ext_status); + req->mDownCallback(req->getUUID(), req->getType(), req->mUserData, result, ext_status); } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -1293,7 +1286,7 @@ bool LLAssetStorage::deletePendingRequestImpl(LLAssetStorage::request_list_t* re if (req->mDownCallback) { add(sFailedDownloadCount, 1); - req->mDownCallback(mVFS, req->getUUID(), req->getType(), req->mUserData, error, LLExtStat::REQUEST_DROPPED); + req->mDownCallback(req->getUUID(), req->getType(), req->mUserData, error, LLExtStat::REQUEST_DROPPED); } if (req->mInfoCallback) { @@ -1363,8 +1356,7 @@ void LLAssetStorage::getAssetData(const LLUUID uuid, { LLAssetRequest* tmp = *iter++; - //void(*const* cbptr)(LLVFS *, const LLUUID &, LLAssetType::EType, void *, S32, LLExtStat) - auto cbptr = tmp->mDownCallback.target(); + auto cbptr = tmp->mDownCallback.target(); if (type == tmp->getType() && uuid == tmp->getUUID() && @@ -1389,8 +1381,7 @@ void LLAssetStorage::getAssetData(const LLUUID uuid, } // static -void LLAssetStorage::legacyGetDataCallback(LLVFS *vfs, - const LLUUID &uuid, +void LLAssetStorage::legacyGetDataCallback(const LLUUID &uuid, LLAssetType::EType type, void *user_data, S32 status, @@ -1405,7 +1396,7 @@ void LLAssetStorage::legacyGetDataCallback(LLVFS *vfs, if ( !status && !toxic ) { - LLVFile file(vfs, uuid, type); + LLFileSystem file(uuid, type); std::string uuid_str; diff --git a/indra/llmessage/llassetstorage.h b/indra/llmessage/llassetstorage.h index c799d8eefc..e0f22f1160 100644 --- a/indra/llmessage/llassetstorage.h +++ b/indra/llmessage/llassetstorage.h @@ -44,7 +44,6 @@ class LLMessageSystem; class LLXferManager; class LLAssetStorage; -class LLVFS; class LLSD; // anything that takes longer than this to download will abort. @@ -60,11 +59,11 @@ const int LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE = -4; const int LL_ERR_INSUFFICIENT_PERMISSIONS = -5; const int LL_ERR_PRICE_MISMATCH = -23018; -// *TODO: these typedefs are passed into the VFS via a legacy C function pointer +// *TODO: these typedefs are passed into the cache via a legacy C function pointer // future project would be to convert these to C++ callables (std::function<>) so that // we can use bind and remove the userData parameter. // -typedef std::function LLGetAssetCallback; +typedef std::function LLGetAssetCallback; typedef std::function LLStoreAssetCallback; @@ -120,7 +119,6 @@ protected: public: LLGetAssetCallback mDownCallback; -// void(*mDownCallback)(LLVFS*, const LLUUID&, LLAssetType::EType, void *, S32, LLExtStat); void *mUserData; LLHost mHost; @@ -128,7 +126,7 @@ public: F64Seconds mTime; // Message system time BOOL mIsPriority; BOOL mDataSentInFirstPacket; - BOOL mDataIsInVFS; + BOOL mDataIsInCache; }; class LLAssetRequest : public LLBaseDownloadRequest @@ -198,9 +196,6 @@ typedef std::map toxic_asset_map_t; class LLAssetStorage { public: - // VFS member is public because static child methods need it :( - LLVFS *mVFS; - LLVFS *mStaticVFS; typedef ::LLStoreAssetCallback LLStoreAssetCallback; typedef ::LLGetAssetCallback LLGetAssetCallback; @@ -230,11 +225,9 @@ protected: toxic_asset_map_t mToxicAssetMap; // Objects in this list are known to cause problems and are not loaded public: - LLAssetStorage(LLMessageSystem *msg, LLXferManager *xfer, - LLVFS *vfs, LLVFS *static_vfs, const LLHost &upstream_host); + LLAssetStorage(LLMessageSystem *msg, LLXferManager *xfer, const LLHost &upstream_host); - LLAssetStorage(LLMessageSystem *msg, LLXferManager *xfer, - LLVFS *vfs, LLVFS *static_vfs); + LLAssetStorage(LLMessageSystem *msg, LLXferManager *xfer); virtual ~LLAssetStorage(); void setUpstream(const LLHost &upstream_host); @@ -284,7 +277,7 @@ public: void markAssetToxic( const LLUUID& uuid ); protected: - bool findInStaticVFSAndInvokeCallback(const LLUUID& uuid, LLAssetType::EType type, + bool findInCacheAndInvokeCallback(const LLUUID& uuid, LLAssetType::EType type, LLGetAssetCallback callback, void *user_data); LLSD getPendingDetailsImpl(const request_list_t* requests, @@ -375,7 +368,7 @@ public: bool user_waiting = false, F64Seconds timeout = LL_ASSET_STORAGE_TIMEOUT) = 0; - static void legacyGetDataCallback(LLVFS *vfs, const LLUUID &uuid, LLAssetType::EType, void *user_data, S32 status, LLExtStat ext_status); + static void legacyGetDataCallback(const LLUUID &uuid, LLAssetType::EType, void *user_data, S32 status, LLExtStat ext_status); static void legacyStoreDataCallback(const LLUUID &uuid, void *user_data, S32 status, LLExtStat ext_status); // add extra methods to handle metadata @@ -385,15 +378,12 @@ protected: void _callUploadCallbacks(const LLUUID &uuid, const LLAssetType::EType asset_type, BOOL success, LLExtStat ext_status); virtual void _queueDataRequest(const LLUUID& uuid, LLAssetType::EType type, LLGetAssetCallback callback, -// void (*callback)(LLVFS *vfs, const LLUUID&, LLAssetType::EType, void *, S32, LLExtStat), void *user_data, BOOL duplicate, BOOL is_priority) = 0; private: void _init(LLMessageSystem *msg, LLXferManager *xfer, - LLVFS *vfs, - LLVFS *static_vfs, const LLHost &upstream_host); protected: @@ -408,7 +398,7 @@ protected: MR_FILE_NONEXIST = 3, // Old format store call - source file does not exist MR_NO_FILENAME = 4, // Old format store call - source filename is NULL/0-length MR_NO_UPSTREAM = 5, // Upstream provider is missing - MR_VFS_CORRUPTION = 6 // VFS is corrupt - too-large or mismatched stated/returned sizes + MR_CACHE_CORRUPTION = 6 // cache is corrupt - too-large or mismatched stated/returned sizes }; static class LLMetrics *metric_recipient; diff --git a/indra/llmessage/llcorehttputil.cpp b/indra/llmessage/llcorehttputil.cpp index 0eae6d9826..7031f1aa8c 100644 --- a/indra/llmessage/llcorehttputil.cpp +++ b/indra/llmessage/llcorehttputil.cpp @@ -37,7 +37,7 @@ #include "llsdserialize.h" #include "reader.h" // JSON #include "writer.h" // JSON -#include "llvfile.h" +#include "llfilesystem.h" #include "message.h" // for getting the port @@ -784,7 +784,7 @@ LLSD HttpCoroutineAdapter::postFileAndSuspend(LLCore::HttpRequest::ptr_t request // scoping for our streams so that they go away when we no longer need them. { LLCore::BufferArrayStream outs(fileData.get()); - LLVFile vfile(gVFS, assetId, assetType, LLVFile::READ); + LLFileSystem vfile(assetId, assetType, LLFileSystem::READ); S32 fileSize = vfile.getSize(); U8* fileBuffer; diff --git a/indra/llmessage/llextendedstatus.h b/indra/llmessage/llextendedstatus.h index 9923d73c1a..2a53dced80 100644 --- a/indra/llmessage/llextendedstatus.h +++ b/indra/llmessage/llextendedstatus.h @@ -1,7 +1,7 @@ /** * @file llextendedstatus.h * @date August 2007 - * @brief extended status codes for curl/vfs/resident asset storage and delivery + * @brief extended status codes for curl/resident asset storage and delivery * * $LicenseInfo:firstyear=2007&license=viewerlgpl$ * Second Life Viewer Source Code @@ -32,9 +32,9 @@ enum class LLExtStat: uint32_t { // Status provider groups - Top bits indicate which status type it is // Zero is common status code (next section) - CURL_RESULT = 1UL<<30, // serviced by curl - use 1L if we really implement the below - RES_RESULT = 2UL<<30, // serviced by resident copy - VFS_RESULT = 3UL<<30, // serviced by vfs + CURL_RESULT = 1UL<<30, // serviced by curl - use 1L if we really implement the below + RES_RESULT = 2UL<<30, // serviced by resident copy + CACHE_RESULT = 3UL<<30, // serviced by cache // Common Status Codes @@ -54,9 +54,9 @@ enum class LLExtStat: uint32_t // Memory-Resident status codes: // None at present - // VFS status codes: - VFS_CACHED = VFS_RESULT | 0x0001, - VFS_CORRUPT = VFS_RESULT | 0x0002, + // CACHE status codes: + CACHE_CACHED = CACHE_RESULT | 0x0001, + CACHE_CORRUPT = CACHE_RESULT | 0x0002, }; diff --git a/indra/llmessage/lltransfersourceasset.cpp b/indra/llmessage/lltransfersourceasset.cpp index 80ed3340c6..027283232d 100644 --- a/indra/llmessage/lltransfersourceasset.cpp +++ b/indra/llmessage/lltransfersourceasset.cpp @@ -32,7 +32,7 @@ #include "message.h" #include "lldatapacker.h" #include "lldir.h" -#include "llvfile.h" +#include "llfilesystem.h" LLTransferSourceAsset::LLTransferSourceAsset(const LLUUID &request_id, const F32 priority) : LLTransferSource(LLTST_ASSET, request_id, priority), @@ -99,7 +99,7 @@ LLTSCode LLTransferSourceAsset::dataCallback(const S32 packet_id, return LLTS_SKIP; } - LLVFile vf(gAssetStorage->mVFS, mParams.getAssetID(), mParams.getAssetType(), LLVFile::READ); + LLFileSystem vf(mParams.getAssetID(), mParams.getAssetType(), LLFileSystem::READ); if (!vf.getSize()) { @@ -171,7 +171,7 @@ BOOL LLTransferSourceAsset::unpackParams(LLDataPacker &dp) } -void LLTransferSourceAsset::responderCallback(LLVFS *vfs, const LLUUID& uuid, LLAssetType::EType type, +void LLTransferSourceAsset::responderCallback(const LLUUID& uuid, LLAssetType::EType type, void *user_data, S32 result, LLExtStat ext_status ) { LLUUID *tidp = ((LLUUID*) user_data); @@ -198,7 +198,7 @@ void LLTransferSourceAsset::responderCallback(LLVFS *vfs, const LLUUID& uuid, LL if (LL_ERR_NOERR == result) { // Everything's OK. - LLVFile vf(gAssetStorage->mVFS, uuid, type, LLVFile::READ); + LLFileSystem vf(uuid, type, LLFileSystem::READ); tsap->mSize = vf.getSize(); status = LLTS_OK; } diff --git a/indra/llmessage/lltransfersourceasset.h b/indra/llmessage/lltransfersourceasset.h index 3abda83cf8..585e683cb3 100644 --- a/indra/llmessage/lltransfersourceasset.h +++ b/indra/llmessage/lltransfersourceasset.h @@ -30,7 +30,7 @@ #include "lltransfermanager.h" #include "llassetstorage.h" -class LLVFile; +class LLFileSystem; class LLTransferSourceParamsAsset : public LLTransferSourceParams { @@ -56,7 +56,7 @@ public: LLTransferSourceAsset(const LLUUID &request_id, const F32 priority); virtual ~LLTransferSourceAsset(); - static void responderCallback(LLVFS *vfs, const LLUUID& uuid, LLAssetType::EType type, + static void responderCallback(const LLUUID& uuid, LLAssetType::EType type, void *user_data, S32 result, LLExtStat ext_status ); protected: /*virtual*/ void initTransfer(); diff --git a/indra/llmessage/lltransfertargetvfile.cpp b/indra/llmessage/lltransfertargetvfile.cpp index b27f0881e0..f6faadf87f 100644 --- a/indra/llmessage/lltransfertargetvfile.cpp +++ b/indra/llmessage/lltransfertargetvfile.cpp @@ -30,7 +30,7 @@ #include "lldatapacker.h" #include "llerror.h" -#include "llvfile.h" +#include "llfilesystem.h" //static void LLTransferTargetVFile::updateQueue(bool shutdown) @@ -138,10 +138,9 @@ LLTSCode LLTransferTargetVFile::dataCallback(const S32 packet_id, U8 *in_datap, //LL_INFOS() << "LLTransferTargetFile::dataCallback" << LL_ENDL; //LL_INFOS() << "Packet: " << packet_id << LL_ENDL; - LLVFile vf(gAssetStorage->mVFS, mTempID, mParams.getAssetType(), LLVFile::APPEND); + LLFileSystem vf(mTempID, mParams.getAssetType(), LLFileSystem::APPEND); if (mNeedsCreate) { - vf.setMaxSize(mSize); mNeedsCreate = FALSE; } @@ -176,7 +175,7 @@ void LLTransferTargetVFile::completionCallback(const LLTSCode status) case LLTS_DONE: if (!mNeedsCreate) { - LLVFile file(gAssetStorage->mVFS, mTempID, mParams.getAssetType(), LLVFile::WRITE); + LLFileSystem file(mTempID, mParams.getAssetType(), LLFileSystem::WRITE); if (!file.rename(mParams.getAssetID(), mParams.getAssetType())) { LL_ERRS() << "LLTransferTargetVFile: rename failed" << LL_ENDL; @@ -195,7 +194,7 @@ void LLTransferTargetVFile::completionCallback(const LLTSCode status) { // We're aborting this transfer, we don't want to keep this file. LL_WARNS() << "Aborting vfile transfer for " << mParams.getAssetID() << LL_ENDL; - LLVFile vf(gAssetStorage->mVFS, mTempID, mParams.getAssetType(), LLVFile::APPEND); + LLFileSystem vf(mTempID, mParams.getAssetType(), LLFileSystem::APPEND); vf.remove(); } break; diff --git a/indra/llmessage/lltransfertargetvfile.h b/indra/llmessage/lltransfertargetvfile.h index c819c1e2f2..39a9125f1b 100644 --- a/indra/llmessage/lltransfertargetvfile.h +++ b/indra/llmessage/lltransfertargetvfile.h @@ -29,9 +29,9 @@ #include "lltransfermanager.h" #include "llassetstorage.h" -#include "llvfile.h" +#include "llfilesystem.h" -class LLVFile; +class LLFileSystem; // Lame, an S32 for now until I figure out the deal with how we want to do // error codes. diff --git a/indra/llmessage/llxfer_vfile.cpp b/indra/llmessage/llxfer_vfile.cpp index ddc24342f6..12419b342d 100644 --- a/indra/llmessage/llxfer_vfile.cpp +++ b/indra/llmessage/llxfer_vfile.cpp @@ -30,8 +30,7 @@ #include "lluuid.h" #include "llerror.h" #include "llmath.h" -#include "llvfile.h" -#include "llvfs.h" +#include "llfilesystem.h" #include "lldir.h" // size of chunks read from/written to disk @@ -42,13 +41,13 @@ const U32 LL_MAX_XFER_FILE_BUFFER = 65536; LLXfer_VFile::LLXfer_VFile () : LLXfer(-1) { - init(NULL, LLUUID::null, LLAssetType::AT_NONE); + init(LLUUID::null, LLAssetType::AT_NONE); } -LLXfer_VFile::LLXfer_VFile (LLVFS *vfs, const LLUUID &local_id, LLAssetType::EType type) +LLXfer_VFile::LLXfer_VFile (const LLUUID &local_id, LLAssetType::EType type) : LLXfer(-1) { - init(vfs, local_id, type); + init(local_id, type); } /////////////////////////////////////////////////////////// @@ -60,10 +59,8 @@ LLXfer_VFile::~LLXfer_VFile () /////////////////////////////////////////////////////////// -void LLXfer_VFile::init (LLVFS *vfs, const LLUUID &local_id, LLAssetType::EType type) +void LLXfer_VFile::init (const LLUUID &local_id, LLAssetType::EType type) { - - mVFS = vfs; mLocalID = local_id; mType = type; @@ -82,14 +79,14 @@ void LLXfer_VFile::cleanup () if (mTempID.notNull() && mDeleteTempFile) { - if (mVFS->getExists(mTempID, mType)) + if (LLFileSystem::getExists(mTempID, mType)) { - LLVFile file(mVFS, mTempID, mType, LLVFile::WRITE); + LLFileSystem file(mTempID, mType, LLFileSystem::WRITE); file.remove(); } else { - LL_WARNS("Xfer") << "LLXfer_VFile::cleanup() can't open to delete VFS file " << mTempID << "." << LLAssetType::lookup(mType) + LL_WARNS("Xfer") << "LLXfer_VFile::cleanup() can't open to delete cache file " << mTempID << "." << LLAssetType::lookup(mType) << ", mRemoteID is " << mRemoteID << LL_ENDL; } } @@ -103,7 +100,6 @@ void LLXfer_VFile::cleanup () /////////////////////////////////////////////////////////// S32 LLXfer_VFile::initializeRequest(U64 xfer_id, - LLVFS* vfs, const LLUUID& local_id, const LLUUID& remote_id, LLAssetType::EType type, @@ -115,7 +111,6 @@ S32 LLXfer_VFile::initializeRequest(U64 xfer_id, mRemoteHost = remote_host; - mVFS = vfs; mLocalID = local_id; mRemoteID = remote_id; mType = type; @@ -192,13 +187,13 @@ S32 LLXfer_VFile::startSend (U64 xfer_id, const LLHost &remote_host) delete mVFile; mVFile = NULL; - if(mVFS->getExists(mLocalID, mType)) + if(LLFileSystem::getExists(mLocalID, mType)) { - mVFile = new LLVFile(mVFS, mLocalID, mType, LLVFile::READ); + mVFile = new LLFileSystem(mLocalID, mType, LLFileSystem::READ); if (mVFile->getSize() <= 0) { - LL_WARNS("Xfer") << "LLXfer_VFile::startSend() VFS file " << mLocalID << "." << LLAssetType::lookup(mType) + LL_WARNS("Xfer") << "LLXfer_VFile::startSend() cache file " << mLocalID << "." << LLAssetType::lookup(mType) << " has unexpected file size of " << mVFile->getSize() << LL_ENDL; delete mVFile; mVFile = NULL; @@ -214,7 +209,7 @@ S32 LLXfer_VFile::startSend (U64 xfer_id, const LLHost &remote_host) } else { - LL_WARNS("Xfer") << "LLXfer_VFile::startSend() can't read VFS file " << mLocalID << "." << LLAssetType::lookup(mType) << LL_ENDL; + LL_WARNS("Xfer") << "LLXfer_VFile::startSend() can't read cache file " << mLocalID << "." << LLAssetType::lookup(mType) << LL_ENDL; retval = LL_ERR_FILE_NOT_FOUND; } @@ -240,13 +235,13 @@ S32 LLXfer_VFile::reopenFileHandle() if (mVFile == NULL) { - if (mVFS->getExists(mLocalID, mType)) + if (LLFileSystem::getExists(mLocalID, mType)) { - mVFile = new LLVFile(mVFS, mLocalID, mType, LLVFile::READ); + mVFile = new LLFileSystem(mLocalID, mType, LLFileSystem::READ); } else { - LL_WARNS("Xfer") << "LLXfer_VFile::reopenFileHandle() can't read VFS file " << mLocalID << "." << LLAssetType::lookup(mType) << LL_ENDL; + LL_WARNS("Xfer") << "LLXfer_VFile::reopenFileHandle() can't read cache file " << mLocalID << "." << LLAssetType::lookup(mType) << LL_ENDL; retval = LL_ERR_FILE_NOT_FOUND; } } @@ -265,8 +260,7 @@ void LLXfer_VFile::setXferSize (S32 xfer_size) // It would be nice if LLXFers could tell which end of the pipe they were if (! mVFile) { - LLVFile file(mVFS, mTempID, mType, LLVFile::APPEND); - file.setMaxSize(xfer_size); + LLFileSystem file(mTempID, mType, LLFileSystem::APPEND); } } @@ -320,7 +314,7 @@ S32 LLXfer_VFile::flush() S32 retval = 0; if (mBufferLength) { - LLVFile file(mVFS, mTempID, mType, LLVFile::APPEND); + LLFileSystem file(mTempID, mType, LLFileSystem::APPEND); file.write((U8*)mBuffer, mBufferLength); @@ -340,22 +334,15 @@ S32 LLXfer_VFile::processEOF() if (!mCallbackResult) { - if (mVFS->getExists(mTempID, mType)) + if (LLFileSystem::getExists(mTempID, mType)) { - LLVFile file(mVFS, mTempID, mType, LLVFile::WRITE); + LLFileSystem file(mTempID, mType, LLFileSystem::WRITE); if (!file.rename(mLocalID, mType)) { - LL_WARNS("Xfer") << "VFS rename of temp file failed: unable to rename " << mTempID << " to " << mLocalID << LL_ENDL; + LL_WARNS("Xfer") << "Cache rename of temp file failed: unable to rename " << mTempID << " to " << mLocalID << LL_ENDL; } else - { - #ifdef VFS_SPAM - // Debugging spam - LL_INFOS("Xfer") << "VFS rename of temp file done: renamed " << mTempID << " to " << mLocalID - << " LLVFile size is " << file.getSize() - << LL_ENDL; - #endif - + { // Rename worked: the original file is gone. Clear mDeleteTempFile // so we don't attempt to delete the file in cleanup() mDeleteTempFile = FALSE; @@ -363,7 +350,7 @@ S32 LLXfer_VFile::processEOF() } else { - LL_WARNS("Xfer") << "LLXfer_VFile::processEOF() can't open for renaming VFS file " << mTempID << "." << LLAssetType::lookup(mType) << LL_ENDL; + LL_WARNS("Xfer") << "LLXfer_VFile::processEOF() can't open for renaming cache file " << mTempID << "." << LLAssetType::lookup(mType) << LL_ENDL; } } diff --git a/indra/llmessage/llxfer_vfile.h b/indra/llmessage/llxfer_vfile.h index 5bf9a5cfba..d82bab5f6c 100644 --- a/indra/llmessage/llxfer_vfile.h +++ b/indra/llmessage/llxfer_vfile.h @@ -30,8 +30,7 @@ #include "llxfer.h" #include "llassetstorage.h" -class LLVFS; -class LLVFile; +class LLFileSystem; class LLXfer_VFile : public LLXfer { @@ -41,9 +40,7 @@ class LLXfer_VFile : public LLXfer LLUUID mTempID; LLAssetType::EType mType; - LLVFile *mVFile; - - LLVFS *mVFS; + LLFileSystem *mVFile; std::string mName; @@ -51,14 +48,13 @@ class LLXfer_VFile : public LLXfer public: LLXfer_VFile (); - LLXfer_VFile (LLVFS *vfs, const LLUUID &local_id, LLAssetType::EType type); + LLXfer_VFile (const LLUUID &local_id, LLAssetType::EType type); virtual ~LLXfer_VFile(); - virtual void init(LLVFS *vfs, const LLUUID &local_id, LLAssetType::EType type); + virtual void init(const LLUUID &local_id, LLAssetType::EType type); virtual void cleanup(); virtual S32 initializeRequest(U64 xfer_id, - LLVFS *vfs, const LLUUID &local_id, const LLUUID &remote_id, const LLAssetType::EType type, diff --git a/indra/llmessage/llxfermanager.cpp b/indra/llmessage/llxfermanager.cpp index 4cea886c8a..f9b59d7e42 100644 --- a/indra/llmessage/llxfermanager.cpp +++ b/indra/llmessage/llxfermanager.cpp @@ -56,9 +56,9 @@ const S32 LL_DEFAULT_MAX_HARD_LIMIT_SIMULTANEOUS_XFERS = 500; /////////////////////////////////////////////////////////// -LLXferManager::LLXferManager (LLVFS *vfs) +LLXferManager::LLXferManager () { - init(vfs); + init(); } /////////////////////////////////////////////////////////// @@ -70,7 +70,7 @@ LLXferManager::~LLXferManager () /////////////////////////////////////////////////////////// -void LLXferManager::init (LLVFS *vfs) +void LLXferManager::init() { cleanup(); @@ -78,8 +78,6 @@ void LLXferManager::init (LLVFS *vfs) setHardLimitOutgoingXfersPerCircuit(LL_DEFAULT_MAX_HARD_LIMIT_SIMULTANEOUS_XFERS); setMaxIncomingXfers(LL_DEFAULT_MAX_REQUEST_FIFO_XFERS); - mVFS = vfs; - // Turn on or off ack throttling mUseAckThrottling = FALSE; setAckThrottleBPS(100000); @@ -462,7 +460,7 @@ U64 LLXferManager::requestFile(const std::string& local_filename, void LLXferManager::requestVFile(const LLUUID& local_id, const LLUUID& remote_id, - LLAssetType::EType type, LLVFS* vfs, + LLAssetType::EType type, const LLHost& remote_host, void (*callback)(void**,S32,LLExtStat), void** user_data, @@ -508,7 +506,6 @@ void LLXferManager::requestVFile(const LLUUID& local_id, addToList(xfer_p, mReceiveList, is_priority); ((LLXfer_VFile *)xfer_p)->initializeRequest(getNextID(), - vfs, local_id, remote_id, type, @@ -784,33 +781,17 @@ void LLXferManager::processFileRequest (LLMessageSystem *mesgsys, void ** /*user LLXfer *xferp; if (uuid != LLUUID::null) - { // Request for an asset - use a VFS file + { // Request for an asset - use a cache file if(NULL == LLAssetType::lookup(type)) { LL_WARNS("Xfer") << "Invalid type for xfer request: " << uuid << ":" << type_s16 << " to " << mesgsys->getSender() << LL_ENDL; return; } - - if (! mVFS) - { - LL_WARNS("Xfer") << "Attempt to send VFile w/o available VFS" << LL_ENDL; - return; - } - - /* Present in fireengine, not used by viewer - if (!validateVFileForTransfer(uuid.asString())) - { - // it is up to the app sending the file to mark it for expected - // transfer before the request arrives or it will be dropped - LL_WARNS("Xfer") << "SECURITY: Unapproved VFile '" << uuid << "'" << LL_ENDL; - return; - } - */ LL_INFOS("Xfer") << "starting vfile transfer: " << uuid << "," << LLAssetType::lookup(type) << " to " << mesgsys->getSender() << LL_ENDL; - xferp = (LLXfer *)new LLXfer_VFile(mVFS, uuid, type); + xferp = (LLXfer *)new LLXfer_VFile(uuid, type); if (xferp) { mSendList.push_front(xferp); @@ -1273,9 +1254,9 @@ void LLXferManager::addToList(LLXfer* xferp, xfer_list_t & xfer_list, BOOL is_pr LLXferManager *gXferManager = NULL; -void start_xfer_manager(LLVFS *vfs) +void start_xfer_manager() { - gXferManager = new LLXferManager(vfs); + gXferManager = new LLXferManager(); } void cleanup_xfer_manager() diff --git a/indra/llmessage/llxfermanager.h b/indra/llmessage/llxfermanager.h index 45ae2ffdd3..f49209bed0 100644 --- a/indra/llmessage/llxfermanager.h +++ b/indra/llmessage/llxfermanager.h @@ -35,7 +35,6 @@ //Forward declaration to avoid circular dependencies class LLXfer; -class LLVFS; #include "llxfer.h" #include "message.h" @@ -72,9 +71,6 @@ public: class LLXferManager { - private: - LLVFS *mVFS; - protected: S32 mMaxOutgoingXfersPerCircuit; S32 mHardLimitOutgoingXfersPerCircuit; // At this limit, kill off the connection @@ -111,10 +107,10 @@ class LLXferManager std::multiset mExpectedVFileRequests; // files that are authorized to be downloaded on top of public: - LLXferManager(LLVFS *vfs); + LLXferManager(); virtual ~LLXferManager(); - virtual void init(LLVFS *vfs); + virtual void init(); virtual void cleanup(); void setUseAckThrottling(const BOOL use); @@ -166,7 +162,7 @@ class LLXferManager // vfile requesting // .. to vfile virtual void requestVFile(const LLUUID &local_id, const LLUUID& remote_id, - LLAssetType::EType type, LLVFS* vfs, + LLAssetType::EType type, const LLHost& remote_host, void (*callback)(void**,S32,LLExtStat), void** user_data, BOOL is_priority = FALSE); @@ -213,7 +209,7 @@ class LLXferManager extern LLXferManager* gXferManager; // initialization and garbage collection -void start_xfer_manager(LLVFS *vfs); +void start_xfer_manager(); void cleanup_xfer_manager(); // message system callbacks diff --git a/indra/llrender/CMakeLists.txt b/indra/llrender/CMakeLists.txt index 47e7ad915b..baab09a104 100644 --- a/indra/llrender/CMakeLists.txt +++ b/indra/llrender/CMakeLists.txt @@ -9,10 +9,9 @@ include(LLCommon) include(LLImage) include(LLMath) include(LLRender) -include(LLVFS) include(LLWindow) include(LLXML) -include(LLVFS) +include(LLFileSystem) include_directories( ${FREETYPE_INCLUDE_DIRS} @@ -20,10 +19,9 @@ include_directories( ${LLIMAGE_INCLUDE_DIRS} ${LLMATH_INCLUDE_DIRS} ${LLRENDER_INCLUDE_DIRS} - ${LLVFS_INCLUDE_DIRS} + ${LLFILESYSTEM_INCLUDE_DIRS} ${LLWINDOW_INCLUDE_DIRS} ${LLXML_INCLUDE_DIRS} - ${LLVFS_INCLUDE_DIRS} ) include_directories(SYSTEM ${LLCOMMON_SYSTEM_INCLUDE_DIRS} @@ -104,9 +102,8 @@ if (BUILD_HEADLESS) ${LLIMAGE_LIBRARIES} ${LLMATH_LIBRARIES} ${LLRENDER_HEADLESS_LIBRARIES} - ${LLVFS_LIBRARIES} ${LLXML_LIBRARIES} - ${LLVFS_LIBRARIES} + ${LLFILESYSTEM_LIBRARIES} ${LLWINDOW_HEADLESS_LIBRARIES} ${OPENGL_HEADLESS_LIBRARIES}) @@ -126,9 +123,8 @@ target_link_libraries(llrender ${LLCOMMON_LIBRARIES} ${LLIMAGE_LIBRARIES} ${LLMATH_LIBRARIES} - ${LLVFS_LIBRARIES} + ${LLFILESYSTEM_LIBRARIES} ${LLXML_LIBRARIES} - ${LLVFS_LIBRARIES} ${LLWINDOW_LIBRARIES} ${FREETYPE_LIBRARIES} ${OPENGL_LIBRARIES}) diff --git a/indra/llui/CMakeLists.txt b/indra/llui/CMakeLists.txt index cce618487b..7401e6130a 100644 --- a/indra/llui/CMakeLists.txt +++ b/indra/llui/CMakeLists.txt @@ -13,7 +13,7 @@ include(LLCoreHttp) include(LLRender) include(LLWindow) include(LLCoreHttp) -include(LLVFS) +include(LLFileSystem) include(LLXML) include_directories( @@ -25,7 +25,7 @@ include_directories( ${LLMESSAGE_INCLUDE_DIRS} ${LLRENDER_INCLUDE_DIRS} ${LLWINDOW_INCLUDE_DIRS} - ${LLVFS_INCLUDE_DIRS} + ${LLFILESYSTEM_INCLUDE_DIRS} ${LLXML_INCLUDE_DIRS} ${LIBS_PREBUILD_DIR}/include/hunspell ) @@ -283,7 +283,7 @@ target_link_libraries(llui ${LLINVENTORY_LIBRARIES} ${LLMESSAGE_LIBRARIES} ${LLCOREHTTP_LIBRARIES} - ${LLVFS_LIBRARIES} # ugh, just for LLDir + ${LLFILESYSTEM_LIBRARIES} ${LLXUIXML_LIBRARIES} ${LLXML_LIBRARIES} ${LLMATH_LIBRARIES} diff --git a/indra/llui/llviewereventrecorder.h b/indra/llui/llviewereventrecorder.h index d1059d55de..94e66f5dc4 100644 --- a/indra/llui/llviewereventrecorder.h +++ b/indra/llui/llviewereventrecorder.h @@ -32,7 +32,6 @@ #include "lldir.h" #include "llsd.h" #include "llfile.h" -#include "llvfile.h" #include "lldate.h" #include "llsdserialize.h" #include "llkeyboard.h" diff --git a/indra/llvfs/llpidlock.cpp b/indra/llvfs/llpidlock.cpp deleted file mode 100644 index f770e93d45..0000000000 --- a/indra/llvfs/llpidlock.cpp +++ /dev/null @@ -1,276 +0,0 @@ -/** - * @file llformat.cpp - * @date January 2007 - * @brief string formatting utility - * - * $LicenseInfo:firstyear=2007&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 "llapr.h" // thread-related functions -#include "llpidlock.h" -#include "lldir.h" -#include "llsd.h" -#include "llsdserialize.h" -#include "llnametable.h" -#include "llframetimer.h" - -#if LL_WINDOWS //For windows platform. - -#include - -bool isProcessAlive(U32 pid) -{ - return (bool) GetProcessVersion((DWORD)pid); -} - -#else //Everyone Else -bool isProcessAlive(U32 pid) -{ - return (bool) kill( (pid_t)pid, 0); -} -#endif //Everyone else. - - - -class LLPidLockFile -{ - public: - LLPidLockFile( ) : - mAutosave(false), - mSaving(false), - mWaiting(false), - mPID(getpid()), - mNameTable(NULL), - mClean(true) - { - mLockName = gDirUtilp->getTempDir() + gDirUtilp->getDirDelimiter() + "savelock"; - } - bool requestLock(LLNameTable *name_table, bool autosave, - bool force_immediate=FALSE, F32 timeout=300.0); - bool checkLock(); - void releaseLock(); - - private: - void writeLockFile(LLSD pids); - public: - static LLPidLockFile& instance(); // return the singleton black list file - - bool mAutosave; - bool mSaving; - bool mWaiting; - LLFrameTimer mTimer; - U32 mPID; - std::string mLockName; - std::string mSaveName; - LLSD mPIDS_sd; - LLNameTable *mNameTable; - bool mClean; -}; - -LLPidLockFile& LLPidLockFile::instance() -{ - static LLPidLockFile the_file; - return the_file; -} - -void LLPidLockFile::writeLockFile(LLSD pids) -{ - llofstream ofile(mLockName.c_str()); - - if (!LLSDSerialize::toXML(pids,ofile)) - { - LL_WARNS() << "Unable to write concurrent save lock file." << LL_ENDL; - } - ofile.close(); -} - -bool LLPidLockFile::requestLock(LLNameTable *name_table, bool autosave, - bool force_immediate, F32 timeout) -{ - bool readyToSave = FALSE; - - if (mSaving) return FALSE; //Bail out if we're currently saving. Will not queue another save. - - if (!mWaiting){ - mNameTable=name_table; - mAutosave = autosave; - } - - LLSD out_pids; - out_pids.append( (LLSD::Integer)mPID ); - - llifstream ifile(mLockName.c_str()); - - if (ifile.is_open()) - { //If file exists, we need to decide whether or not to continue. - if ( force_immediate - || mTimer.hasExpired() ) //Only deserialize if we REALLY need to. - { - - LLSD in_pids; - - LLSDSerialize::fromXML(in_pids, ifile); - - //Clean up any dead PIDS that might be in there. - for (LLSD::array_iterator i=in_pids.beginArray(); - i !=in_pids.endArray(); - ++i) - { - U32 stored_pid=(*i).asInteger(); - - if (isProcessAlive(stored_pid)) - { - out_pids.append( (*i) ); - } - } - - readyToSave=TRUE; - } - ifile.close(); - } - else - { - readyToSave=TRUE; - } - - if (!mWaiting) //Not presently waiting to save. Queue up. - { - mTimer.resetWithExpiry(timeout); - mWaiting=TRUE; - } - - if (readyToSave) - { //Potential race condition won't kill us. Ignore it. - writeLockFile(out_pids); - mSaving=TRUE; - } - - return readyToSave; -} - -bool LLPidLockFile::checkLock() -{ - return mWaiting; -} - -void LLPidLockFile::releaseLock() -{ - llifstream ifile(mLockName.c_str()); - LLSD in_pids; - LLSD out_pids; - bool write_file=FALSE; - - LLSDSerialize::fromXML(in_pids, ifile); - - //Clean up this PID and any dead ones. - for (LLSD::array_iterator i=in_pids.beginArray(); - i !=in_pids.endArray(); - ++i) - { - U32 stored_pid=(*i).asInteger(); - - if (stored_pid != mPID && isProcessAlive(stored_pid)) - { - out_pids.append( (*i) ); - write_file=TRUE; - } - } - ifile.close(); - - if (write_file) - { - writeLockFile(out_pids); - } - else - { - unlink(mLockName.c_str()); - } - - mSaving=FALSE; - mWaiting=FALSE; -} - -//LLPidLock - -void LLPidLock::initClass() { - (void) LLPidLockFile::instance(); -} - -bool LLPidLock::checkLock() -{ - return LLPidLockFile::instance().checkLock(); -} - -bool LLPidLock::requestLock(LLNameTable *name_table, bool autosave, - bool force_immediate, F32 timeout) -{ - return LLPidLockFile::instance().requestLock(name_table,autosave,force_immediate,timeout); -} - -void LLPidLock::releaseLock() -{ - return LLPidLockFile::instance().releaseLock(); -} - -bool LLPidLock::isClean() -{ - return LLPidLockFile::instance().mClean; -} - -//getters -LLNameTable * LLPidLock::getNameTable() -{ - return LLPidLockFile::instance().mNameTable; -} - -bool LLPidLock::getAutosave() -{ - return LLPidLockFile::instance().mAutosave; -} - -bool LLPidLock::getClean() -{ - return LLPidLockFile::instance().mClean; -} - -std::string LLPidLock::getSaveName() -{ - return LLPidLockFile::instance().mSaveName; -} - -//setters -void LLPidLock::setClean(bool clean) -{ - LLPidLockFile::instance().mClean=clean; -} - -void LLPidLock::setSaveName(std::string savename) -{ - LLPidLockFile::instance().mSaveName=savename; -} - -S32 LLPidLock::getPID() -{ - return (S32)getpid(); -} diff --git a/indra/llvfs/llpidlock.h b/indra/llvfs/llpidlock.h deleted file mode 100644 index 334f26bb29..0000000000 --- a/indra/llvfs/llpidlock.h +++ /dev/null @@ -1,60 +0,0 @@ -/** - * @file llpidlock.h - * @brief System information debugging classes. - * - * $LicenseInfo:firstyear=2001&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#ifndef LL_PIDLOCK_H -#define LL_PIDLOCK_H -#include "llnametable.h" - -class LLSD; -class LLFrameTimer; - -#if !LL_WINDOWS //For non-windows platforms. -#include -#endif - -namespace LLPidLock -{ - void initClass(); // { (void) LLPidLockFile::instance(); } - - bool requestLock( LLNameTable *name_table=NULL, bool autosave=TRUE, - bool force_immediate=FALSE, F32 timeout=300.0); - bool checkLock(); - void releaseLock(); - bool isClean(); - - //getters - LLNameTable * getNameTable(); - bool getAutosave(); - bool getClean(); - std::string getSaveName(); - S32 getPID(); - - //setters - void setClean(bool clean); - void setSaveName(std::string savename); -}; - -#endif // LL_PIDLOCK_H diff --git a/indra/llvfs/llvfile.cpp b/indra/llvfs/llvfile.cpp deleted file mode 100644 index b8588e99f4..0000000000 --- a/indra/llvfs/llvfile.cpp +++ /dev/null @@ -1,437 +0,0 @@ -/** - * @file llvfile.cpp - * @brief Implementation of virtual file - * - * $LicenseInfo:firstyear=2002&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#include "linden_common.h" - -#include "llvfile.h" - -#include "llerror.h" -#include "llthread.h" -#include "lltimer.h" -#include "llfasttimer.h" -#include "llmemory.h" -#include "llvfs.h" - -const S32 LLVFile::READ = 0x00000001; -const S32 LLVFile::WRITE = 0x00000002; -const S32 LLVFile::READ_WRITE = 0x00000003; // LLVFile::READ & LLVFile::WRITE -const S32 LLVFile::APPEND = 0x00000006; // 0x00000004 & LLVFile::WRITE - -static LLTrace::BlockTimerStatHandle FTM_VFILE_WAIT("VFile Wait"); - -//---------------------------------------------------------------------------- -LLVFSThread* LLVFile::sVFSThread = NULL; -BOOL LLVFile::sAllocdVFSThread = FALSE; -//---------------------------------------------------------------------------- - -//============================================================================ - -LLVFile::LLVFile(LLVFS *vfs, const LLUUID &file_id, const LLAssetType::EType file_type, S32 mode) -{ - mFileType = file_type; - - mFileID = file_id; - mPosition = 0; - mMode = mode; - mVFS = vfs; - - mBytesRead = 0; - mHandle = LLVFSThread::nullHandle(); - mPriority = 128.f; - - mVFS->incLock(mFileID, mFileType, VFSLOCK_OPEN); -} - -LLVFile::~LLVFile() -{ - if (!isReadComplete()) - { - if (mHandle != LLVFSThread::nullHandle()) - { - if (!(mMode & LLVFile::WRITE)) - { - //LL_WARNS() << "Destroying LLVFile with pending async read/write, aborting..." << LL_ENDL; - sVFSThread->setFlags(mHandle, LLVFSThread::FLAG_AUTO_COMPLETE | LLVFSThread::FLAG_ABORT); - } - else // WRITE - { - sVFSThread->setFlags(mHandle, LLVFSThread::FLAG_AUTO_COMPLETE); - } - } - } - mVFS->decLock(mFileID, mFileType, VFSLOCK_OPEN); -} - -BOOL LLVFile::read(U8 *buffer, S32 bytes, BOOL async, F32 priority) -{ - if (! (mMode & READ)) - { - LL_WARNS() << "Attempt to read from file " << mFileID << " opened with mode " << std::hex << mMode << std::dec << LL_ENDL; - return FALSE; - } - - if (mHandle != LLVFSThread::nullHandle()) - { - LL_WARNS() << "Attempt to read from vfile object " << mFileID << " with pending async operation" << LL_ENDL; - return FALSE; - } - mPriority = priority; - - BOOL success = TRUE; - - // We can't do a read while there are pending async writes - waitForLock(VFSLOCK_APPEND); - - // *FIX: (?) - if (async) - { - mHandle = sVFSThread->read(mVFS, mFileID, mFileType, buffer, mPosition, bytes, threadPri()); - } - else - { - // We can't do a read while there are pending async writes on this file - mBytesRead = sVFSThread->readImmediate(mVFS, mFileID, mFileType, buffer, mPosition, bytes); - mPosition += mBytesRead; - if (! mBytesRead) - { - success = FALSE; - } - } - - return success; -} - -//static -U8* LLVFile::readFile(LLVFS *vfs, const LLUUID &uuid, LLAssetType::EType type, S32* bytes_read) -{ - U8 *data; - LLVFile file(vfs, uuid, type, LLVFile::READ); - S32 file_size = file.getSize(); - if (file_size == 0) - { - // File is empty. - data = NULL; - } - else - { - data = (U8*) ll_aligned_malloc<16>(file_size); - file.read(data, file_size); /* Flawfinder: ignore */ - - if (file.getLastBytesRead() != (S32)file_size) - { - ll_aligned_free<16>(data); - data = NULL; - file_size = 0; - } - } - if (bytes_read) - { - *bytes_read = file_size; - } - return data; -} - -void LLVFile::setReadPriority(const F32 priority) -{ - mPriority = priority; - if (mHandle != LLVFSThread::nullHandle()) - { - sVFSThread->setPriority(mHandle, threadPri()); - } -} - -BOOL LLVFile::isReadComplete() -{ - BOOL res = TRUE; - if (mHandle != LLVFSThread::nullHandle()) - { - LLVFSThread::Request* req = (LLVFSThread::Request*)sVFSThread->getRequest(mHandle); - LLVFSThread::status_t status = req->getStatus(); - if (status == LLVFSThread::STATUS_COMPLETE) - { - mBytesRead = req->getBytesRead(); - mPosition += mBytesRead; - sVFSThread->completeRequest(mHandle); - mHandle = LLVFSThread::nullHandle(); - } - else - { - res = FALSE; - } - } - return res; -} - -S32 LLVFile::getLastBytesRead() -{ - return mBytesRead; -} - -BOOL LLVFile::eof() -{ - return mPosition >= getSize(); -} - -BOOL LLVFile::write(const U8 *buffer, S32 bytes) -{ - if (! (mMode & WRITE)) - { - LL_WARNS() << "Attempt to write to file " << mFileID << " opened with mode " << std::hex << mMode << std::dec << LL_ENDL; - } - if (mHandle != LLVFSThread::nullHandle()) - { - LL_ERRS() << "Attempt to write to vfile object " << mFileID << " with pending async operation" << LL_ENDL; - return FALSE; - } - BOOL success = TRUE; - - // *FIX: allow async writes? potential problem wit mPosition... - if (mMode == APPEND) // all appends are async (but WRITEs are not) - { - U8* writebuf = new U8[bytes]; - memcpy(writebuf, buffer, bytes); - S32 offset = -1; - mHandle = sVFSThread->write(mVFS, mFileID, mFileType, - writebuf, offset, bytes, - LLVFSThread::FLAG_AUTO_COMPLETE | LLVFSThread::FLAG_AUTO_DELETE); - mHandle = LLVFSThread::nullHandle(); // FLAG_AUTO_COMPLETE means we don't track this - } - else - { - // We can't do a write while there are pending reads or writes on this file - waitForLock(VFSLOCK_READ); - waitForLock(VFSLOCK_APPEND); - - S32 pos = (mMode & APPEND) == APPEND ? -1 : mPosition; - - S32 wrote = sVFSThread->writeImmediate(mVFS, mFileID, mFileType, (U8*)buffer, pos, bytes); - - mPosition += wrote; - - if (wrote < bytes) - { - LL_WARNS() << "Tried to write " << bytes << " bytes, actually wrote " << wrote << LL_ENDL; - - success = FALSE; - } - } - return success; -} - -//static -BOOL LLVFile::writeFile(const U8 *buffer, S32 bytes, LLVFS *vfs, const LLUUID &uuid, LLAssetType::EType type) -{ - LLVFile file(vfs, uuid, type, LLVFile::WRITE); - file.setMaxSize(bytes); - return file.write(buffer, bytes); -} - -BOOL LLVFile::seek(S32 offset, S32 origin) -{ - if (mMode == APPEND) - { - LL_WARNS() << "Attempt to seek on append-only file" << LL_ENDL; - return FALSE; - } - - if (-1 == origin) - { - origin = mPosition; - } - - S32 new_pos = origin + offset; - - S32 size = getSize(); // Calls waitForLock(VFSLOCK_APPEND) - - if (new_pos > size) - { - LL_WARNS() << "Attempt to seek past end of file" << LL_ENDL; - - mPosition = size; - return FALSE; - } - else if (new_pos < 0) - { - LL_WARNS() << "Attempt to seek past beginning of file" << LL_ENDL; - - mPosition = 0; - return FALSE; - } - - mPosition = new_pos; - return TRUE; -} - -S32 LLVFile::tell() const -{ - return mPosition; -} - -S32 LLVFile::getSize() -{ - waitForLock(VFSLOCK_APPEND); - S32 size = mVFS->getSize(mFileID, mFileType); - - return size; -} - -S32 LLVFile::getMaxSize() -{ - S32 size = mVFS->getMaxSize(mFileID, mFileType); - - return size; -} - -BOOL LLVFile::setMaxSize(S32 size) -{ - if (! (mMode & WRITE)) - { - LL_WARNS() << "Attempt to change size of file " << mFileID << " opened with mode " << std::hex << mMode << std::dec << LL_ENDL; - - return FALSE; - } - - if (!mVFS->checkAvailable(size)) - { - //LL_RECORD_BLOCK_TIME(FTM_VFILE_WAIT); - S32 count = 0; - while (sVFSThread->getPending() > 1000) - { - if (count % 100 == 0) - { - LL_INFOS() << "VFS catching up... Pending: " << sVFSThread->getPending() << LL_ENDL; - } - if (sVFSThread->isPaused()) - { - sVFSThread->update(0); - } - ms_sleep(10); - } - } - return mVFS->setMaxSize(mFileID, mFileType, size); -} - -BOOL LLVFile::rename(const LLUUID &new_id, const LLAssetType::EType new_type) -{ - if (! (mMode & WRITE)) - { - LL_WARNS() << "Attempt to rename file " << mFileID << " opened with mode " << std::hex << mMode << std::dec << LL_ENDL; - - return FALSE; - } - - if (mHandle != LLVFSThread::nullHandle()) - { - LL_WARNS() << "Renaming file with pending async read" << LL_ENDL; - } - - waitForLock(VFSLOCK_READ); - waitForLock(VFSLOCK_APPEND); - - // we need to release / replace our own lock - // since the renamed file will inherit locks from the new name - mVFS->decLock(mFileID, mFileType, VFSLOCK_OPEN); - mVFS->renameFile(mFileID, mFileType, new_id, new_type); - mVFS->incLock(new_id, new_type, VFSLOCK_OPEN); - - mFileID = new_id; - mFileType = new_type; - - return TRUE; -} - -BOOL LLVFile::remove() -{ -// LL_INFOS() << "Removing file " << mFileID << LL_ENDL; - - if (! (mMode & WRITE)) - { - // Leaving paranoia warning just because this should be a very infrequent - // operation. - LL_WARNS() << "Remove file " << mFileID << " opened with mode " << std::hex << mMode << std::dec << LL_ENDL; - } - - if (mHandle != LLVFSThread::nullHandle()) - { - LL_WARNS() << "Removing file with pending async read" << LL_ENDL; - } - - // why not seek back to the beginning of the file too? - mPosition = 0; - - waitForLock(VFSLOCK_READ); - waitForLock(VFSLOCK_APPEND); - mVFS->removeFile(mFileID, mFileType); - - return TRUE; -} - -// static -void LLVFile::initClass(LLVFSThread* vfsthread) -{ - if (!vfsthread) - { - if (LLVFSThread::sLocal != NULL) - { - vfsthread = LLVFSThread::sLocal; - } - else - { - vfsthread = new LLVFSThread(); - sAllocdVFSThread = TRUE; - } - } - sVFSThread = vfsthread; -} - -// static -void LLVFile::cleanupClass() -{ - if (sAllocdVFSThread) - { - delete sVFSThread; - } - sVFSThread = NULL; -} - -bool LLVFile::isLocked(EVFSLock lock) -{ - return mVFS->isLocked(mFileID, mFileType, lock) ? true : false; -} - -void LLVFile::waitForLock(EVFSLock lock) -{ - //LL_RECORD_BLOCK_TIME(FTM_VFILE_WAIT); - // spin until the lock clears - while (isLocked(lock)) - { - if (sVFSThread->isPaused()) - { - sVFSThread->update(0); - } - ms_sleep(1); - } -} diff --git a/indra/llvfs/llvfile.h b/indra/llvfs/llvfile.h deleted file mode 100644 index 7e9d9f73e5..0000000000 --- a/indra/llvfs/llvfile.h +++ /dev/null @@ -1,90 +0,0 @@ -/** - * @file llvfile.h - * @brief Definition of virtual file - * - * $LicenseInfo:firstyear=2002&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#ifndef LL_LLVFILE_H -#define LL_LLVFILE_H - -#include "lluuid.h" -#include "llassettype.h" -#include "llvfs.h" -#include "llvfsthread.h" - -class LLVFile -{ -public: - LLVFile(LLVFS *vfs, const LLUUID &file_id, const LLAssetType::EType file_type, S32 mode = LLVFile::READ); - ~LLVFile(); - - BOOL read(U8 *buffer, S32 bytes, BOOL async = FALSE, F32 priority = 128.f); /* Flawfinder: ignore */ - static U8* readFile(LLVFS *vfs, const LLUUID &uuid, LLAssetType::EType type, S32* bytes_read = 0); - void setReadPriority(const F32 priority); - BOOL isReadComplete(); - S32 getLastBytesRead(); - BOOL eof(); - - BOOL write(const U8 *buffer, S32 bytes); - static BOOL writeFile(const U8 *buffer, S32 bytes, LLVFS *vfs, const LLUUID &uuid, LLAssetType::EType type); - BOOL seek(S32 offset, S32 origin = -1); - S32 tell() const; - - S32 getSize(); - S32 getMaxSize(); - BOOL setMaxSize(S32 size); - BOOL rename(const LLUUID &new_id, const LLAssetType::EType new_type); - BOOL remove(); - - bool isLocked(EVFSLock lock); - void waitForLock(EVFSLock lock); - - static void initClass(LLVFSThread* vfsthread = NULL); - static void cleanupClass(); - static LLVFSThread* getVFSThread() { return sVFSThread; } - -protected: - static LLVFSThread* sVFSThread; - static BOOL sAllocdVFSThread; - U32 threadPri() { return LLVFSThread::PRIORITY_NORMAL + llmin((U32)mPriority,(U32)0xfff); } - -public: - static const S32 READ; - static const S32 WRITE; - static const S32 READ_WRITE; - static const S32 APPEND; - -protected: - LLAssetType::EType mFileType; - - LLUUID mFileID; - S32 mPosition; - S32 mMode; - LLVFS *mVFS; - F32 mPriority; - - S32 mBytesRead; - LLVFSThread::handle_t mHandle; -}; - -#endif diff --git a/indra/llvfs/llvfs.cpp b/indra/llvfs/llvfs.cpp deleted file mode 100644 index 617056d94d..0000000000 --- a/indra/llvfs/llvfs.cpp +++ /dev/null @@ -1,2220 +0,0 @@ -/** - * @file llvfs.cpp - * @brief Implementation of virtual file system - * - * $LicenseInfo:firstyear=2002&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#include "linden_common.h" - -#include "llvfs.h" - -#include -#include -#include -#if LL_WINDOWS -#include -#elif LL_SOLARIS -#include -#include -#include -#else -#include -#endif - -#include "llstl.h" -#include "lltimer.h" - -const S32 FILE_BLOCK_MASK = 0x000003FF; // 1024-byte blocks -const S32 VFS_CLEANUP_SIZE = 5242880; // how much space we free up in a single stroke -const S32 BLOCK_LENGTH_INVALID = -1; // mLength for invalid LLVFSFileBlocks - -LLVFS *gVFS = NULL; - -// internal class definitions -class LLVFSBlock -{ -public: - LLVFSBlock() - { - mLocation = 0; - mLength = 0; - } - - LLVFSBlock(U32 loc, S32 size) - { - mLocation = loc; - mLength = size; - } - - static bool locationSortPredicate( - const LLVFSBlock* lhs, - const LLVFSBlock* rhs) - { - return lhs->mLocation < rhs->mLocation; - } - -public: - U32 mLocation; - S32 mLength; // allocated block size -}; - -LLVFSFileSpecifier::LLVFSFileSpecifier() -: mFileID(), - mFileType( LLAssetType::AT_NONE ) -{ -} - -LLVFSFileSpecifier::LLVFSFileSpecifier(const LLUUID &file_id, const LLAssetType::EType file_type) -{ - mFileID = file_id; - mFileType = file_type; -} - -bool LLVFSFileSpecifier::operator<(const LLVFSFileSpecifier &rhs) const -{ - return (mFileID == rhs.mFileID) - ? mFileType < rhs.mFileType - : mFileID < rhs.mFileID; -} - -bool LLVFSFileSpecifier::operator==(const LLVFSFileSpecifier &rhs) const -{ - return (mFileID == rhs.mFileID && - mFileType == rhs.mFileType); -} - - -class LLVFSFileBlock : public LLVFSBlock, public LLVFSFileSpecifier -{ -public: - LLVFSFileBlock() : LLVFSBlock(), LLVFSFileSpecifier() - { - init(); - } - - LLVFSFileBlock(const LLUUID &file_id, LLAssetType::EType file_type, U32 loc = 0, S32 size = 0) - : LLVFSBlock(loc, size), LLVFSFileSpecifier( file_id, file_type ) - { - init(); - } - - void init() - { - mSize = 0; - mIndexLocation = -1; - mAccessTime = (U32)time(NULL); - - for (S32 i = 0; i < (S32)VFSLOCK_COUNT; i++) - { - mLocks[(EVFSLock)i] = 0; - } - } - - #ifdef LL_LITTLE_ENDIAN - inline void swizzleCopy(void *dst, void *src, int size) { memcpy(dst, src, size); /* Flawfinder: ignore */} - - #else - - inline U32 swizzle32(U32 x) - { - return(((x >> 24) & 0x000000FF) | ((x >> 8) & 0x0000FF00) | ((x << 8) & 0x00FF0000) |((x << 24) & 0xFF000000)); - } - - inline U16 swizzle16(U16 x) - { - return( ((x >> 8) & 0x000000FF) | ((x << 8) & 0x0000FF00) ); - } - - inline void swizzleCopy(void *dst, void *src, int size) - { - if(size == 4) - { - ((U32*)dst)[0] = swizzle32(((U32*)src)[0]); - } - else if(size == 2) - { - ((U16*)dst)[0] = swizzle16(((U16*)src)[0]); - } - else - { - // Perhaps this should assert... - memcpy(dst, src, size); /* Flawfinder: ignore */ - } - } - - #endif - - void serialize(U8 *buffer) - { - swizzleCopy(buffer, &mLocation, 4); - buffer += 4; - swizzleCopy(buffer, &mLength, 4); - buffer +=4; - swizzleCopy(buffer, &mAccessTime, 4); - buffer +=4; - memcpy(buffer, &mFileID.mData, 16); /* Flawfinder: ignore */ - buffer += 16; - S16 temp_type = mFileType; - swizzleCopy(buffer, &temp_type, 2); - buffer += 2; - swizzleCopy(buffer, &mSize, 4); - } - - void deserialize(U8 *buffer, const S32 index_loc) - { - mIndexLocation = index_loc; - - swizzleCopy(&mLocation, buffer, 4); - buffer += 4; - swizzleCopy(&mLength, buffer, 4); - buffer += 4; - swizzleCopy(&mAccessTime, buffer, 4); - buffer += 4; - memcpy(&mFileID.mData, buffer, 16); - buffer += 16; - S16 temp_type; - swizzleCopy(&temp_type, buffer, 2); - mFileType = (LLAssetType::EType)temp_type; - buffer += 2; - swizzleCopy(&mSize, buffer, 4); - } - - static BOOL insertLRU(LLVFSFileBlock* const& first, - LLVFSFileBlock* const& second) - { - return (first->mAccessTime == second->mAccessTime) - ? *first < *second - : first->mAccessTime < second->mAccessTime; - } - -public: - S32 mSize; - S32 mIndexLocation; // location of index entry - U32 mAccessTime; - BOOL mLocks[VFSLOCK_COUNT]; // number of outstanding locks of each type - - static const S32 SERIAL_SIZE; -}; - -// Helper structure for doing lru w/ stl... is there a simpler way? -struct LLVFSFileBlock_less -{ - bool operator()(LLVFSFileBlock* const& lhs, LLVFSFileBlock* const& rhs) const - { - return (LLVFSFileBlock::insertLRU(lhs, rhs)) ? true : false; - } -}; - - -const S32 LLVFSFileBlock::SERIAL_SIZE = 34; - - -LLVFS::LLVFS(const std::string& index_filename, const std::string& data_filename, const BOOL read_only, const U32 presize, const BOOL remove_after_crash) -: mRemoveAfterCrash(remove_after_crash), - mDataFP(NULL), - mIndexFP(NULL) -{ - mDataMutex = new LLMutex(); - - S32 i; - for (i = 0; i < VFSLOCK_COUNT; i++) - { - mLockCounts[i] = 0; - } - mValid = VFSVALID_OK; - mReadOnly = read_only; - mIndexFilename = index_filename; - mDataFilename = data_filename; - - const char *file_mode = mReadOnly ? "rb" : "r+b"; - - LL_INFOS("VFS") << "Attempting to open VFS index file " << mIndexFilename << LL_ENDL; - LL_INFOS("VFS") << "Attempting to open VFS data file " << mDataFilename << LL_ENDL; - - mDataFP = openAndLock(mDataFilename, file_mode, mReadOnly); - if (!mDataFP) - { - if (mReadOnly) - { - LL_WARNS("VFS") << "Can't find " << mDataFilename << " to open read-only VFS" << LL_ENDL; - mValid = VFSVALID_BAD_CANNOT_OPEN_READONLY; - return; - } - - mDataFP = openAndLock(mDataFilename, "w+b", FALSE); - if (mDataFP) - { - // Since we're creating this data file, assume any index file is bogus - // remove the index, since this vfs is now blank - LLFile::remove(mIndexFilename); - } - else - { - LL_WARNS("VFS") << "Couldn't open vfs data file " - << mDataFilename << LL_ENDL; - mValid = VFSVALID_BAD_CANNOT_CREATE; - return; - } - - if (presize) - { - presizeDataFile(presize); - } - } - - // Did we leave this file open for writing last time? - // If so, close it and start over. - if (!mReadOnly && mRemoveAfterCrash) - { - llstat marker_info; - std::string marker = mDataFilename + ".open"; - if (!LLFile::stat(marker, &marker_info)) - { - // marker exists, kill the lock and the VFS files - unlockAndClose(mDataFP); - mDataFP = NULL; - - LL_WARNS("VFS") << "VFS: File left open on last run, removing old VFS file " << mDataFilename << LL_ENDL; - LLFile::remove(mIndexFilename); - LLFile::remove(mDataFilename); - LLFile::remove(marker); - - mDataFP = openAndLock(mDataFilename, "w+b", FALSE); - if (!mDataFP) - { - LL_WARNS("VFS") << "Can't open VFS data file in crash recovery" << LL_ENDL; - mValid = VFSVALID_BAD_CANNOT_CREATE; - return; - } - - if (presize) - { - presizeDataFile(presize); - } - } - } - - // determine the real file size - fseek(mDataFP, 0, SEEK_END); - U32 data_size = ftell(mDataFP); - - // read the index file - // make sure there's at least one file in it too - // if not, we'll treat this as a new vfs - llstat fbuf; - if (! LLFile::stat(mIndexFilename, &fbuf) && - fbuf.st_size >= LLVFSFileBlock::SERIAL_SIZE && - (mIndexFP = openAndLock(mIndexFilename, file_mode, mReadOnly)) // Yes, this is an assignment and not '==' - ) - { - std::vector buffer(fbuf.st_size); - size_t buf_offset = 0; - size_t nread = fread(&buffer[0], 1, fbuf.st_size, mIndexFP); - - std::vector files_by_loc; - - while (buf_offset < nread) - { - LLVFSFileBlock *block = new LLVFSFileBlock(); - - block->deserialize(&buffer[buf_offset], (S32)buf_offset); - - // Do sanity check on this block. - // Note that this skips zero size blocks, which helps VFS - // to heal after some errors. JC - if (block->mLength > 0 && - (U32)block->mLength <= data_size && - block->mLocation < data_size && - block->mSize > 0 && - block->mSize <= block->mLength && - block->mFileType >= LLAssetType::AT_NONE && - block->mFileType < LLAssetType::AT_COUNT) - { - mFileBlocks.insert(fileblock_map::value_type(*block, block)); - files_by_loc.push_back(block); - } - else - if (block->mLength && block->mSize > 0) - { - // this is corrupt, not empty - LL_WARNS("VFS") << "VFS corruption: " << block->mFileID << " (" << block->mFileType << ") at index " << block->mIndexLocation << " DS: " << data_size << LL_ENDL; - LL_WARNS("VFS") << "Length: " << block->mLength << "\tLocation: " << block->mLocation << "\tSize: " << block->mSize << LL_ENDL; - LL_WARNS("VFS") << "File has bad data - VFS removed" << LL_ENDL; - - delete block; - - unlockAndClose( mIndexFP ); - mIndexFP = NULL; - LLFile::remove( mIndexFilename ); - - unlockAndClose( mDataFP ); - mDataFP = NULL; - LLFile::remove( mDataFilename ); - - LL_WARNS("VFS") << "Deleted corrupt VFS files " - << mDataFilename - << " and " - << mIndexFilename - << LL_ENDL; - - mValid = VFSVALID_BAD_CORRUPT; - return; - } - else - { - // this is a null or bad entry, skip it - mIndexHoles.push_back(buf_offset); - - delete block; - } - - buf_offset += LLVFSFileBlock::SERIAL_SIZE; - } - - std::sort( - files_by_loc.begin(), - files_by_loc.end(), - LLVFSFileBlock::locationSortPredicate); - - // There are 3 cases that have to be considered. - // 1. No blocks - // 2. One block. - // 3. Two or more blocks. - if (!files_by_loc.empty()) - { - // cur walks through the list. - std::vector::iterator cur = files_by_loc.begin(); - std::vector::iterator end = files_by_loc.end(); - LLVFSFileBlock* last_file_block = *cur; - - // Check to see if there is an empty space before the first file. - if (last_file_block->mLocation > 0) - { - // If so, create a free block. - addFreeBlock(new LLVFSBlock(0, last_file_block->mLocation)); - } - - // Walk through the 2nd+ block. If there is a free space - // between cur_file_block and last_file_block, add it to - // the free space collection. This block will not need to - // run in the case there is only one entry in the VFS. - ++cur; - while( cur != end ) - { - LLVFSFileBlock* cur_file_block = *cur; - - // Dupe check on the block - if (cur_file_block->mLocation == last_file_block->mLocation - && cur_file_block->mLength == last_file_block->mLength) - { - LL_WARNS("VFS") << "VFS: removing duplicate entry" - << " at " << cur_file_block->mLocation - << " length " << cur_file_block->mLength - << " size " << cur_file_block->mSize - << " ID " << cur_file_block->mFileID - << " type " << cur_file_block->mFileType - << LL_ENDL; - - // Duplicate entries. Nuke them both for safety. - mFileBlocks.erase(*cur_file_block); // remove ID/type entry - if (cur_file_block->mLength > 0) - { - // convert to hole - addFreeBlock( - new LLVFSBlock( - cur_file_block->mLocation, - cur_file_block->mLength)); - } - lockData(); // needed for sync() - sync(cur_file_block, TRUE); // remove first on disk - sync(last_file_block, TRUE); // remove last on disk - unlockData(); // needed for sync() - last_file_block = cur_file_block; - ++cur; - continue; - } - - // Figure out where the last block ended. - S32 loc = last_file_block->mLocation+last_file_block->mLength; - - // Figure out how much space there is between where - // the last block ended and this block begins. - S32 length = cur_file_block->mLocation - loc; - - // Check for more errors... Seeing if the current - // entry and the last entry make sense together. - if (length < 0 || loc < 0 || (U32)loc > data_size) - { - // Invalid VFS - unlockAndClose( mIndexFP ); - mIndexFP = NULL; - LLFile::remove( mIndexFilename ); - - unlockAndClose( mDataFP ); - mDataFP = NULL; - LLFile::remove( mDataFilename ); - - LL_WARNS("VFS") << "VFS: overlapping entries" - << " at " << cur_file_block->mLocation - << " length " << cur_file_block->mLength - << " ID " << cur_file_block->mFileID - << " type " << cur_file_block->mFileType - << LL_ENDL; - - LL_WARNS("VFS") << "Deleted corrupt VFS files " - << mDataFilename - << " and " - << mIndexFilename - << LL_ENDL; - - mValid = VFSVALID_BAD_CORRUPT; - return; - } - - // we don't want to add empty blocks to the list... - if (length > 0) - { - addFreeBlock(new LLVFSBlock(loc, length)); - } - last_file_block = cur_file_block; - ++cur; - } - - // also note any empty space at the end - U32 loc = last_file_block->mLocation + last_file_block->mLength; - if (loc < data_size) - { - addFreeBlock(new LLVFSBlock(loc, data_size - loc)); - } - } - else // There where no blocks in the file. - { - addFreeBlock(new LLVFSBlock(0, data_size)); - } - } - else // Pre-existing index file wasn't opened - { - if (mReadOnly) - { - LL_WARNS("VFS") << "Can't find " << mIndexFilename << " to open read-only VFS" << LL_ENDL; - mValid = VFSVALID_BAD_CANNOT_OPEN_READONLY; - return; - } - - - mIndexFP = openAndLock(mIndexFilename, "w+b", FALSE); - if (!mIndexFP) - { - LL_WARNS("VFS") << "Couldn't open an index file for the VFS, probably a sharing violation!" << LL_ENDL; - - unlockAndClose( mDataFP ); - mDataFP = NULL; - LLFile::remove( mDataFilename ); - - mValid = VFSVALID_BAD_CANNOT_CREATE; - return; - } - - // no index file, start from scratch w/ 1GB allocation - LLVFSBlock *first_block = new LLVFSBlock(0, data_size ? data_size : 0x40000000); - addFreeBlock(first_block); - } - - // Open marker file to look for bad shutdowns - if (!mReadOnly && mRemoveAfterCrash) - { - std::string marker = mDataFilename + ".open"; - LLFILE* marker_fp = LLFile::fopen(marker, "w"); /* Flawfinder: ignore */ - if (marker_fp) - { - fclose(marker_fp); - marker_fp = NULL; - } - } - - LL_INFOS("VFS") << "Using VFS index file " << mIndexFilename << LL_ENDL; - LL_INFOS("VFS") << "Using VFS data file " << mDataFilename << LL_ENDL; - - mValid = VFSVALID_OK; -} - -LLVFS::~LLVFS() -{ - if (mDataMutex->isLocked()) - { - LL_ERRS("VFS") << "LLVFS destroyed with mutex locked" << LL_ENDL; - } - - unlockAndClose(mIndexFP); - mIndexFP = NULL; - - fileblock_map::const_iterator it; - for (it = mFileBlocks.begin(); it != mFileBlocks.end(); ++it) - { - delete (*it).second; - } - mFileBlocks.clear(); - - mFreeBlocksByLength.clear(); - - for_each(mFreeBlocksByLocation.begin(), mFreeBlocksByLocation.end(), DeletePairedPointer()); - mFreeBlocksByLocation.clear(); - - unlockAndClose(mDataFP); - mDataFP = NULL; - - // Remove marker file - if (!mReadOnly && mRemoveAfterCrash) - { - std::string marker = mDataFilename + ".open"; - LLFile::remove(marker); - } - - delete mDataMutex; -} - - -// Use this function normally to create LLVFS files. -// Will append digits to the end of the filename with multiple re-trys -// static -LLVFS * LLVFS::createLLVFS(const std::string& index_filename, - const std::string& data_filename, - const BOOL read_only, - const U32 presize, - const BOOL remove_after_crash) -{ - LLVFS * new_vfs = new LLVFS(index_filename, data_filename, read_only, presize, remove_after_crash); - - if( !new_vfs->isValid() ) - { // First name failed, retry with new names - std::string retry_vfs_index_name; - std::string retry_vfs_data_name; - S32 count = 0; - while (!new_vfs->isValid() && - count < 256) - { // Append '.' to end of filenames - retry_vfs_index_name = index_filename + llformat(".%u",count); - retry_vfs_data_name = data_filename + llformat(".%u", count); - - delete new_vfs; // Delete bad VFS and try again - new_vfs = new LLVFS(retry_vfs_index_name, retry_vfs_data_name, read_only, presize, remove_after_crash); - - count++; - } - } - - if( !new_vfs->isValid() ) - { - delete new_vfs; // Delete bad VFS - new_vfs = NULL; // Total failure - } - - return new_vfs; -} - - - -void LLVFS::presizeDataFile(const U32 size) -{ - if (!mDataFP) - { - LL_ERRS() << "LLVFS::presizeDataFile() with no data file open" << LL_ENDL; - return; - } - - // we're creating this file for the first time, size it - fseek(mDataFP, size-1, SEEK_SET); - S32 tmp = 0; - tmp = (S32)fwrite(&tmp, 1, 1, mDataFP); - // fflush(mDataFP); - - // also remove any index, since this vfs is now blank - LLFile::remove(mIndexFilename); - - if (tmp) - { - LL_INFOS() << "Pre-sized VFS data file to " << ftell(mDataFP) << " bytes" << LL_ENDL; - } - else - { - LL_WARNS() << "Failed to pre-size VFS data file" << LL_ENDL; - } -} - -BOOL LLVFS::getExists(const LLUUID &file_id, const LLAssetType::EType file_type) -{ - LLVFSFileBlock *block = NULL; - - if (!isValid()) - { - LL_ERRS() << "Attempting to use invalid VFS!" << LL_ENDL; - } - - lockData(); - - LLVFSFileSpecifier spec(file_id, file_type); - fileblock_map::iterator it = mFileBlocks.find(spec); - if (it != mFileBlocks.end()) - { - block = (*it).second; - block->mAccessTime = (U32)time(NULL); - } - - BOOL res = (block && block->mLength > 0) ? TRUE : FALSE; - - unlockData(); - - return res; -} - -S32 LLVFS::getSize(const LLUUID &file_id, const LLAssetType::EType file_type) -{ - S32 size = 0; - - if (!isValid()) - { - LL_ERRS() << "Attempting to use invalid VFS!" << LL_ENDL; - - } - - lockData(); - - LLVFSFileSpecifier spec(file_id, file_type); - fileblock_map::iterator it = mFileBlocks.find(spec); - if (it != mFileBlocks.end()) - { - LLVFSFileBlock *block = (*it).second; - - block->mAccessTime = (U32)time(NULL); - size = block->mSize; - } - - unlockData(); - - return size; -} - -S32 LLVFS::getMaxSize(const LLUUID &file_id, const LLAssetType::EType file_type) -{ - S32 size = 0; - - if (!isValid()) - { - LL_ERRS() << "Attempting to use invalid VFS!" << LL_ENDL; - } - - lockData(); - - LLVFSFileSpecifier spec(file_id, file_type); - fileblock_map::iterator it = mFileBlocks.find(spec); - if (it != mFileBlocks.end()) - { - LLVFSFileBlock *block = (*it).second; - - block->mAccessTime = (U32)time(NULL); - size = block->mLength; - } - - unlockData(); - - return size; -} - -BOOL LLVFS::checkAvailable(S32 max_size) -{ - lockData(); - - blocks_length_map_t::iterator iter = mFreeBlocksByLength.lower_bound(max_size); // first entry >= size - const BOOL res(iter == mFreeBlocksByLength.end() ? FALSE : TRUE); - - unlockData(); - - return res; -} - -BOOL LLVFS::setMaxSize(const LLUUID &file_id, const LLAssetType::EType file_type, S32 max_size) -{ - if (!isValid()) - { - LL_ERRS() << "Attempting to use invalid VFS!" << LL_ENDL; - } - if (mReadOnly) - { - LL_ERRS() << "Attempt to write to read-only VFS" << LL_ENDL; - } - if (max_size <= 0) - { - LL_WARNS() << "VFS: Attempt to assign size " << max_size << " to vfile " << file_id << LL_ENDL; - return FALSE; - } - - lockData(); - - LLVFSFileSpecifier spec(file_id, file_type); - LLVFSFileBlock *block = NULL; - fileblock_map::iterator it = mFileBlocks.find(spec); - if (it != mFileBlocks.end()) - { - block = (*it).second; - } - - // round all sizes upward to KB increments - // SJB: Need to not round for the new texture-pipeline code so we know the correct - // max file size. Need to investigate the potential problems with this... - if (file_type != LLAssetType::AT_TEXTURE) - { - if (max_size & FILE_BLOCK_MASK) - { - max_size += FILE_BLOCK_MASK; - max_size &= ~FILE_BLOCK_MASK; - } - } - - if (block && block->mLength > 0) - { - block->mAccessTime = (U32)time(NULL); - - if (max_size == block->mLength) - { - unlockData(); - return TRUE; - } - else if (max_size < block->mLength) - { - // this file is shrinking - LLVFSBlock *free_block = new LLVFSBlock(block->mLocation + max_size, block->mLength - max_size); - - addFreeBlock(free_block); - - block->mLength = max_size; - - if (block->mLength < block->mSize) - { - // JC: Was a warning, but Ian says it's bad. - LL_ERRS() << "Truncating virtual file " << file_id << " to " << block->mLength << " bytes" << LL_ENDL; - block->mSize = block->mLength; - } - - sync(block); - //mergeFreeBlocks(); - - unlockData(); - return TRUE; - } - else if (max_size > block->mLength) - { - // this file is growing - // first check for an adjacent free block to grow into - S32 size_increase = max_size - block->mLength; - - // Find the first free block with and addres > block->mLocation - LLVFSBlock *free_block; - blocks_location_map_t::iterator iter = mFreeBlocksByLocation.upper_bound(block->mLocation); - if (iter != mFreeBlocksByLocation.end()) - { - free_block = iter->second; - - if (free_block->mLocation == block->mLocation + block->mLength && - free_block->mLength >= size_increase) - { - // this free block is at the end of the file and is large enough - - // Must call useFreeSpace before sync(), as sync() - // unlocks data structures. - useFreeSpace(free_block, size_increase); - block->mLength += size_increase; - sync(block); - - unlockData(); - return TRUE; - } - } - - // no adjecent free block, find one in the list - free_block = findFreeBlock(max_size, block); - - if (free_block) - { - // Save location where data is going, useFreeSpace will move free_block->mLocation; - U32 new_data_location = free_block->mLocation; - - //mark the free block as used so it does not - //interfere with other operations such as addFreeBlock - useFreeSpace(free_block, max_size); // useFreeSpace takes ownership (and may delete) free_block - - if (block->mLength > 0) - { - // create a new free block where this file used to be - LLVFSBlock *new_free_block = new LLVFSBlock(block->mLocation, block->mLength); - - addFreeBlock(new_free_block); - - if (block->mSize > 0) - { - // move the file into the new block - std::vector buffer(block->mSize); - fseek(mDataFP, block->mLocation, SEEK_SET); - if (fread(&buffer[0], block->mSize, 1, mDataFP) == 1) - { - fseek(mDataFP, new_data_location, SEEK_SET); - if (fwrite(&buffer[0], block->mSize, 1, mDataFP) != 1) - { - LL_WARNS() << "Short write" << LL_ENDL; - } - } else { - LL_WARNS() << "Short read" << LL_ENDL; - } - } - } - - block->mLocation = new_data_location; - - block->mLength = max_size; - - - sync(block); - - unlockData(); - return TRUE; - } - else - { - LL_WARNS() << "VFS: No space (" << max_size << ") to resize existing vfile " << file_id << LL_ENDL; - //dumpMap(); - unlockData(); - dumpStatistics(); - return FALSE; - } - } - } - else - { - // find a free block in the list - LLVFSBlock *free_block = findFreeBlock(max_size); - - if (free_block) - { - if (block) - { - block->mLocation = free_block->mLocation; - block->mLength = max_size; - } - else - { - // this file doesn't exist, create it - block = new LLVFSFileBlock(file_id, file_type, free_block->mLocation, max_size); - mFileBlocks.insert(fileblock_map::value_type(spec, block)); - } - - // Must call useFreeSpace before sync(), as sync() - // unlocks data structures. - useFreeSpace(free_block, max_size); - block->mAccessTime = (U32)time(NULL); - - sync(block); - } - else - { - LL_WARNS() << "VFS: No space (" << max_size << ") for new virtual file " << file_id << LL_ENDL; - //dumpMap(); - unlockData(); - dumpStatistics(); - return FALSE; - } - } - unlockData(); - return TRUE; -} - - -// WARNING: HERE BE DRAGONS! -// rename is the weirdest VFS op, because the file moves but the locks don't! -void LLVFS::renameFile(const LLUUID &file_id, const LLAssetType::EType file_type, - const LLUUID &new_id, const LLAssetType::EType &new_type) -{ - if (!isValid()) - { - LL_ERRS() << "Attempting to use invalid VFS!" << LL_ENDL; - } - if (mReadOnly) - { - LL_ERRS() << "Attempt to write to read-only VFS" << LL_ENDL; - } - - lockData(); - - LLVFSFileSpecifier new_spec(new_id, new_type); - LLVFSFileSpecifier old_spec(file_id, file_type); - - fileblock_map::iterator it = mFileBlocks.find(old_spec); - if (it != mFileBlocks.end()) - { - LLVFSFileBlock *src_block = (*it).second; - - // this will purge the data but leave the file block in place, w/ locks, if any - // WAS: removeFile(new_id, new_type); NOW uses removeFileBlock() to avoid mutex lock recursion - fileblock_map::iterator new_it = mFileBlocks.find(new_spec); - if (new_it != mFileBlocks.end()) - { - LLVFSFileBlock *new_block = (*new_it).second; - removeFileBlock(new_block); - } - - // if there's something in the target location, remove it but inherit its locks - it = mFileBlocks.find(new_spec); - if (it != mFileBlocks.end()) - { - LLVFSFileBlock *dest_block = (*it).second; - - for (S32 i = 0; i < (S32)VFSLOCK_COUNT; i++) - { - if(dest_block->mLocks[i]) - { - LL_ERRS() << "Renaming VFS block to a locked file." << LL_ENDL; - } - dest_block->mLocks[i] = src_block->mLocks[i]; - } - - mFileBlocks.erase(new_spec); - delete dest_block; - } - - src_block->mFileID = new_id; - src_block->mFileType = new_type; - src_block->mAccessTime = (U32)time(NULL); - - mFileBlocks.erase(old_spec); - mFileBlocks.insert(fileblock_map::value_type(new_spec, src_block)); - - sync(src_block); - } - else - { - LL_WARNS() << "VFS: Attempt to rename nonexistent vfile " << file_id << ":" << file_type << LL_ENDL; - } - unlockData(); -} - -// mDataMutex must be LOCKED before calling this -void LLVFS::removeFileBlock(LLVFSFileBlock *fileblock) -{ - // convert this into an unsaved, dummy fileblock to preserve locks - // a more rubust solution would store the locks in a seperate data structure - sync(fileblock, TRUE); - - if (fileblock->mLength > 0) - { - // turn this file into an empty block - LLVFSBlock *free_block = new LLVFSBlock(fileblock->mLocation, fileblock->mLength); - - addFreeBlock(free_block); - } - - fileblock->mLocation = 0; - fileblock->mSize = 0; - fileblock->mLength = BLOCK_LENGTH_INVALID; - fileblock->mIndexLocation = -1; - - //mergeFreeBlocks(); -} - -void LLVFS::removeFile(const LLUUID &file_id, const LLAssetType::EType file_type) -{ - if (!isValid()) - { - LL_ERRS() << "Attempting to use invalid VFS!" << LL_ENDL; - } - if (mReadOnly) - { - LL_ERRS() << "Attempt to write to read-only VFS" << LL_ENDL; - } - - lockData(); - - LLVFSFileSpecifier spec(file_id, file_type); - fileblock_map::iterator it = mFileBlocks.find(spec); - if (it != mFileBlocks.end()) - { - LLVFSFileBlock *block = (*it).second; - removeFileBlock(block); - } - else - { - LL_WARNS() << "VFS: attempting to remove nonexistent file " << file_id << " type " << file_type << LL_ENDL; - } - - unlockData(); -} - - -S32 LLVFS::getData(const LLUUID &file_id, const LLAssetType::EType file_type, U8 *buffer, S32 location, S32 length) -{ - S32 bytesread = 0; - - if (!isValid()) - { - LL_ERRS() << "Attempting to use invalid VFS!" << LL_ENDL; - } - llassert(location >= 0); - llassert(length >= 0); - - BOOL do_read = FALSE; - - lockData(); - - LLVFSFileSpecifier spec(file_id, file_type); - fileblock_map::iterator it = mFileBlocks.find(spec); - if (it != mFileBlocks.end()) - { - LLVFSFileBlock *block = (*it).second; - - block->mAccessTime = (U32)time(NULL); - - if (location > block->mSize) - { - LL_WARNS() << "VFS: Attempt to read location " << location << " in file " << file_id << " of length " << block->mSize << LL_ENDL; - } - else - { - if (length > block->mSize - location) - { - length = block->mSize - location; - } - location += block->mLocation; - do_read = TRUE; - } - } - - if (do_read) - { - fseek(mDataFP, location, SEEK_SET); - bytesread = (S32)fread(buffer, 1, length, mDataFP); - } - - unlockData(); - - return bytesread; -} - -S32 LLVFS::storeData(const LLUUID &file_id, const LLAssetType::EType file_type, const U8 *buffer, S32 location, S32 length) -{ - if (!isValid()) - { - LL_ERRS() << "Attempting to use invalid VFS!" << LL_ENDL; - } - if (mReadOnly) - { - LL_ERRS() << "Attempt to write to read-only VFS" << LL_ENDL; - } - - llassert(length > 0); - - lockData(); - - LLVFSFileSpecifier spec(file_id, file_type); - fileblock_map::iterator it = mFileBlocks.find(spec); - if (it != mFileBlocks.end()) - { - LLVFSFileBlock *block = (*it).second; - - S32 in_loc = location; - if (location == -1) - { - location = block->mSize; - } - llassert(location >= 0); - - block->mAccessTime = (U32)time(NULL); - - if (block->mLength == BLOCK_LENGTH_INVALID) - { - // Block was removed, ignore write - LL_WARNS() << "VFS: Attempt to write to invalid block" - << " in file " << file_id - << " location: " << in_loc - << " bytes: " << length - << LL_ENDL; - unlockData(); - return length; - } - else if (location > block->mLength) - { - LL_WARNS() << "VFS: Attempt to write to location " << location - << " in file " << file_id - << " type " << S32(file_type) - << " of size " << block->mSize - << " block length " << block->mLength - << LL_ENDL; - unlockData(); - return length; - } - else - { - if (length > block->mLength - location ) - { - LL_WARNS() << "VFS: Truncating write to virtual file " << file_id << " type " << S32(file_type) << LL_ENDL; - length = block->mLength - location; - } - U32 file_location = location + block->mLocation; - - fseek(mDataFP, file_location, SEEK_SET); - S32 write_len = (S32)fwrite(buffer, 1, length, mDataFP); - if (write_len != length) - { - LL_WARNS() << llformat("VFS Write Error: %d != %d",write_len,length) << LL_ENDL; - } - // fflush(mDataFP); - - if (location + length > block->mSize) - { - block->mSize = location + write_len; - sync(block); - } - unlockData(); - - return write_len; - } - } - else - { - unlockData(); - return 0; - } -} - -void LLVFS::incLock(const LLUUID &file_id, const LLAssetType::EType file_type, EVFSLock lock) -{ - lockData(); - - LLVFSFileSpecifier spec(file_id, file_type); - LLVFSFileBlock *block; - - fileblock_map::iterator it = mFileBlocks.find(spec); - if (it != mFileBlocks.end()) - { - block = (*it).second; - } - else - { - // Create a dummy block which isn't saved - block = new LLVFSFileBlock(file_id, file_type, 0, BLOCK_LENGTH_INVALID); - block->mAccessTime = (U32)time(NULL); - mFileBlocks.insert(fileblock_map::value_type(spec, block)); - } - - block->mLocks[lock]++; - mLockCounts[lock]++; - - unlockData(); -} - -void LLVFS::decLock(const LLUUID &file_id, const LLAssetType::EType file_type, EVFSLock lock) -{ - lockData(); - - LLVFSFileSpecifier spec(file_id, file_type); - fileblock_map::iterator it = mFileBlocks.find(spec); - if (it != mFileBlocks.end()) - { - LLVFSFileBlock *block = (*it).second; - - if (block->mLocks[lock] > 0) - { - block->mLocks[lock]--; - } - else - { - LL_WARNS() << "VFS: Decrementing zero-value lock " << lock << LL_ENDL; - } - mLockCounts[lock]--; - } - - unlockData(); -} - -BOOL LLVFS::isLocked(const LLUUID &file_id, const LLAssetType::EType file_type, EVFSLock lock) -{ - lockData(); - - BOOL res = FALSE; - - LLVFSFileSpecifier spec(file_id, file_type); - fileblock_map::iterator it = mFileBlocks.find(spec); - if (it != mFileBlocks.end()) - { - LLVFSFileBlock *block = (*it).second; - res = (block->mLocks[lock] > 0); - } - - unlockData(); - - return res; -} - -//============================================================================ -// protected -//============================================================================ - -void LLVFS::eraseBlockLength(LLVFSBlock *block) -{ - // find the corresponding map entry in the length map and erase it - S32 length = block->mLength; - blocks_length_map_t::iterator iter = mFreeBlocksByLength.lower_bound(length); - blocks_length_map_t::iterator end = mFreeBlocksByLength.end(); - bool found_block = false; - while(iter != end) - { - LLVFSBlock *tblock = iter->second; - llassert(tblock->mLength == length); // there had -better- be an entry with our length! - if (tblock == block) - { - mFreeBlocksByLength.erase(iter); - found_block = true; - break; - } - ++iter; - } - if(!found_block) - { - LL_ERRS() << "eraseBlock could not find block" << LL_ENDL; - } -} - - -// Remove block from both free lists (by location and by length). -void LLVFS::eraseBlock(LLVFSBlock *block) -{ - eraseBlockLength(block); - // find the corresponding map entry in the location map and erase it - U32 location = block->mLocation; - llverify(mFreeBlocksByLocation.erase(location) == 1); // we should only have one entry per location. -} - - -// Add the region specified by block location and length to the free lists. -// Also incrementally defragment by merging with previous and next free blocks. -void LLVFS::addFreeBlock(LLVFSBlock *block) -{ -#if LL_DEBUG - size_t dbgcount = mFreeBlocksByLocation.count(block->mLocation); - if(dbgcount > 0) - { - LL_ERRS() << "addFreeBlock called with block already in list" << LL_ENDL; - } -#endif - - // Get a pointer to the next free block (by location). - blocks_location_map_t::iterator next_free_it = mFreeBlocksByLocation.lower_bound(block->mLocation); - - // We can merge with previous if it ends at our requested location. - LLVFSBlock* prev_block = NULL; - bool merge_prev = false; - if (next_free_it != mFreeBlocksByLocation.begin()) - { - blocks_location_map_t::iterator prev_free_it = next_free_it; - --prev_free_it; - prev_block = prev_free_it->second; - merge_prev = (prev_block->mLocation + prev_block->mLength == block->mLocation); - } - - // We can merge with next if our block ends at the next block's location. - LLVFSBlock* next_block = NULL; - bool merge_next = false; - if (next_free_it != mFreeBlocksByLocation.end()) - { - next_block = next_free_it->second; - merge_next = (block->mLocation + block->mLength == next_block->mLocation); - } - - if (merge_prev && merge_next) - { - // LL_INFOS() << "VFS merge BOTH" << LL_ENDL; - // Previous block is changing length (a lot), so only need to update length map. - // Next block is going away completely. JC - eraseBlockLength(prev_block); - eraseBlock(next_block); - prev_block->mLength += block->mLength + next_block->mLength; - mFreeBlocksByLength.insert(blocks_length_map_t::value_type(prev_block->mLength, prev_block)); - delete block; - block = NULL; - delete next_block; - next_block = NULL; - } - else if (merge_prev) - { - // LL_INFOS() << "VFS merge previous" << LL_ENDL; - // Previous block is maintaining location, only changing length, - // therefore only need to update the length map. JC - eraseBlockLength(prev_block); - prev_block->mLength += block->mLength; - mFreeBlocksByLength.insert(blocks_length_map_t::value_type(prev_block->mLength, prev_block)); // multimap insert - delete block; - block = NULL; - } - else if (merge_next) - { - // LL_INFOS() << "VFS merge next" << LL_ENDL; - // Next block is changing both location and length, - // so both free lists must update. JC - eraseBlock(next_block); - next_block->mLocation = block->mLocation; - next_block->mLength += block->mLength; - // Don't hint here, next_free_it iterator may be invalid. - mFreeBlocksByLocation.insert(blocks_location_map_t::value_type(next_block->mLocation, next_block)); // multimap insert - mFreeBlocksByLength.insert(blocks_length_map_t::value_type(next_block->mLength, next_block)); // multimap insert - delete block; - block = NULL; - } - else - { - // Can't merge with other free blocks. - // Hint that insert should go near next_free_it. - mFreeBlocksByLocation.insert(next_free_it, blocks_location_map_t::value_type(block->mLocation, block)); // multimap insert - mFreeBlocksByLength.insert(blocks_length_map_t::value_type(block->mLength, block)); // multimap insert - } -} - -// Superceeded by new addFreeBlock which does incremental free space merging. -// Incremental is faster overall. -//void LLVFS::mergeFreeBlocks() -//{ -// if (!isValid()) -// { -// LL_ERRS() << "Attempting to use invalid VFS!" << LL_ENDL; -// } -// // TODO: could we optimize this with hints from the calling code? -// blocks_location_map_t::iterator iter = mFreeBlocksByLocation.begin(); -// blocks_location_map_t::iterator end = mFreeBlocksByLocation.end(); -// LLVFSBlock *first_block = iter->second; -// while(iter != end) -// { -// blocks_location_map_t::iterator first_iter = iter; // save for if we do a merge -// if (++iter == end) -// break; -// LLVFSBlock *second_block = iter->second; -// if (first_block->mLocation + first_block->mLength == second_block->mLocation) -// { -// // remove the first block from the length map -// eraseBlockLength(first_block); -// // merge first_block with second_block, since they're adjacent -// first_block->mLength += second_block->mLength; -// // add the first block to the length map (with the new size) -// mFreeBlocksByLength.insert(blocks_length_map_t::value_type(first_block->mLength, first_block)); // multimap insert -// -// // erase and delete the second block -// eraseBlock(second_block); -// delete second_block; -// -// // reset iterator -// iter = first_iter; // haven't changed first_block, so corresponding iterator is still valid -// end = mFreeBlocksByLocation.end(); -// } -// first_block = second_block; -// } -//} - -// length bytes from free_block are going to be used (so they are no longer free) -void LLVFS::useFreeSpace(LLVFSBlock *free_block, S32 length) -{ - if (free_block->mLength == length) - { - eraseBlock(free_block); - delete free_block; - } - else - { - eraseBlock(free_block); - - free_block->mLocation += length; - free_block->mLength -= length; - - addFreeBlock(free_block); - } -} - -// NOTE! mDataMutex must be LOCKED before calling this -// sync this index entry out to the index file -// we need to do this constantly to avoid corruption on viewer crash -void LLVFS::sync(LLVFSFileBlock *block, BOOL remove) -{ - if (!isValid()) - { - LL_ERRS() << "Attempting to use invalid VFS!" << LL_ENDL; - } - if (mReadOnly) - { - LL_WARNS() << "Attempt to sync read-only VFS" << LL_ENDL; - return; - } - if (block->mLength == BLOCK_LENGTH_INVALID) - { - // This is a dummy file, don't save - return; - } - if (block->mLength == 0) - { - LL_ERRS() << "VFS syncing zero-length block" << LL_ENDL; - } - - BOOL set_index_to_end = FALSE; - long seek_pos = block->mIndexLocation; - - if (-1 == seek_pos) - { - if (!mIndexHoles.empty()) - { - seek_pos = mIndexHoles.front(); - mIndexHoles.pop_front(); - } - else - { - set_index_to_end = TRUE; - } - } - - if (set_index_to_end) - { - // Need fseek/ftell to update the seek_pos and hence data - // structures, so can't unlockData() before this. - fseek(mIndexFP, 0, SEEK_END); - seek_pos = ftell(mIndexFP); - } - - block->mIndexLocation = seek_pos; - if (remove) - { - mIndexHoles.push_back(seek_pos); - } - - U8 buffer[LLVFSFileBlock::SERIAL_SIZE]; - if (remove) - { - memset(buffer, 0, LLVFSFileBlock::SERIAL_SIZE); - } - else - { - block->serialize(buffer); - } - - // If set_index_to_end, file pointer is already at seek_pos - // and we don't need to do anything. Only seek if not at end. - if (!set_index_to_end) - { - fseek(mIndexFP, seek_pos, SEEK_SET); - } - - if (fwrite(buffer, LLVFSFileBlock::SERIAL_SIZE, 1, mIndexFP) != 1) - { - LL_WARNS() << "Short write" << LL_ENDL; - } - - // *NOTE: Why was this commented out? - // fflush(mIndexFP); - - return; -} - -// mDataMutex must be LOCKED before calling this -// Can initiate LRU-based file removal to make space. -// The immune file block will not be removed. -LLVFSBlock *LLVFS::findFreeBlock(S32 size, LLVFSFileBlock *immune) -{ - if (!isValid()) - { - LL_ERRS() << "Attempting to use invalid VFS!" << LL_ENDL; - } - - LLVFSBlock *block = NULL; - BOOL have_lru_list = FALSE; - - typedef std::set lru_set; - lru_set lru_list; - - LLTimer timer; - - while (! block) - { - // look for a suitable free block - blocks_length_map_t::iterator iter = mFreeBlocksByLength.lower_bound(size); // first entry >= size - if (iter != mFreeBlocksByLength.end()) - block = iter->second; - - // no large enough free blocks, time to clean out some junk - if (! block) - { - // create a list of files sorted by usage time - // this is far faster than sorting a linked list - if (! have_lru_list) - { - for (fileblock_map::iterator it = mFileBlocks.begin(); it != mFileBlocks.end(); ++it) - { - LLVFSFileBlock *tmp = (*it).second; - - if (tmp != immune && - tmp->mLength > 0 && - ! tmp->mLocks[VFSLOCK_READ] && - ! tmp->mLocks[VFSLOCK_APPEND] && - ! tmp->mLocks[VFSLOCK_OPEN]) - { - lru_list.insert(tmp); - } - } - - have_lru_list = TRUE; - } - - if (lru_list.size() == 0) - { - // No more files to delete, and still not enough room! - LL_WARNS() << "VFS: Can't make " << size << " bytes of free space in VFS, giving up" << LL_ENDL; - break; - } - - // is the oldest file big enough? (Should be about half the time) - lru_set::iterator it = lru_list.begin(); - LLVFSFileBlock *file_block = *it; - if (file_block->mLength >= size && file_block != immune) - { - // ditch this file and look again for a free block - should find it - // TODO: it'll be faster just to assign the free block and break - LL_INFOS() << "LRU: Removing " << file_block->mFileID << ":" << file_block->mFileType << LL_ENDL; - lru_list.erase(it); - removeFileBlock(file_block); - file_block = NULL; - continue; - } - - - LL_INFOS() << "VFS: LRU: Aggressive: " << (S32)lru_list.size() << " files remain" << LL_ENDL; - dumpLockCounts(); - - // Now it's time to aggressively make more space - // Delete the oldest 5MB of the vfs or enough to hold the file, which ever is larger - // This may yield too much free space, but we'll use it up soon enough - U32 cleanup_target = (size > VFS_CLEANUP_SIZE) ? size : VFS_CLEANUP_SIZE; - U32 cleaned_up = 0; - for (it = lru_list.begin(); - it != lru_list.end() && cleaned_up < cleanup_target; - ) - { - file_block = *it; - - // TODO: it would be great to be able to batch all these sync() calls - // LL_INFOS() << "LRU2: Removing " << file_block->mFileID << ":" << file_block->mFileType << " last accessed" << file_block->mAccessTime << LL_ENDL; - - cleaned_up += file_block->mLength; - lru_list.erase(it++); - removeFileBlock(file_block); - file_block = NULL; - } - //mergeFreeBlocks(); - } - } - - F32 time = timer.getElapsedTimeF32(); - if (time > 0.5f) - { - LL_WARNS() << "VFS: Spent " << time << " seconds in findFreeBlock!" << LL_ENDL; - } - - return block; -} - -//============================================================================ -// public -//============================================================================ - -void LLVFS::pokeFiles() -{ - if (!isValid()) - { - LL_ERRS() << "Attempting to use invalid VFS!" << LL_ENDL; - } - U32 word; - - // only write data if we actually read 4 bytes - // otherwise we're writing garbage and screwing up the file - fseek(mDataFP, 0, SEEK_SET); - if (fread(&word, sizeof(word), 1, mDataFP) == 1) - { - fseek(mDataFP, 0, SEEK_SET); - if (fwrite(&word, sizeof(word), 1, mDataFP) != 1) - { - LL_WARNS() << "Could not write to data file" << LL_ENDL; - } - fflush(mDataFP); - } - - fseek(mIndexFP, 0, SEEK_SET); - if (fread(&word, sizeof(word), 1, mIndexFP) == 1) - { - fseek(mIndexFP, 0, SEEK_SET); - if (fwrite(&word, sizeof(word), 1, mIndexFP) != 1) - { - LL_WARNS() << "Could not write to index file" << LL_ENDL; - } - fflush(mIndexFP); - } -} - - -void LLVFS::dumpMap() -{ - LL_INFOS() << "Files:" << LL_ENDL; - for (fileblock_map::iterator it = mFileBlocks.begin(); it != mFileBlocks.end(); ++it) - { - LLVFSFileBlock *file_block = (*it).second; - LL_INFOS() << "Location: " << file_block->mLocation << "\tLength: " << file_block->mLength << "\t" << file_block->mFileID << "\t" << file_block->mFileType << LL_ENDL; - } - - LL_INFOS() << "Free Blocks:" << LL_ENDL; - for (blocks_location_map_t::iterator iter = mFreeBlocksByLocation.begin(), - end = mFreeBlocksByLocation.end(); - iter != end; iter++) - { - LLVFSBlock *free_block = iter->second; - LL_INFOS() << "Location: " << free_block->mLocation << "\tLength: " << free_block->mLength << LL_ENDL; - } -} - -// verify that the index file contents match the in-memory file structure -// Very slow, do not call routinely. JC -void LLVFS::audit() -{ - // Lock the mutex through this whole function. - LLMutexLock lock_data(mDataMutex); - - fflush(mIndexFP); - - fseek(mIndexFP, 0, SEEK_END); - size_t index_size = ftell(mIndexFP); - fseek(mIndexFP, 0, SEEK_SET); - - BOOL vfs_corrupt = FALSE; - - // since we take the address of element 0, we need to have at least one element. - std::vector buffer(llmax(index_size,1U)); - - if (fread(&buffer[0], 1, index_size, mIndexFP) != index_size) - { - LL_WARNS() << "Index truncated" << LL_ENDL; - vfs_corrupt = TRUE; - } - - size_t buf_offset = 0; - - std::map found_files; - U32 cur_time = (U32)time(NULL); - - std::vector audit_blocks; - while (!vfs_corrupt && buf_offset < index_size) - { - LLVFSFileBlock *block = new LLVFSFileBlock(); - audit_blocks.push_back(block); - - block->deserialize(&buffer[buf_offset], (S32)buf_offset); - buf_offset += block->SERIAL_SIZE; - - // do sanity check on this block - if (block->mLength >= 0 && - block->mSize >= 0 && - block->mSize <= block->mLength && - block->mFileType >= LLAssetType::AT_NONE && - block->mFileType < LLAssetType::AT_COUNT && - block->mAccessTime <= cur_time && - block->mFileID != LLUUID::null) - { - if (mFileBlocks.find(*block) == mFileBlocks.end()) - { - LL_WARNS() << "VFile " << block->mFileID << ":" << block->mFileType << " on disk, not in memory, loc " << block->mIndexLocation << LL_ENDL; - } - else if (found_files.find(*block) != found_files.end()) - { - std::map::iterator it; - it = found_files.find(*block); - LLVFSFileBlock* dupe = it->second; - // try to keep data from being lost - unlockAndClose(mIndexFP); - mIndexFP = NULL; - unlockAndClose(mDataFP); - mDataFP = NULL; - LL_WARNS() << "VFS: Original block index " << block->mIndexLocation - << " location " << block->mLocation - << " length " << block->mLength - << " size " << block->mSize - << " id " << block->mFileID - << " type " << block->mFileType - << LL_ENDL; - LL_WARNS() << "VFS: Duplicate block index " << dupe->mIndexLocation - << " location " << dupe->mLocation - << " length " << dupe->mLength - << " size " << dupe->mSize - << " id " << dupe->mFileID - << " type " << dupe->mFileType - << LL_ENDL; - LL_WARNS() << "VFS: Index size " << index_size << LL_ENDL; - LL_WARNS() << "VFS: INDEX CORRUPT" << LL_ENDL; - vfs_corrupt = TRUE; - break; - } - else - { - found_files[*block] = block; - } - } - else - { - if (block->mLength) - { - LL_WARNS() << "VFile " << block->mFileID << ":" << block->mFileType << " corrupt on disk" << LL_ENDL; - } - // else this is just a hole - } - } - - if (!vfs_corrupt) - { - for (fileblock_map::iterator it = mFileBlocks.begin(); it != mFileBlocks.end(); ++it) - { - LLVFSFileBlock* block = (*it).second; - - if (block->mSize > 0) - { - if (! found_files.count(*block)) - { - LL_WARNS() << "VFile " << block->mFileID << ":" << block->mFileType << " in memory, not on disk, loc " << block->mIndexLocation<< LL_ENDL; - fseek(mIndexFP, block->mIndexLocation, SEEK_SET); - U8 buf[LLVFSFileBlock::SERIAL_SIZE]; - if (fread(buf, LLVFSFileBlock::SERIAL_SIZE, 1, mIndexFP) != 1) - { - LL_WARNS() << "VFile " << block->mFileID - << " gave short read" << LL_ENDL; - } - - LLVFSFileBlock disk_block; - disk_block.deserialize(buf, block->mIndexLocation); - - LL_WARNS() << "Instead found " << disk_block.mFileID << ":" << block->mFileType << LL_ENDL; - } - else - { - block = found_files.find(*block)->second; - found_files.erase(*block); - } - } - } - - for (std::map::iterator iter = found_files.begin(); - iter != found_files.end(); iter++) - { - LLVFSFileBlock* block = iter->second; - LL_WARNS() << "VFile " << block->mFileID << ":" << block->mFileType << " szie:" << block->mSize << " leftover" << LL_ENDL; - } - - LL_INFOS() << "VFS: audit OK" << LL_ENDL; - // mutex released by LLMutexLock() destructor. - } - - for_each(audit_blocks.begin(), audit_blocks.end(), DeletePointer()); - audit_blocks.clear(); -} - - -// quick check for uninitialized blocks -// Slow, do not call in release. -void LLVFS::checkMem() -{ - lockData(); - - for (fileblock_map::iterator it = mFileBlocks.begin(); it != mFileBlocks.end(); ++it) - { - LLVFSFileBlock *block = (*it).second; - llassert(block->mFileType >= LLAssetType::AT_NONE && - block->mFileType < LLAssetType::AT_COUNT && - block->mFileID != LLUUID::null); - - for (std::deque::iterator iter = mIndexHoles.begin(); - iter != mIndexHoles.end(); ++iter) - { - S32 index_loc = *iter; - if (index_loc == block->mIndexLocation) - { - LL_WARNS() << "VFile block " << block->mFileID << ":" << block->mFileType << " is marked as a hole" << LL_ENDL; - } - } - } - - LL_INFOS() << "VFS: mem check OK" << LL_ENDL; - - unlockData(); -} - -void LLVFS::dumpLockCounts() -{ - S32 i; - for (i = 0; i < VFSLOCK_COUNT; i++) - { - LL_INFOS() << "LockType: " << i << ": " << mLockCounts[i] << LL_ENDL; - } -} - -void LLVFS::dumpStatistics() -{ - lockData(); - - // Investigate file blocks. - std::map size_counts; - std::map location_counts; - std::map > filetype_counts; - - S32 max_file_size = 0; - S32 total_file_size = 0; - S32 invalid_file_count = 0; - for (fileblock_map::iterator it = mFileBlocks.begin(); it != mFileBlocks.end(); ++it) - { - LLVFSFileBlock *file_block = (*it).second; - if (file_block->mLength == BLOCK_LENGTH_INVALID) - { - invalid_file_count++; - } - else if (file_block->mLength <= 0) - { - LL_INFOS() << "Bad file block at: " << file_block->mLocation << "\tLength: " << file_block->mLength << "\t" << file_block->mFileID << "\t" << file_block->mFileType << LL_ENDL; - size_counts[file_block->mLength]++; - location_counts[file_block->mLocation]++; - } - else - { - total_file_size += file_block->mLength; - } - - if (file_block->mLength > max_file_size) - { - max_file_size = file_block->mLength; - } - - filetype_counts[file_block->mFileType].first++; - filetype_counts[file_block->mFileType].second += file_block->mLength; - } - - for (std::map::iterator it = size_counts.begin(); it != size_counts.end(); ++it) - { - S32 size = it->first; - S32 size_count = it->second; - LL_INFOS() << "Bad files size " << size << " count " << size_count << LL_ENDL; - } - for (std::map::iterator it = location_counts.begin(); it != location_counts.end(); ++it) - { - U32 location = it->first; - S32 location_count = it->second; - LL_INFOS() << "Bad files location " << location << " count " << location_count << LL_ENDL; - } - - // Investigate free list. - S32 max_free_size = 0; - S32 total_free_size = 0; - std::map free_length_counts; - for (blocks_location_map_t::iterator iter = mFreeBlocksByLocation.begin(), - end = mFreeBlocksByLocation.end(); - iter != end; iter++) - { - LLVFSBlock *free_block = iter->second; - if (free_block->mLength <= 0) - { - LL_INFOS() << "Bad free block at: " << free_block->mLocation << "\tLength: " << free_block->mLength << LL_ENDL; - } - else - { - LL_INFOS() << "Block: " << free_block->mLocation - << "\tLength: " << free_block->mLength - << "\tEnd: " << free_block->mLocation + free_block->mLength - << LL_ENDL; - total_free_size += free_block->mLength; - } - - if (free_block->mLength > max_free_size) - { - max_free_size = free_block->mLength; - } - - free_length_counts[free_block->mLength]++; - } - - // Dump histogram of free block sizes - for (std::map::iterator it = free_length_counts.begin(); it != free_length_counts.end(); ++it) - { - LL_INFOS() << "Free length " << it->first << " count " << it->second << LL_ENDL; - } - - LL_INFOS() << "Invalid blocks: " << invalid_file_count << LL_ENDL; - LL_INFOS() << "File blocks: " << mFileBlocks.size() << LL_ENDL; - - S32 length_list_count = (S32)mFreeBlocksByLength.size(); - S32 location_list_count = (S32)mFreeBlocksByLocation.size(); - if (length_list_count == location_list_count) - { - LL_INFOS() << "Free list lengths match, free blocks: " << location_list_count << LL_ENDL; - } - else - { - LL_WARNS() << "Free list lengths do not match!" << LL_ENDL; - LL_WARNS() << "By length: " << length_list_count << LL_ENDL; - LL_WARNS() << "By location: " << location_list_count << LL_ENDL; - } - LL_INFOS() << "Max file: " << max_file_size/1024 << "K" << LL_ENDL; - LL_INFOS() << "Max free: " << max_free_size/1024 << "K" << LL_ENDL; - LL_INFOS() << "Total file size: " << total_file_size/1024 << "K" << LL_ENDL; - LL_INFOS() << "Total free size: " << total_free_size/1024 << "K" << LL_ENDL; - LL_INFOS() << "Sum: " << (total_file_size + total_free_size) << " bytes" << LL_ENDL; - LL_INFOS() << llformat("%.0f%% full",((F32)(total_file_size)/(F32)(total_file_size+total_free_size))*100.f) << LL_ENDL; - - LL_INFOS() << " " << LL_ENDL; - for (std::map >::iterator iter = filetype_counts.begin(); - iter != filetype_counts.end(); ++iter) - { - LL_INFOS() << "Type: " << LLAssetType::getDesc(iter->first) - << " Count: " << iter->second.first - << " Bytes: " << (iter->second.second>>20) << " MB" << LL_ENDL; - } - - // Look for potential merges - { - blocks_location_map_t::iterator iter = mFreeBlocksByLocation.begin(); - blocks_location_map_t::iterator end = mFreeBlocksByLocation.end(); - LLVFSBlock *first_block = iter->second; - while(iter != end) - { - if (++iter == end) - break; - LLVFSBlock *second_block = iter->second; - if (first_block->mLocation + first_block->mLength == second_block->mLocation) - { - LL_INFOS() << "Potential merge at " << first_block->mLocation << LL_ENDL; - } - first_block = second_block; - } - } - unlockData(); -} - -// Debug Only! -std::string get_extension(LLAssetType::EType type) -{ - std::string extension; - switch(type) - { - case LLAssetType::AT_TEXTURE: - extension = ".jp2"; // formerly ".j2c" - break; - case LLAssetType::AT_SOUND: - extension = ".ogg"; - break; - case LLAssetType::AT_SOUND_WAV: - extension = ".wav"; - break; - case LLAssetType::AT_TEXTURE_TGA: - extension = ".tga"; - break; - case LLAssetType::AT_ANIMATION: - extension = ".lla"; - break; - case LLAssetType::AT_MESH: - extension = ".slm"; - break; - default: - // Just use the asset server filename extension in most cases - extension += "."; - extension += LLAssetType::lookup(type); - break; - } - return extension; -} - -void LLVFS::listFiles() -{ - lockData(); - - for (fileblock_map::iterator it = mFileBlocks.begin(); it != mFileBlocks.end(); ++it) - { - LLVFSFileSpecifier file_spec = it->first; - LLVFSFileBlock *file_block = it->second; - S32 length = file_block->mLength; - S32 size = file_block->mSize; - if (length != BLOCK_LENGTH_INVALID && size > 0) - { - LLUUID id = file_spec.mFileID; - std::string extension = get_extension(file_spec.mFileType); - LL_INFOS() << " File: " << id - << " Type: " << LLAssetType::getDesc(file_spec.mFileType) - << " Size: " << size - << LL_ENDL; - } - } - - unlockData(); -} - -#include "llapr.h" -void LLVFS::dumpFiles() -{ - lockData(); - - S32 files_extracted = 0; - for (fileblock_map::iterator it = mFileBlocks.begin(); it != mFileBlocks.end(); ++it) - { - LLVFSFileSpecifier file_spec = it->first; - LLVFSFileBlock *file_block = it->second; - S32 length = file_block->mLength; - S32 size = file_block->mSize; - if (length != BLOCK_LENGTH_INVALID && size > 0) - { - LLUUID id = file_spec.mFileID; - LLAssetType::EType type = file_spec.mFileType; - std::vector buffer(size); - - unlockData(); - getData(id, type, &buffer[0], 0, size); - lockData(); - - std::string extension = get_extension(type); - std::string filename = id.asString() + extension; - LL_INFOS() << " Writing " << filename << LL_ENDL; - - LLAPRFile outfile; - outfile.open(filename, LL_APR_WB); - outfile.write(&buffer[0], size); - outfile.close(); - - files_extracted++; - } - } - - unlockData(); - - LL_INFOS() << "Extracted " << files_extracted << " files out of " << mFileBlocks.size() << LL_ENDL; -} - -time_t LLVFS::creationTime() -{ - llstat data_file_stat; - int errors = LLFile::stat(mDataFilename, &data_file_stat); - if (0 == errors) - { - time_t creation_time = data_file_stat.st_ctime; -#if LL_DARWIN - creation_time = data_file_stat.st_birthtime; -#endif - return creation_time; - } - return 0; -} - -//============================================================================ -// protected -//============================================================================ - -// static -LLFILE *LLVFS::openAndLock(const std::string& filename, const char* mode, BOOL read_lock) -{ -#if LL_WINDOWS - - return LLFile::_fsopen(filename, mode, (read_lock ? _SH_DENYWR : _SH_DENYRW)); - -#else - - LLFILE *fp; - int fd; - - // first test the lock in a non-destructive way -#if LL_SOLARIS - struct flock fl; - fl.l_whence = SEEK_SET; - fl.l_start = 0; - fl.l_len = 1; -#else // !LL_SOLARIS - if (strchr(mode, 'w') != NULL) - { - fp = LLFile::fopen(filename, "rb"); /* Flawfinder: ignore */ - if (fp) - { - fd = fileno(fp); - if (flock(fd, (read_lock ? LOCK_SH : LOCK_EX) | LOCK_NB) == -1) - { - fclose(fp); - return NULL; - } - - fclose(fp); - } - } -#endif // !LL_SOLARIS - - // now actually open the file for use - fp = LLFile::fopen(filename, mode); /* Flawfinder: ignore */ - if (fp) - { - fd = fileno(fp); -#if LL_SOLARIS - fl.l_type = read_lock ? F_RDLCK : F_WRLCK; - if (fcntl(fd, F_SETLK, &fl) == -1) -#else - if (flock(fd, (read_lock ? LOCK_SH : LOCK_EX) | LOCK_NB) == -1) -#endif - { - fclose(fp); - fp = NULL; - } - } - - return fp; - -#endif -} - -// static -void LLVFS::unlockAndClose(LLFILE *fp) -{ - if (fp) - { - // IW: we don't actually want to unlock on linux - // this is because a forked process can kill the parent's lock - // with an explicit unlock - // however, fclose() will implicitly remove the lock - // but only once both parent and child have closed the file - /* - #if !LL_WINDOWS - int fd = fileno(fp); - flock(fd, LOCK_UN); - #endif - */ -#if LL_SOLARIS - struct flock fl; - fl.l_whence = SEEK_SET; - fl.l_start = 0; - fl.l_len = 1; - fl.l_type = F_UNLCK; - fcntl(fileno(fp), F_SETLK, &fl); -#endif - fclose(fp); - } -} diff --git a/indra/llvfs/llvfs.h b/indra/llvfs/llvfs.h deleted file mode 100644 index 42feafe20b..0000000000 --- a/indra/llvfs/llvfs.h +++ /dev/null @@ -1,183 +0,0 @@ -/** - * @file llvfs.h - * @brief Definition of virtual file system - * - * $LicenseInfo:firstyear=2002&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#ifndef LL_LLVFS_H -#define LL_LLVFS_H - -#include -#include "lluuid.h" -#include "llassettype.h" -#include "llthread.h" -#include "llmutex.h" - -enum EVFSValid -{ - VFSVALID_UNKNOWN = 0, - VFSVALID_OK = 1, - VFSVALID_BAD_CORRUPT = 2, - VFSVALID_BAD_CANNOT_OPEN_READONLY = 3, - VFSVALID_BAD_CANNOT_CREATE = 4 -}; - -// Lock types for open vfiles, pending async reads, and pending async appends -// (There are no async normal writes, currently) -enum EVFSLock -{ - VFSLOCK_OPEN = 0, - VFSLOCK_READ = 1, - VFSLOCK_APPEND = 2, - - VFSLOCK_COUNT = 3 -}; - -// internal classes -class LLVFSBlock; -class LLVFSFileBlock; -class LLVFSFileSpecifier -{ -public: - LLVFSFileSpecifier(); - LLVFSFileSpecifier(const LLUUID &file_id, const LLAssetType::EType file_type); - bool operator<(const LLVFSFileSpecifier &rhs) const; - bool operator==(const LLVFSFileSpecifier &rhs) const; - -public: - LLUUID mFileID; - LLAssetType::EType mFileType; -}; - -class LLVFS -{ -private: - // Use createLLVFS() to open a VFS file - // Pass 0 to not presize - LLVFS(const std::string& index_filename, - const std::string& data_filename, - const BOOL read_only, - const U32 presize, - const BOOL remove_after_crash); -public: - ~LLVFS(); - - // Use this function normally to create LLVFS files - // Pass 0 to not presize - static LLVFS * createLLVFS(const std::string& index_filename, - const std::string& data_filename, - const BOOL read_only, - const U32 presize, - const BOOL remove_after_crash); - - BOOL isValid() const { return (VFSVALID_OK == mValid); } - EVFSValid getValidState() const { return mValid; } - - // ---------- The following fucntions lock/unlock mDataMutex ---------- - BOOL getExists(const LLUUID &file_id, const LLAssetType::EType file_type); - S32 getSize(const LLUUID &file_id, const LLAssetType::EType file_type); - - BOOL checkAvailable(S32 max_size); - - S32 getMaxSize(const LLUUID &file_id, const LLAssetType::EType file_type); - BOOL setMaxSize(const LLUUID &file_id, const LLAssetType::EType file_type, S32 max_size); - - void renameFile(const LLUUID &file_id, const LLAssetType::EType file_type, - const LLUUID &new_id, const LLAssetType::EType &new_type); - void removeFile(const LLUUID &file_id, const LLAssetType::EType file_type); - - S32 getData(const LLUUID &file_id, const LLAssetType::EType file_type, U8 *buffer, S32 location, S32 length); - S32 storeData(const LLUUID &file_id, const LLAssetType::EType file_type, const U8 *buffer, S32 location, S32 length); - - void incLock(const LLUUID &file_id, const LLAssetType::EType file_type, EVFSLock lock); - void decLock(const LLUUID &file_id, const LLAssetType::EType file_type, EVFSLock lock); - BOOL isLocked(const LLUUID &file_id, const LLAssetType::EType file_type, EVFSLock lock); - // ---------------------------------------------------------------- - - // Used to trigger evil WinXP behavior of "preloading" entire file into memory. - void pokeFiles(); - - // Verify that the index file contents match the in-memory file structure - // Very slow, do not call routinely. JC - void audit(); - // Check for uninitialized blocks. Slow, do not call in release. JC - void checkMem(); - // for debugging, prints a map of the vfs - void dumpMap(); - void dumpLockCounts(); - void dumpStatistics(); - void listFiles(); - void dumpFiles(); - time_t creationTime(); - -protected: - void removeFileBlock(LLVFSFileBlock *fileblock); - - void eraseBlockLength(LLVFSBlock *block); - void eraseBlock(LLVFSBlock *block); - void addFreeBlock(LLVFSBlock *block); - //void mergeFreeBlocks(); - void useFreeSpace(LLVFSBlock *free_block, S32 length); - void sync(LLVFSFileBlock *block, BOOL remove = FALSE); - void presizeDataFile(const U32 size); - - static LLFILE *openAndLock(const std::string& filename, const char* mode, BOOL read_lock); - static void unlockAndClose(FILE *fp); - - // Can initiate LRU-based file removal to make space. - // The immune file block will not be removed. - LLVFSBlock *findFreeBlock(S32 size, LLVFSFileBlock *immune = NULL); - - // lock/unlock data mutex (mDataMutex) - void lockData() { mDataMutex->lock(); } - void unlockData() { mDataMutex->unlock(); } - -protected: - LLMutex* mDataMutex; - - typedef std::map fileblock_map; - fileblock_map mFileBlocks; - - typedef std::multimap blocks_length_map_t; - blocks_length_map_t mFreeBlocksByLength; - typedef std::multimap blocks_location_map_t; - blocks_location_map_t mFreeBlocksByLocation; - - LLFILE *mDataFP; - LLFILE *mIndexFP; - - std::deque mIndexHoles; - - std::string mIndexFilename; - std::string mDataFilename; - BOOL mReadOnly; - - EVFSValid mValid; - - S32 mLockCounts[VFSLOCK_COUNT]; - BOOL mRemoveAfterCrash; -}; - -extern LLVFS *gVFS; - -#endif diff --git a/indra/llvfs/llvfsthread.cpp b/indra/llvfs/llvfsthread.cpp deleted file mode 100644 index 8cd85929e2..0000000000 --- a/indra/llvfs/llvfsthread.cpp +++ /dev/null @@ -1,300 +0,0 @@ -/** - * @file llvfsthread.cpp - * @brief LLVFSThread implementation - * - * $LicenseInfo:firstyear=2001&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#include "linden_common.h" -#include "llvfsthread.h" -#include "llstl.h" - -//============================================================================ - -/*static*/ std::string LLVFSThread::sDataPath = ""; - -/*static*/ LLVFSThread* LLVFSThread::sLocal = NULL; - -//============================================================================ -// Run on MAIN thread -//static -void LLVFSThread::initClass(bool local_is_threaded) -{ - llassert(sLocal == NULL); - sLocal = new LLVFSThread(local_is_threaded); -} - -//static -S32 LLVFSThread::updateClass(U32 ms_elapsed) -{ - sLocal->update((F32)ms_elapsed); - return sLocal->getPending(); -} - -//static -void LLVFSThread::cleanupClass() -{ - sLocal->setQuitting(); - while (sLocal->getPending()) - { - sLocal->update(0); - } - delete sLocal; - sLocal = 0; -} - -//---------------------------------------------------------------------------- - -LLVFSThread::LLVFSThread(bool threaded) : - LLQueuedThread("VFS", threaded) -{ -} - -LLVFSThread::~LLVFSThread() -{ - // ~LLQueuedThread() will be called here -} - -//---------------------------------------------------------------------------- - -LLVFSThread::handle_t LLVFSThread::read(LLVFS* vfs, const LLUUID &file_id, const LLAssetType::EType file_type, - U8* buffer, S32 offset, S32 numbytes, U32 priority, U32 flags) -{ - handle_t handle = generateHandle(); - - priority = llmax(priority, (U32)PRIORITY_LOW); // All reads are at least PRIORITY_LOW - Request* req = new Request(handle, priority, flags, FILE_READ, vfs, file_id, file_type, - buffer, offset, numbytes); - - bool res = addRequest(req); - if (!res) - { - LL_ERRS() << "LLVFSThread::read called after LLVFSThread::cleanupClass()" << LL_ENDL; - req->deleteRequest(); - handle = nullHandle(); - } - - return handle; -} - -S32 LLVFSThread::readImmediate(LLVFS* vfs, const LLUUID &file_id, const LLAssetType::EType file_type, - U8* buffer, S32 offset, S32 numbytes) -{ - handle_t handle = generateHandle(); - - Request* req = new Request(handle, PRIORITY_IMMEDIATE, 0, FILE_READ, vfs, file_id, file_type, - buffer, offset, numbytes); - - S32 res = addRequest(req) ? 1 : 0; - if (res == 0) - { - LL_ERRS() << "LLVFSThread::read called after LLVFSThread::cleanupClass()" << LL_ENDL; - req->deleteRequest(); - } - else - { - llverify(waitForResult(handle, false) == true); - res = req->getBytesRead(); - completeRequest(handle); - } - return res; -} - -LLVFSThread::handle_t LLVFSThread::write(LLVFS* vfs, const LLUUID &file_id, const LLAssetType::EType file_type, - U8* buffer, S32 offset, S32 numbytes, U32 flags) -{ - handle_t handle = generateHandle(); - - Request* req = new Request(handle, 0, flags, FILE_WRITE, vfs, file_id, file_type, - buffer, offset, numbytes); - - bool res = addRequest(req); - if (!res) - { - LL_ERRS() << "LLVFSThread::read called after LLVFSThread::cleanupClass()" << LL_ENDL; - req->deleteRequest(); - handle = nullHandle(); - } - - return handle; -} - -S32 LLVFSThread::writeImmediate(LLVFS* vfs, const LLUUID &file_id, const LLAssetType::EType file_type, - U8* buffer, S32 offset, S32 numbytes) -{ - handle_t handle = generateHandle(); - - Request* req = new Request(handle, PRIORITY_IMMEDIATE, 0, FILE_WRITE, vfs, file_id, file_type, - buffer, offset, numbytes); - - S32 res = addRequest(req) ? 1 : 0; - if (res == 0) - { - LL_ERRS() << "LLVFSThread::read called after LLVFSThread::cleanupClass()" << LL_ENDL; - req->deleteRequest(); - } - else - { - llverify(waitForResult(handle, false) == true); - res = req->getBytesRead(); - completeRequest(handle); - } - return res; -} - - -// LLVFSThread::handle_t LLVFSThread::rename(LLVFS* vfs, const LLUUID &file_id, const LLAssetType::EType file_type, -// const LLUUID &new_id, const LLAssetType::EType new_type, U32 flags) -// { -// handle_t handle = generateHandle(); - -// LLUUID* new_idp = new LLUUID(new_id); // deleted with Request -// // new_type is passed as "numbytes" -// Request* req = new Request(handle, 0, flags, FILE_RENAME, vfs, file_id, file_type, -// (U8*)new_idp, 0, (S32)new_type); - -// bool res = addRequest(req); -// if (!res) -// { -// LL_ERRS() << "LLVFSThread::read called after LLVFSThread::cleanupClass()" << LL_ENDL; -// req->deleteRequest(); -// handle = nullHandle(); -// } - -// return handle; -// } - -//============================================================================ - -LLVFSThread::Request::Request(handle_t handle, U32 priority, U32 flags, - operation_t op, LLVFS* vfs, - const LLUUID &file_id, const LLAssetType::EType file_type, - U8* buffer, S32 offset, S32 numbytes) : - QueuedRequest(handle, priority, flags), - mOperation(op), - mVFS(vfs), - mFileID(file_id), - mFileType(file_type), - mBuffer(buffer), - mOffset(offset), - mBytes(numbytes), - mBytesRead(0) -{ - llassert(mBuffer); - - if (numbytes <= 0 && mOperation != FILE_RENAME) - { - LL_WARNS() << "LLVFSThread: Request with numbytes = " << numbytes - << " operation = " << op - << " offset " << offset - << " file_type " << file_type << LL_ENDL; - } - if (mOperation == FILE_WRITE) - { - S32 blocksize = mVFS->getMaxSize(mFileID, mFileType); - if (blocksize < 0) - { - LL_WARNS() << "VFS write to temporary block (shouldn't happen)" << LL_ENDL; - } - mVFS->incLock(mFileID, mFileType, VFSLOCK_APPEND); - } - else if (mOperation == FILE_RENAME) - { - mVFS->incLock(mFileID, mFileType, VFSLOCK_APPEND); - } - else // if (mOperation == FILE_READ) - { - mVFS->incLock(mFileID, mFileType, VFSLOCK_READ); - } -} - -// dec locks as soon as a request finishes -void LLVFSThread::Request::finishRequest(bool completed) -{ - if (mOperation == FILE_WRITE) - { - mVFS->decLock(mFileID, mFileType, VFSLOCK_APPEND); - } - else if (mOperation == FILE_RENAME) - { - mVFS->decLock(mFileID, mFileType, VFSLOCK_APPEND); - } - else // if (mOperation == FILE_READ) - { - mVFS->decLock(mFileID, mFileType, VFSLOCK_READ); - } -} - -void LLVFSThread::Request::deleteRequest() -{ - if (getStatus() == STATUS_QUEUED) - { - LL_ERRS() << "Attempt to delete a queued LLVFSThread::Request!" << LL_ENDL; - } - if (mOperation == FILE_WRITE) - { - if (mFlags & FLAG_AUTO_DELETE) - { - delete [] mBuffer; - } - } - else if (mOperation == FILE_RENAME) - { - LLUUID* new_idp = (LLUUID*)mBuffer; - delete new_idp; - } - LLQueuedThread::QueuedRequest::deleteRequest(); -} - -bool LLVFSThread::Request::processRequest() -{ - bool complete = false; - if (mOperation == FILE_READ) - { - llassert(mOffset >= 0); - mBytesRead = mVFS->getData(mFileID, mFileType, mBuffer, mOffset, mBytes); - complete = true; - //LL_INFOS() << llformat("LLVFSThread::READ '%s': %d bytes arg:%d",getFilename(),mBytesRead) << LL_ENDL; - } - else if (mOperation == FILE_WRITE) - { - mBytesRead = mVFS->storeData(mFileID, mFileType, mBuffer, mOffset, mBytes); - complete = true; - //LL_INFOS() << llformat("LLVFSThread::WRITE '%s': %d bytes arg:%d",getFilename(),mBytesRead) << LL_ENDL; - } - else if (mOperation == FILE_RENAME) - { - LLUUID* new_idp = (LLUUID*)mBuffer; - LLAssetType::EType new_type = (LLAssetType::EType)mBytes; - mVFS->renameFile(mFileID, mFileType, *new_idp, new_type); - mFileID = *new_idp; - complete = true; - //LL_INFOS() << llformat("LLVFSThread::RENAME '%s': %d bytes arg:%d",getFilename(),mBytesRead) << LL_ENDL; - } - else - { - LL_ERRS() << llformat("LLVFSThread::unknown operation: %d", mOperation) << LL_ENDL; - } - return complete; -} - -//============================================================================ diff --git a/indra/llvfs/llvfsthread.h b/indra/llvfs/llvfsthread.h deleted file mode 100644 index 7814de4a2d..0000000000 --- a/indra/llvfs/llvfsthread.h +++ /dev/null @@ -1,140 +0,0 @@ -/** - * @file llvfsthread.h - * @brief LLVFSThread definition - * - * $LicenseInfo:firstyear=2001&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#ifndef LL_LLVFSTHREAD_H -#define LL_LLVFSTHREAD_H - -#include -#include -#include -#include - -#include "llqueuedthread.h" - -#include "llvfs.h" - -//============================================================================ - -class LLVFSThread : public LLQueuedThread -{ - //------------------------------------------------------------------------ -public: - enum operation_t { - FILE_READ, - FILE_WRITE, - FILE_RENAME - }; - - //------------------------------------------------------------------------ -public: - - class Request : public QueuedRequest - { - protected: - ~Request() {}; // use deleteRequest() - - public: - Request(handle_t handle, U32 priority, U32 flags, - operation_t op, LLVFS* vfs, - const LLUUID &file_id, const LLAssetType::EType file_type, - U8* buffer, S32 offset, S32 numbytes); - - S32 getBytesRead() - { - return mBytesRead; - } - S32 getOperation() - { - return mOperation; - } - U8* getBuffer() - { - return mBuffer; - } - LLVFS* getVFS() - { - return mVFS; - } - std::string getFilename() - { - std::string tstring; - mFileID.toString(tstring); - return tstring; - } - - /*virtual*/ bool processRequest(); - /*virtual*/ void finishRequest(bool completed); - /*virtual*/ void deleteRequest(); - - private: - operation_t mOperation; - - LLVFS* mVFS; - LLUUID mFileID; - LLAssetType::EType mFileType; - - U8* mBuffer; // dest for reads, source for writes, new UUID for rename - S32 mOffset; // offset into file, -1 = append (WRITE only) - S32 mBytes; // bytes to read from file, -1 = all (new mFileType for rename) - S32 mBytesRead; // bytes read from file - }; - - //------------------------------------------------------------------------ -public: - static std::string sDataPath; - static LLVFSThread* sLocal; // Default worker thread - -public: - LLVFSThread(bool threaded = TRUE); - ~LLVFSThread(); - - // Return a Request handle - handle_t read(LLVFS* vfs, const LLUUID &file_id, const LLAssetType::EType file_type, /* Flawfinder: ignore */ - U8* buffer, S32 offset, S32 numbytes, U32 pri=PRIORITY_NORMAL, U32 flags = 0); - handle_t write(LLVFS* vfs, const LLUUID &file_id, const LLAssetType::EType file_type, - U8* buffer, S32 offset, S32 numbytes, U32 flags); - // SJB: rename seems to have issues, especially when threaded -// handle_t rename(LLVFS* vfs, const LLUUID &file_id, const LLAssetType::EType file_type, -// const LLUUID &new_id, const LLAssetType::EType new_type, U32 flags); - // Return number of bytes read - S32 readImmediate(LLVFS* vfs, const LLUUID &file_id, const LLAssetType::EType file_type, - U8* buffer, S32 offset, S32 numbytes); - S32 writeImmediate(LLVFS* vfs, const LLUUID &file_id, const LLAssetType::EType file_type, - U8* buffer, S32 offset, S32 numbytes); - - /*virtual*/ bool processRequest(QueuedRequest* req); - -public: - static void initClass(bool local_is_threaded = TRUE); // Setup sLocal - static S32 updateClass(U32 ms_elapsed); - static void cleanupClass(); // Delete sLocal - static void setDataPath(const std::string& path) { sDataPath = path; } -}; - -//============================================================================ - - -#endif // LL_LLVFSTHREAD_H diff --git a/indra/llwindow/CMakeLists.txt b/indra/llwindow/CMakeLists.txt index 8bfb23ed64..70eb99c86c 100644 --- a/indra/llwindow/CMakeLists.txt +++ b/indra/llwindow/CMakeLists.txt @@ -16,7 +16,7 @@ include(LLCommon) include(LLImage) include(LLMath) include(LLRender) -include(LLVFS) +include(LLFileSystem) include(LLWindow) include(LLXML) include(UI) @@ -26,7 +26,7 @@ include_directories( ${LLIMAGE_INCLUDE_DIRS} ${LLMATH_INCLUDE_DIRS} ${LLRENDER_INCLUDE_DIRS} - ${LLVFS_INCLUDE_DIRS} + ${LLFILESYSTEM_INCLUDE_DIRS} ${LLWINDOW_INCLUDE_DIRS} ${LLXML_INCLUDE_DIRS} ) @@ -72,7 +72,7 @@ if (LINUX) ${LLIMAGE_LIBRARIES} ${LLMATH_LIBRARIES} ${LLRENDER_LIBRARIES} - ${LLVFS_LIBRARIES} + ${LLFILESYSTEM_LIBRARIES} ${LLWINDOW_LIBRARIES} ${LLXML_LIBRARIES} ${UI_LIBRARIES} # for GTK @@ -95,7 +95,7 @@ if (LINUX) ${LLIMAGE_LIBRARIES} ${LLMATH_LIBRARIES} ${LLRENDER_HEADLESS_LIBRARIES} - ${LLVFS_LIBRARIES} + ${LLFILESYSTEM_LIBRARIES} ${LLWINDOW_HEADLESS_LIBRARIES} ${LLXML_LIBRARIES} fontconfig # For FCInit and other FC* functions. diff --git a/indra/llxml/CMakeLists.txt b/indra/llxml/CMakeLists.txt index 013a422d35..3a7a54e51d 100644 --- a/indra/llxml/CMakeLists.txt +++ b/indra/llxml/CMakeLists.txt @@ -5,13 +5,13 @@ project(llxml) include(00-Common) include(LLCommon) include(LLMath) -include(LLVFS) +include(LLFileSystem) include(LLXML) include_directories( ${LLCOMMON_INCLUDE_DIRS} ${LLMATH_INCLUDE_DIRS} - ${LLVFS_INCLUDE_DIRS} + ${LLFILESYSTEM_INCLUDE_DIRS} ) include_directories( ${LLCOMMON_SYSTEM_INCLUDE_DIRS} @@ -42,7 +42,7 @@ add_library (llxml ${llxml_SOURCE_FILES}) # Libraries on which this library depends, needed for Linux builds # Sort by high-level to low-level target_link_libraries( llxml - ${LLVFS_LIBRARIES} + ${LLFILESYSTEM_LIBRARIES} ${LLMATH_LIBRARIES} ${LLCOMMON_LIBRARIES} ${EXPAT_LIBRARIES} diff --git a/indra/mac_crash_logger/CMakeLists.txt b/indra/mac_crash_logger/CMakeLists.txt index 95637c9a28..75621d7b75 100644 --- a/indra/mac_crash_logger/CMakeLists.txt +++ b/indra/mac_crash_logger/CMakeLists.txt @@ -8,7 +8,7 @@ include(LLCoreHttp) include(LLCrashLogger) include(LLMath) include(LLMessage) -include(LLVFS) +include(LLFilesystem) include(LLXML) include(Linking) include(LLSharedLibs) @@ -19,7 +19,7 @@ include_directories( ${LLCOMMON_INCLUDE_DIRS} ${LLCRASHLOGGER_INCLUDE_DIRS} ${LLMATH_INCLUDE_DIRS} - ${LLVFS_INCLUDE_DIRS} + ${LLFILESYSTEM_INCLUDE_DIRS} ${LLXML_INCLUDE_DIRS} ) include_directories(SYSTEM @@ -68,11 +68,10 @@ find_library(COCOA_LIBRARY Cocoa) target_link_libraries(mac-crash-logger ${LLCRASHLOGGER_LIBRARIES} - ${LLVFS_LIBRARIES} + ${LLFILESYSTEM_LIBRARIES} ${COCOA_LIBRARIES} ${LLXML_LIBRARIES} ${LLMESSAGE_LIBRARIES} - ${LLVFS_LIBRARIES} ${LLMATH_LIBRARIES} ${LLCOREHTTP_LIBRARIES} ${LLCOMMON_LIBRARIES} diff --git a/indra/mac_crash_logger/mac_crash_logger.cpp b/indra/mac_crash_logger/mac_crash_logger.cpp index 54e41a1954..66d8cfa590 100644 --- a/indra/mac_crash_logger/mac_crash_logger.cpp +++ b/indra/mac_crash_logger/mac_crash_logger.cpp @@ -27,7 +27,6 @@ #include "linden_common.h" #include "llcrashloggermac.h" #include "indra_constants.h" -#include "llpidlock.h" #include diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index 3439951e80..82e6cda193 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -39,7 +39,7 @@ include(LLPlugin) include(LLPrimitive) include(LLRender) include(LLUI) -include(LLVFS) +include(LLFileSystem) include(LLWindow) include(LLXML) include(NDOF) @@ -84,7 +84,7 @@ include_directories( ${LLPRIMITIVE_INCLUDE_DIRS} ${LLRENDER_INCLUDE_DIRS} ${LLUI_INCLUDE_DIRS} - ${LLVFS_INCLUDE_DIRS} + ${LLFILESYSTEM_INCLUDE_DIRS} ${LLWINDOW_INCLUDE_DIRS} ${LLXML_INCLUDE_DIRS} ${LLLOGIN_INCLUDE_DIRS} @@ -2016,7 +2016,7 @@ target_link_libraries(${VIEWER_BINARY_NAME} ${LLRENDER_LIBRARIES} ${FREETYPE_LIBRARIES} ${LLUI_LIBRARIES} - ${LLVFS_LIBRARIES} + ${LLFILESYSTEM_LIBRARIES} ${LLWINDOW_LIBRARIES} ${LLXML_LIBRARIES} ${LLMATH_LIBRARIES} @@ -2492,7 +2492,7 @@ if (LL_TESTS) set(test_libs ${LLMESSAGE_LIBRARIES} ${WINDOWS_LIBRARIES} - ${LLVFS_LIBRARIES} + ${LLFILESYSTEM_LIBRARIES} ${LLMATH_LIBRARIES} ${LLCOMMON_LIBRARIES} ${GOOGLEMOCK_LIBRARIES} @@ -2507,7 +2507,7 @@ if (LL_TESTS) set(test_libs ${WINDOWS_LIBRARIES} - ${LLVFS_LIBRARIES} + ${LLFILESYSTEM_LIBRARIES} ${LLMATH_LIBRARIES} ${LLCOMMON_LIBRARIES} ${LLMESSAGE_LIBRARIES} diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index c0166f158e..393a38fb9c 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -1362,6 +1362,39 @@ Value 23 + EnableCacheDebugInfo + + Comment + When set, display additional cache debugging information + Persist + 1 + Type + Boolean + Value + 0 + + DiskCachePercentOfTotal + + Comment + The percent of total cache size (defined by CacheSize) to use for the disk cache + Persist + 1 + Type + F32 + Value + 20.0 + + DiskCacheDirName + + Comment + The name of the disk cache (within the standard Viewer disk cache directory) + Persist + 1 + Type + String + Value + cache + CacheLocation Comment @@ -2835,17 +2868,6 @@ Value -1 - DebugStatModeVFSPendingOps - - Comment - Mode of stat in Statistics floater - Persist - 1 - Type - S32 - Value - -1 - DebugStatModeTimeDialation Comment @@ -3638,17 +3660,6 @@ Value 4 - DumpVFSCaches - - Comment - Dump VFS caches on startup. - Persist - 1 - Type - Boolean - Value - 0 - DynamicCameraStrength Comment @@ -11580,7 +11591,7 @@ Boolean Value 0 - + NearbyListShowMap Comment @@ -14258,28 +14269,6 @@ Value - VFSOldSize - - Comment - [DO NOT MODIFY] Controls resizing of local file cache - Persist - 1 - Type - U32 - Value - 0 - - VFSSalt - - Comment - [DO NOT MODIFY] Controls local file caching behavior - Persist - 1 - Type - U32 - Value - 1 - VelocityInterpolate Comment @@ -16621,7 +16610,7 @@ Type Boolean Value - 1 + 1 diff --git a/indra/newview/app_settings/static_data.db2 b/indra/newview/app_settings/static_data.db2 deleted file mode 100644 index f85aa81601787e0643162d85f1086f548577809d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 576578 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�cKK(~i-aO*cSa&$kG1h$Xp?gV@$*^{|GB$u_IY5iNG7KxGarAElQ#RVkoOeX zujEA{9>ANCeD3uDg;YEzfufLo?dE^~T6L)1{9E9)>UY5EI3xE8zLcPP<>p?)T?kgc zd&Xp(guZt}&J_FvVfB1vJcwJNACZ`T##`XZZzoMH{mmL4HI;M$FdhZ%-= z_=^#bRe*RXA>!dl5sy`lj;8=Zn-TFaEr`czMLf1L#KYW;cuMxS>C=dKn8(oZybEo7 zSAH!lB$#SmE8;tMx2=8@s;}J~A6{G27tE}V=$hKfX}iXrbVFYYZmamykLbPvM`6?k z?dR#yew(pv{}r^&Yi-;9=hx;8yD0RN)%-5%gKIX-EwwtzHc#Hk+-d9Hnqet~>#Ft= zM)^p8-@xj(GVJDZuYA9`8F~j3# z<=w2Lyl154*L+jWVr|{DbKB8sD+eJp>E|s6wx?|7Pp{l`aC^!&TPTu8%|r5-VMrc- zF_K3`B6(H;l4naq@+cva#}p%ZJSmcAmAA%scwFkj_GHYkQS@sAG{9!38hr8s0UA|9(89Zvy-HY4I; zS`d%big;{gh=*5=c$mA}^l3yq%wyjOz8=@>Rl6IC(y6{2_TZVH=WWTm#pPWV!!l zOo`OM$+M%W`|2{aZOrWaUds-tDDTy4)N{J3S**~~keRDgR!(!-=qVZ{fBJRnwNMjW z!V~dR^AJBX4Ds_9BYvv@@lry>%M>GCc=>1NwaO7M1rV>zh?B3|Y(#9ML(@$xPpq^>M1eKg~_lGlploV(j5=P9xmMIrmy8{2ys z5+m)_4OHdi1HkVRp`5erM`+!3@<+!v!i)9&%AHj+;Klm4O77ZP%r-==aM-zD&2qn% zUV17;W%WESKY3s*v??LDoLCR7+M3S&akrAiYDgdPbE4A9;imt5#SvO{ihSnz8*q3; zyv#7f%U_ImsYt|Y6(C+phk~4^pcL5=F<+t?aOR3PBi2vMO#DDH}ch&kef55x=$X<49zMsJ{ z%5F{yOO*~I_+4J5eI`uLusV|QfAg(Is#i-AKV?xatKU!Z?@cZ+){!q)l3x+foQjpg zix__dE`1i~t+je?N==OFZLp1LPWD(W$)>!2iMt+AZLo5B$9}PNNCtm;OWexUci}?V zh?g0Lc=?MFFBOS+p*iimwnW5B2@x+-jCgrc#0&4M*m-S6#LKiGUaJ-H+R6|wuNv_} zv)Xxi^@z7*f1ADs+VpKiyd`H4FYf|E>dGInek+^|yjCRV++8H+-0QEEpQWwRz^f*^ z-Rx$4FGFRF-Kyv(@A+L;rW8h>)mR;?WBy+7Qe*4>8$WZ^1d{3%8MiKB0CWKhk{`)` zRNIDBiWO0>pbKaaZ(N=ULkc;m{!2gC*~V;5g8Abb%KL}aQ$ml@cV{9OgjDIQoK7oi zf{*L@)7eo=W>@KKp@^TFhxnOch@Zb0@l%nA-zq@-lo0VV#fYCLMf@=2VCSa*;iD^S z&>6Lc>h)UVxXA*i$~!bc#XDfQqPw1IXd+qeT{3#W@2#Fb`n|_TXl!HL_5P<8LvvT_ z<1d6jb0635ZqC)hE0m05SMO{2)0gS*{V-f>3q`!lFvQDWjCiR?#A_8GUP_2~nPSAt zlOkTL9Pv^B@!E`tmuW$~Rx9GQl_6eUHR5INM!Y5a+w?uqrf(zSWgbJkC1(&X?*c;V zN|oNyoTKHnB01;oB01+?pU}jVeh+WfA-mbl`v0)^9&k})+rBUo6rDlEF)N61OgJD& z6h#3+B?nOn5*uh58tA5>Q|+owG&$$cfG8q4Nm5kI3MeQB989AlB48Sw8J(GaySm0O z-nr+y=X>|uci(+BKYDdl?OL^K?X}}t>%TwqFj^*4XI;#f;S4A0E%Daj{p{SyR#^kV zt60)$b25q<*P?a4Nr`RBGKOt#v+y=82+>*kMBqZog+1A+B(|T3*}e8f@=5=yXz6#C za_0KvBe{l7`A+-1;Zj0<&Kyz%?7;|r>zxRGq+J9*={|yAZV(dE-xw!ycTV0R zA1~nlBf-_gQm&zI=`|0|;Z^<~ljhA{en z-Fg^T4&%0Ac)TnE{*&l`Z9KLg#_z)rdOWlpM%3d0<_5Cp{|)d+7I!ZT|A)83L)n{gZ%MWc6jp7P<9ytzI<*aUcL42$3KI0>I<{KLG-OarrO;Ul$LIhq3;606ct20tx^^2H>Ii ze?bDkFaA9e07M0l;Q+`00q_Svwtv9^fEgih0B~S{4>$mLav2T)gbl!P0A$B_F%dWb zFsNS!1E6mJf8bKn#V^3zLaEAN0AO@Kjsk$A1K=nCI`Fa#1wijl6aa`8fTIAs2LXU= zWFP=Ke*po2urW9W03-wiz=kgv0ROVq_zUAN68Nu`z<;3scf~<~95u}CTy4J~fBm;X z{@U;<`VS6hg9Ga5!Ojzcw?G6O9PCS9_6nZ15*(8tD2MXzJ_flYF&&y-E7My10Gd%jbWH1pdDM+xkao zSip#Y|DN^TkEE@w<*TiwslVPI?j@?_2Q}4DTTfG4*GJb!OGi)7N84b^D$>q~d{Evy0+z(_iR64!9&FITj?+X+>I03C2=DjEIL84Ty~R~Dy{ z6s|7ZRi2>u^*{Hu__s+%IDV`NFtVATvZONCpnse4hB#axfX^nVEafLII3Lp!E;!xY zlbK^k49o;UW$E90lgn&S_!&GXfi*K$H!zjNy2pC1_c%?&acG@sFgHDo)7`z)AUypZ z3`r)ajKfD)5ByM3cKeJdbzUX;sY5V5gLgK#yZfu~>3jiQDkZ4wwvR3fA8)f0{S1D> z?y(Mu4o2&7ySrD2jz;uHNu>mp-S(*|A3s4znK0FNcmF1w9`6c0^9U-t;r$B|?(!dR z`RU?7+F5>gx1jqab`07%2r9ef6BF^r^nNgS`f56qVf?}D#w;j98I`5~#H9H#y$fp+ z`UvapzQLQvZG^f*P+9u-Cclq~7YX{=CQzAg{StdFU0aJt0PVCpXR z$yg@LIzeTrKbmMhCYK=7*nhy}(Siw4bM`}geHoP{|6qFfn3}=9&W0{_-3QrY^rO&p zPEc9uk4xqslP~5si)&%>-vBEUIy*`UDog&!Qt-$0A(#T2igb4u3AAZ;Kk`ye2Zor8P65m70?9V84wR|#W7VrZ58mALH*BG0oQ2!506Jx zS6Yhx1S$b*W)pBn2SDyTG2o)Za0_c!kPhbw*Ox8_x#&E&eX|NkM3=$so7aI56b3x# zlmi2_6*w3O(PuydZfTu}6#_T7&2l);1|-03mS6Lxfk9~DUdVrgB*JkwK|cvOAs+t} z@kUdC$&_Zq4>cFCW@;n(=!_J&`8PKTjm&IS&*a_#iMiL8e#bq54CTLGImD^so++5Q z4o2i~Zx!h1tmf7r)dda)6Ofx&RY91^WKbtOUXZ-?9>^EB7F1hqLStf~pQ_Xb<;DgS zz&CzBd%-1whheHKwIP0BCVWGb%LYnte|32z40{CkxxUR^B#MS18&%xLqJ6L(AgGMR zhqm(Xu7nt$FOq7{*U|Rd3z6@qlvr>y`Q@ zB?q5n=;%x^F*qp9a4_I)v^n6A9%jePK;ZNE{fFAc^Wea==3m? zxx%N&GFtLhAXtp-jp(-CDm>5G4%re^#`e>B8qOG>7pg0r7M%f|oG_CgL>(X0eF}Ac-{TGR~UVZ8HrH>1mbZrY?ue_VT$pB5Cxh}BCVoQlwN9XzeRGT|cKNBie z?0$lTnZ#E4x|Q;hx2jb|I~|Fywrr~mH=mK)ZN09#!(?-@R7y};);^gR;;%&HiR+eq3iS7l|AL- zJQ;rs(Yok@=@E;u>r2zo9F`&WdSwvW#GZ-4wi@+e&c}3g27oc$7`6sh2yiU@Z3nlx!Y9I%PGKte9V(I01GjU3`<&jZnhh3fMV~ zXqX8_NUnYWGdoRGc*KQQZOIhPK2{H#t~^oD@f)z|BB<;!pUl%g3ZonSBU~40RX@es z$gDwLudL)%1l{1ZZCI-=GWKcm7Xn?w9BPXGq}h>%WaR#b3kRpB5AVO=ueS z-l24whErfr1YKjLWrV+f=zj}GKz}VQEokQRjqvxTQ)Pxe=)R-{y_EjHZ1f*&eE-4p ze>DvL2XFc>GYlGhY8Zr$05aphp3L~Kr-fSy^|TD(H{8t&U#5l5clft#2Qaw(4*ac; zZX`ic;1)fYhYkV@`pS0=xXT01!5nP zmae8ZzB7cM9$fVGBk99C4E=lz4E;9f=t7UR{|qht!sA~hf%o%&XK415J>&fkeEkpq z$LBow^d#i(<}Bulr(!&jr|cm$H&HKW=YBu*Of(PRCNSbW&hY~_*2g&uj-70-C^|WZ zcMqj3H7vE|F!^}-k?^Ma4mNSzoj@E970y0zHjH#+eIs#xdS7M3>Cmuh=Ycm()2Ucx z&MlwTufv=UEq<`#1fTXtF^ugwwI_03QN@VCnIjC_g7Ix z<(Vr6WBs)XnPTN64*7s>Q8xrky_3VMP*q(Wy(r;klgq3i=4+6CJa=9sM>F#0^FwNe z=r~3B3LJ!D*Q0OUh|+h(=5p>1nw!UxOS(5O&oV85XVD>+tDjx&ByB-iSyI@+L5gIXAhhQ zmLZE1p5Mv2^@4Lban8W^LwDJ?Q(De0eo(}onQ3{%|Hr+YzFcZ~#YigGyNFXbK7JO- zEqw>W7P|oFAUl)sGXjw;j>0(&@xC&7d^V@jkjdjx)c4HkY_YO?VjN#b-2L@%2}RtM ztE&2-&PxNe^7U6_t74))zO*-yKH+QmQ=Ncb6M|nhpMV{r<1*K?Y8Q?+ zm$2T$1ou8d{9$0tA!+qANoLl@e zi6K)uz8^YsG@d&J>P6zAW4tBF{y(x(PH_#`6(fA$5p^VZx%$&fu^(h5T&OJ zn(KO(OF<00&sOIfG?aaY8)$5XHbi@~pI8Y|t;l|+yhAN&6h4==aL)-;p6bEkd*-40 zsJqyD-rLZH)cKqd-?Kn2%#2$|DgdylMiihK5C3ZkRYS-5#V9#^AsQ~4gsIV0QK5JW zrq6i^vXZlagWxvs$XpA86CQz!xjY~#n1a?x)}l`BH$h+-8)%%l2CDXxLCnP=pj9da zW0zlmuOw%I^T0GzEzcSa9a@cUO*O;@9xO%^682)suZZWqH-g}8eWN^K3MDCRf|!_0 zD4S^X9ne5fl{6GC({pvEm%^Qj)^Z=uIE20ibGUi4s^E@ATe&uKThW&wk1My}8a$qg z%wM`2dkeCmtPt!s_-?vujzH=GWtM@?MfK4@wM2R^d9H~dfpM}eeeVnlFZ@$OVd#MAT9JaFc(#T$Ww&uv`|I#C?JQML6eLR zP^0fcRngg?kKuvNL0=&PrV}(L$N_!MCTO}*2P23Dx&|Vn6k(pI4!Rd{5QL+~=m=La zCIq!WPjOpgccV7wNp5h$7Ssu?F87t;`T`P)*LF!x->K^Ep?ms^R@z98v8p zunQgH7&a)Nj_5dNv}q-32l3vDTg*{gNS)eUA$`f2c+4H1AK|ngcR=mY`<#$29n=B6 z$DLAIg4a7y|Wkxl3tuJgb+R~Kb+ zC*AxSS%u!_b_`l0>ZmyqI#h_vM9Y!I_nsnOqrV~p4^{zXR2#TFp9tmq15keTnTgz) z8bPDNQG}e_l257>s`3?D5PK9>p($uVTqCSP6Vd5$^{@&}Ky}5(5NP;7C(Xm z^m0lvIzC$56HxG3@ZNTRSAmZQ{&p)zldln+J|LA(bzye7eZ0! zpsCb8D2kPs5%oG0#dd5<*aavGKWs6r8hmUWZUbGJD3+m@MNBA)iRd6S((7}oz{40m z6h#jh5-)?V{sL&G%tj>z8&F0{7f>oqL>rQqfU8wEfm`Yfw4^^D>`cB7U-d_HXVL}u zit?CE!hZN_dSJ820lrcL_zv>=+gJKv?86-+-nXNFoAQIvZ}}%F@fOw{>J#3w#zH3r zo4HbO8ahG*Xh^~LfkX>?$R9cxn8C1UZ|EH1DFv^srBEhPpuIy1Wg-PukQPGlUq>gY zOg6`9c*_Z$7BJ}i0G$*Z;-s+lLx+YGDXjevD*(3O`Va#xB^zFYP8FMSq);uOQ$#X! za%h)=8hE|^xD>2_G^7ir&6Gm*fahWQYtZolgXv=~O2Gi^0gQU!{ZQs(mm!uKA6qxd6V9JH)8m+M*E#I*49DmSFpSyEjStTRuQ9m=q=*7Yo784T)q@w<{H13F zqu?IaySyn*5xs%wt~m|&yhz1tbqdlH&;~5f*nn0B)Jb8zT zw6|a*Z{Z#z+ICRD<9p7|d=5%@dfvBVz6Z|y5#R6V`CyMgfkH~2iH!(aLXp@@C|5uZ zk7nth&-iNer<4{D$QLlvS=~T|ug|fMc?J&him>ZZv7ilg5G)ES2a8~Jadlq z;T{57?BE1{kt>+OQcrdlh=CcaKQ)&93eaII`zE3ntj7$pzX^Mdgo>Z$-VS#{&Lv9< zN+MZ^afYMhRrFjiJzc3Zf>i{L$G4Tmvi<8MR=~UqMqz84&m@Bv zf{?C4rW&Y?(>PNM@Bc|0bFqy14qV|H^^`HEp!wXA{)5bB;3aS#;4t&RI?<$?KSw8l zoubg86O0((CV+J;k_k@m#gBG`tASC0@$f*HBA^M!N0vq`2g`)Yul~f>`-gaWb}~)S z)9cE(h|E*YF=l7ZVD(ISvuR;gL=>vRF#A4hZ=}xj*s}yN7*JR)G z+zPtf0{49n@)9DN)CSy+=FgzcU%K95L%~5(@A3ibd-)4|b=T-oY$TV0^R>`jZAG_y zZFPLDs|uU;H5)wjc~$fzFwj_mT2Z7E!ZX8m-YJ;m|HSGh*`#=8n4RrR7fNwffV{)6 zJL)9rzCpVRe6~pXgBI@5q$U)VQLeZpx?e56?8o;!vvX$2T{k`NWlm|u6`mu$DuF{q zkNpctN`X5i7Jl|Y`}W!wulG=(=sEaF23=c1gxzeBJ zTG+2mv!qH2CfgfkU-fg8C_1|4E#9M4dfHkci?_F}%-BqlSVy9iCv21o^&=M@o@4YA zPo90XYOArAXgEw%E8Ma-@v4_$!&$4Y^tY~~O}*Q1XX<$rw>-3*m0=R()GpX|EVVpr z;;}-DH>nE2?Z+o=lS|*SFQhAZ+vfD6t{P|FnLS9G>~`&(tLay1`}|`rdT#1S8KD~W z{AhwEXVJ$lx0{3{snDGVo^6bc|2AaO&3zk}#I^->3{KxTAiPfs9ooE+hyCEU_})5` zX>i0j@ZiCwTai*<@guhB;&4ZQ<6*fi@nMO9<0F#I(-ZTCwlKoQ&B48U?;b za}Lj+zckXfH|OD^-sO6}mvb&H!&dt5yPN%5U3ZO*+gSF_`T1IPp5JGiFR|6p@N&*k z`nK8Nn43pd%c4MI^F2>8n-*R+RrLHmr$vKjw#e&Hp6b#K+rIKN%{{CB#H!5AB4^?P zJ6nBEjhykt@(#}X{By>a2koM}MP`LBTDXU}|B73Rn^%_iQoiRF4{^4^8a?lEH-&80 zsuAA>dqy*zmKKtV_fRu?m)Zw~xzjUGtyG}2c<#^aTiX(P){~#XT@BUN{c+mnWoq=6 zJ#J~q>V1r5yU(SWFBCApale|{xk#TA?EiD>-8Cb~XnR$=eG`mH~R`w z&_#+dFFXcQzFpWFYvq}k; zG}qO8j_8k>k^%=`Il=SUj*@Tvb$E62luCc`pNZAZrIcIx&qHfe7admjZv(BL4z*n`}iKib3&;3C`R6}OxvwIfBdoZ7ue^@!&;6Oa8sQb7V| zwjaM0;LNp~6VeqDsKFJ?(>S9N*ulLtH|C-qNeSID)2Qc|e>-~Oo3YCm{C`6q%`EBP zN0P_#=Qt0L1C%kvg_CZgfm1Qcl8(W(K|i41t_dBQ6SN$S(p!9QY2a3bWj^rW1nCB= z&{_OwGf5-rjIZ(Vt^l*hw;|&rQ^{8u#bKpmy&*BIeW5PTCq%R$eq`lWg#JmT1eK}j zU!7shWomjzqz!jkMOB`~uA}ef<;{8-cQUw3WHVPGo)M%KBe!5$ynDb?Vej(LIH{MI zrMu=tqLKGYp{>sCgnRn}*n!4w$f9`U85-3jrDEhM$3Ef3xlZy&TRO~vN{Pl1x0tmt_qswLDt(VjF&C5L+^2GUeQ z)aZ?g->{s*`xtK$qa)^X;H)Lp)#o=j1Duf=<1~jef@Ec{wxMu}uuFMgTc6-L2)y%u zwOtjf7?YM2=dvKaHCC8d@5;et@bW*%FSHEhC93Yaqluln||Kg75gr|xP{`rBjH%4 zQ~MT=v7}Sku$A**C(q4kKd$LLq>JX(oU|%i~hu<^3ikt_6oozCgNhaMK*nKcVEa@1`@pQHz~R+`~%C1l!<1_+ZEm)DO|~_KDI!y^#^$@}vgv z7AYjPCp1BiJ^LUss}OK71&WYj4=(XqLVpMk0$qG^xIFJIP#37tvr}oPkl)AnId%qm z9uqKk^16T+(dQ&Y4*^Hk2(k;^3noPuVS_Ppz%SZC;FkOZxy@9J$&5Dz*I2EwA;<|3 z0|#pB7-Jxfqn_NwX#w+*{?y_)3HSjKW}Hjk3wCl1vPYA@NBp9n<|+uc0ka56K`bi< z{VBvzqRX~LcZI_Ch}#3KBiqW(L66B@fKr~yS3#*Uiw?Vr_M+M1t5sfbKjKAjpynys z0Yd494ZB6-h+*hx6GgNZtfCdS@I|eF!gXp-7R^I71rv|uh~5BGto?YQC?0HNhIAE) zOh7PAM0T_q2qA!;~dhIog|yNUI$d$FU83%xVV4fvAGFNYH%{pc{DXZBd|QWGcI@j(t8zK zj!8;-m$y{LcNibiT{9`U>GUsIwmP9TNgZRA%?3TWZ;xNf4>XQWDn4;K{j%wT1I?XZ z@8_90*V-OEbr`B%3iXUfhP;DA?e3$84hQY}C0Ba9Ab;T=`6O^6C*z9S&SJ&m!UKHI zhT3Uu8;e|Dkro_v=i(PHRaaDK#^#bHaZ6pe?06?eUEYlsktQjg;dpp@&O$ z)i)j`hi9hVsc&yoqbCbiG(4*AV;G61HU3d6V8*6wYE)^}=WNSPtKZf+g0v*eK34V;>({U3I=8IALY;#>0#2)swBOf2&?}xIcAQ zep3UpM3`Ze8r?jv&>*`l|6ucQ$AYTbFMrWt&gqWBmy@qnrJYz-sgN$JebGF>Ca}=3!LQP$fwq6N z$*5wW$x2e(vaBk-sXxo9U0kEzFrGH?SXMQ^W;D0`_@TouDl`s+bZJ*a9}KS4I1^J9 zcF?B$+PS?A+YikyjJf!*Gqq>I;(#I|vAD12)&o1ddcf9eS3T)#VkI~EA zN+;cHYn!F>|p2+s8uXWDPMd~rSjpym_q{(b|0Eo8CxNK#6J{PlU-pv ze6T9KW_$VgNPAOd#e|a5v5UtHOEt4yp07KTpO+G^{EE;&sg$6yw(c`Sp{=ZsG>%)# z)6OL+@x>14le~G#iJ}ZHH@|0!Q1BB=s}NPm;sIveex2#<=v$^y!{Zri5IxR;^Levw zv83F|cWmaCLGFRVm5Kv-{(*o})#vG0Ljv8^dH8wtG4yAV}IN^0nF1h-Sdh(gr z7IOO!{i(mlOM=lS!i?a=r@?`v2HDn$&gATor@80i9Rk23NdYDHrf=n4M~P#Mws+C@ zaD7IU>8*6Pt*lJ+o!{Yyl=5?;=m7VTMTf75CXuVgu2#*Bc|oR+iE2w@hRI$}4I7Nb zvx0}8j5alkNfhZwamyXCe(0Jpr}ic>i)uPP@tB*KLwz{fe*Ab$Z|Js>kgjf#b0~9I z;|wM&3SIW(+PP!=h17*lV=nq()2Yd$Mm_1s?9g?iW0!wp@1s0^QqmvDnniy6$a!D~ zOEX~4y^g_fPQ90Tf9TLxh`#4Hm!KY^J3W3rJ@6oj*Xo&bLj35JAi!t%sPQlm{SdIV zb$moICO6c!zI2Qi(-S#($mMy7xQ1g{to(}5FSuK=OwVL`_?dy$My7{;Oe6FrT%8Yz zrn046IHiaz3%SEYRc_Eo!R=8x)4gb0!u2B`&q${~Ln9*cW|c6U)62tb=2k|jNxH)1 z7SI`w3sq@NYA*DPX@*e&8b>4c@-jH{mwH8<2-D{EE}ukO>2q78yQYj`se? zy_{Z18si3rPsy+kGC`EX-7^#@-*YF>ucfzy(m40Ir&Gz{#q1x1zb2{CnQ-OjMgkn; zAtR*DcmY!nW7^+{)#t3^#oFe_j39FSDwia25r$#49uI^L0x!NGzyMK)c=8NgK(6%!3oMdz*lTv;wduGzlA&U+-<*v(0n_|8_r}48avX2p<|bK z*Mp4okdl6KjVNPXsPjNQY#ovCNjL8vC`^$sItH&v#0kc*i>}W(DAK?d-^))4MeGFw z587k;XvsqHBS$bCv`}O`yp(yyZ>4B_B#yB$V2-eKESb?2x}NXy{6Umzv;`dV5qc$+ z5>%#tpE^CSktv@&#O;khNlFERJE1qwo+(p>&)j-2RAsgBXXo`io#{rxUi)y~;~5r0 zMSBjMNNf|TIPT-w%-tfKze|nRq&88g?n8wOaEXE);fK-Q<$DFXQNAcNe+c9l4AfSq znx6p_q50zqKa!)5^2|nfLQxxdVl~Qp%li??JG{jfB=~_NPP2H$@j-C>7sca=Q{Vz< z0-qMY2`+$c6nMlL!v)Y{!98ITTmaoGXo}hgO-3$){@_<|ojgcD4$y<+I~#$4PduDB z=nKZY%CQl|Mxf&H3@gG=!97=JIB^IPxH!l1)RS-X+jlDP4YG6i<$0ihOV34>UlDSYN(m|x_FtUBb!E~v=OC#OV4kuvyRd98(laHAHNWZw7gf<= zk?TvLv1tM;swo@nOP!;d?hB1kft;zyrC@^I zQqEvnFdUV;u^oy|!BP1JPFpG$mWmzwdeLd5VCP|WLhfu}XS;~=G%XUAQZOeusU4P* zCg-=*1XxO;>_vs62;Xy*eK&I#EG=cuvJ5J)58BFk1)bd$D28xHX9irRp2Vrh*bbMe z3)w39&k!~GPBxG>b68&`9OVt|+<+N97`RUH&9!q_SqqONOA4>N@Mq0VXt3 z6|q7qwj;p_2+Ou|C8D0ZkL6aa07u`anJLY1b(G{VliMt~ zl=9b1O5-7}VS^@1x%OA?wR6*0@^x>xu9L5T4o^lDW53z=oV?OE{unVqAZ$icXPH;8)I^YG`VF4Os;1XgAE5l+i zF?=;#jedsEXv^Sgv@`gLY{bjgS_Ud2RQa|#>HtIn{scXBFp=gY2sBm$cY|k$cxI1~ z9bs=oPprNIy8_S0*x9NAR#;k$yu(~jM2n0$;-m^f!h>QK?ok0p$@^mXo|#A~)krkr zD?yUN_X_NTx{%G0Kf_7U3uFW1JFF#iDX@yngp~yV?Fd6yS-Qa2Ve8R8#%=HmH3ik@ zTm&qd0jw;)f{79Su(E7HtwJ%(L6C}OP|`5<sC*a=sg zyD<`F0;X}s1!GbAQ0IXbw42UG2ObE3DI*)M@)PosN(m|x>tBKkaQym4`9JZ3l^(Mm zgt|k^Yb@)TntPEV%*N$gkWe~H}cTGf^)EZbz zd@7;xf5oOP&)b}JB{m2h@tw?W zhgQ-;5|b?yYC%h^Hv4!~EmZCz)}`R3&;}F13J!P;l{%WW$mcv%>U`D}uhYl~lE6~* zD1u7u$ZB@=gi5`dwZeHFROS(8;Lf8^i5D;}w*1DC6r739HfiN3m5xWVAvJ7x#N=+- zz>T^1lF2mv4l1uIYwuQ5xc08bx@7JHEt@*57^_U~;(K>kzj)*$F3(r8v*`z+^a;8C z1KeOenfS~2kq|d{p7I4jMwvC%Gi9T2cGWqk+<8L(`gySBza$K4vV<-FP2tjJN7(Xr z32!x8!j?Zns8GLvC%3>(c(v*WXo7hoSXQ0{l|NCixcFPB{K|rm?1Qi;IKX#E-HBo= zCkXViOJR=?C8#QziVbV76g1_YL-Vyx@dMMzu!l(HA4=9iC+MBy*QJNSo%Yu(-PT57T^MaSijYXQsj8N)X5uufX`8 z^93n6$6;~x@}H$gz?FguesZcUEUrWR3`ko-AMzD4Vc1Hzy&x(7Cae^xf)U9qtdCJH zs3=|ldy*8vK+(^za_kcv%0G#YAUT3-MbFS8>}z4)0S8z)EQD4S0xUSeU1(BS4l4-| zHdpt+N-|Znvc->Qki9{4r!AfLG}lt}u3f@&lo*KawaJsBmxV$`^;ry>(gebT2<+}d1z#8b40{x!e56u>$|})kK`-CR%25{!V%R|g zNddYwLN3(;bvs82=r5T#eR%7C@cK#D97P>jmSYT(X ziPce!1o94nSZIX4;E2-(j2rfi09G5+oP3tg_e@5oQLnTVZ{(80 z=VQg;+qlr#1LIMRxP6SNSR(Z>SD#~u#n9Seby<$BhoKcoE=DeMEj z!){U9V6{<(4IBgZ0l%WB1B{TTx$Cj00BvN^;k8&I#T3yv^A;6SB#86Ck7z#qDReGC0xNE6Pcc!@Sp!@{u&o=6Of6xC8*Y`ZW&@U4BB7y(W68M1sLkocX2h_-XlRYWZ*Q(eyRY@%7nY;HTs5heHSbj~45fm-`}t|0^W$-v3ulPV0mJ zFAnMTXXdp`@gKP3FFx|X6Mydbi@TwfD-sT`gZj`-3%ZM~+R_9{&<9ALg%lvrEiHP- zAX z!S}fKoLMc+)cdUcoL}1A>3=W|aP>MBnSK%GK;vX3cVkF6_WLO(-cJED1^s8=in@JK z(eU}wcqO00n6eAoQyP30#4NaAS`_P}6SL|(=Sjzx!`)3_dUUb6J3J@CEpG9t`@96q55#1&yW0` zV{OB6e%`!OtzKiXfpFAYuly1TIRqvjs(o`Rf(=>BA)*q@!^8j}&D22cUa;EE_RMcD7a3VACE z!#dHqNNIcsb_<<>Y)=WrdeNB(t&gA!uG6vW=wyU^m!PT-iSup4Zdem)gm{gaVDTse zaea3g`ei!8SbQRXpP;R%%3g06Xkbr4(Tpb`F=_;4Xp8`h@F!qU|1Jm$tA($d3iO~K zcAv!skP`k5zU~2Zd-y{5ntSJ>J1w@6S&y~LdDv0iwOdLoKMsuq@qmC@bl$Al}w zXVGYVmO{61a~k=sx6n8IRfOt8;@E2}RG<<5EK(|ciIs+xabZ?Ibri+%YRVPwgDFrO zS8bV&8bZjIK8qj01TGb3;aiZyF-B&4keLEzC4)p-9Ca|-pWaMe!B`R<3LiO-VHgz# zA9*)&dell9EPdH=+wg5hXOtTRZhXak&W_;79{ItM6Gu&WUoSGC8z%mT*AE@&Wy{+L zT`qAqN?1RBlHm0Nx-RaQLLo@Oh6At;JtWTK4&*}+OG?K1gX8CdPdMWo=OQ@Aw_p`( zH@a%e6CfW^55+45+sHWQcr=P6;%eB%VREEQ<~gUUJW)Ucz0mFI< zr4sy0+_tCyk7nxc3GUIy_qx;R$%E0%-Id(AS@W6Z&Q81)c|pwij&DUtg?E|$_NDQv zk`=51yB8TzMYC8(?Pz^+MN^}Bt_!Yb75PNl?k3;m6)lL~yGQk5Z{eOOo4swr)O@AL zuRXlRBC?V2=|0LYccit4EDUsgmn>=skU$v{`IEirXO5cq?5SMwy(3>D^D407$0kZ7<)$xXq2eE;t^dD{HNhtkXQ8~~?2KA2%Q5bK) z+ju3$7Chsw+VU*^5t7C2v$&IlBEj6~9i~YRNG=-?es4vRCepVA0nlYocKxHq zev~)9k!rc3_Z8muZ#(QJe}6sPc}nLS6|?V|-m^~@&A{$%4ZV2EVouM!vFJx+zwOIrr_IhIm)2Q}3@u1cBhA*eNS^%Qh^AF5{fTCqu_AF7)J0wYv{bE>m_JIT$| z;HtNKr;yy~Zz{PC6G)28%Qe|M-Ue54?;J7Qv6|_`^XmG}X-(o=QNpDW&nc49c*VYD zK6+)_Q`D|*-jkpIB7>m0xntdRo-~PR(dko_By#a^DLB?ei7ZSm7azM2xII_DO8bn< z9)-+1b@{z#>@(6t&9weQ&Oc{qwi9%qv$lKKT~Nq5m2}!AXj<8_^Tj6x}k!laxr6$-&_ii^9&e*s^mL>$ug@aW)q-hM7`>yy=5~~Qfri~ytE-GBIp>^A zEq;&ePp9slZZR#gFmblW50;zggQ8CFh8?%*z9@-A+2J3h$cFX6@+zx^(MOKr z=1#wBx*weyuE<0;pT^dO!9v+Gip~pn;x$|D=2p_)id3Bn7?q6D_-(#bl*Q58Q$ixX z@$F~4$RH@(sFqRY*B5D8R27N&{T4Y~dcn8eN1v5k{)0`q_Y0t3wZr_nw}^MA?gxiz z?+1veS%(IEN*S8%1RdyH6lCGOmU`?|Z^EyaG3D6OwKz}Lr%2}dH% zOI_DvU4sNA-<{2x=4nb-eMqEl8$PhwD6lZrYb;TN9om?v{Bpt4sWjb`+Bd5;`yzi# zbA310_(z6976eX`$xBuqpBf~I4%97$u*E!rdCXFi4CxQ(q%~!aM(nm>?cyJujpqPK*3;pTp0I+Iti7%>|YFmIN(*eq6%kH)&e--xWT@Xy%Y{E8`&%K zUcfrVG%U8%VM!KJ-eT6NXj1=lyQkcJG{X=<@}4M|+DF*lZ^ zu7s=nGL|*3<_x#?%_UY+g))3Po4vR2EYTbM)vz^B_V^XRgf<7`ZBzzr5hQHY77I`x zaR=+OFaf(G=3&u0+`#YQQxOfjTyQ%)H0qp_8k!!a8A{!K1y!XkBz1b7QEHHH2!;zB8B9^IhDa}B-1>)yN9@PWP#^` z>()qOpou5>ZayLo6nUsVEJbz(`gyhu_aZ8Rqh4NPGeL5|4}Quo*8|1C--Bx3Xn_Yo zYE;*EDqv~|7shyxBiq7i7&77h#lSR2_I6*ftr$n(xKf)PO_x9+Ph;Pqi{aSIgVjy9 zhQdx}Eu&*lm3~JQ=>T+k)39Ud z4b})bK~HuatPwK>_j8V+)ZP092@*N1)BBC!ewiCaBE1tB9`MGRsr7>2ON=o^rk>zg z-c9taNS7}ccLI(W=JVH!i{M~Zjel2s8bD3vZ;$&Pc#Zk+#}X7!<(G${!DJ^|`{owE zID>{trAmTBS*fT@$e$S?a1hvX#jmj?v`ugXa~b7Dlp(9O{Dy`{7(sE5quV14kmw!r zu_fVbmWG`;~!4K9|Q~l3XKLUU}(C|zZ;s4!n@Gp_7>K=wmW^iA2%Yv zqxb(GF6ihqZibKsn@OazvcUI$Kd=7`*PiZC7()LmJ74G$0BB08mzdXS=|l`AJbb7vDmk1DCKrmhFK6 zzs3~5wa0)n;E^xtTt-|0Hz;eX1Q`OVESJsL z2$)AczuQzszw;u_Kk)qn{SjVIPauxreipLypR9G^9slPdP+lSi!-C&v9m~H(YGRiJ zUekKRjLX&X9XIZcvMWjQaW*SwuS~t?HOX=+;u7PsFT^$$6k-GJh93HG;IHQ)@%vu1 z9^LJwL=gz@pmhPQ)KEbYc7YsB%jFsKJwnx^>d-{tiikdzGjI}Ljuarz5Tp3tqV;)t z;89`{dqh|Rlu}sS!q`_JIQ1N&05KOHrNJoQaw%ZL=v#a_38#3@|J+{%UrYE3KmM#V zJC;j#MYX7FUc{;(1Qcw5-zbM zegj}UZWf{r^OuT!Ez5HXlgI&1@hAR?cJ*OpiO_gr4a!BGpdHHzdQGdIxdDKrapOkj zw;(@xl4T7e4GaoGY&*j)f~AB7G~>fz=Oo^YqGzW9dH(PF;#;M^0Do zT1G$OqE66`<;CkZrToOdrsboxCv|&fjBcOSl9->fj12U(`#AMES`wo(>95uKp#MW19BENY5RhO34KX4OD4LxqJOk(dY z9rc>4m61|dEAcbY(=0p-*FGfM3iG{>C{fnz4$qBlZ>5&`OizE*5=@&OU=lNQSj)6eoM`up@2p6L z)D@1J-uJ_gWNfon@_8Ii&Y|o)>@QDOD`?%epB%`zB8jy4BXm|Ye}C5Y#o>d|dgVuL zS4Y@0rBZ_8lKCunaxs2R?iyU1n-bunPSB3!r`gKM1C(o8=Q%}rvqOyxzF}A$S|2fP z{5axTjU!UBIcDFDT7_t5v%|CnjRu@amfx^#L(VytvhVy}UA2Nc>90=h(!CamDMX28IX{cB2og0tDtwwF=cd6O)=FTP;MvD$YeT^$Ro zD+sYQ?s;x&-K^ml-@VZ;t>LPR^Ce}wj#@*HmWwy+cUO&isr6j>(3oRYEYWA@eZ3ElxeER}>qzH?fbk4B12>Ckqfu&Kv(t ziTb=A?qbgr@rdvp(%>>lSQz^=*U_d^XrEZhso&-+R!D8->@{l@AIVq`!pu+b$vKM! znmdd+Y6WlOPC2DOt-6-_)xI_cfB((Q%Ahf>Uis#1`v^smR7y}>LjMNsj%Wag;3OAy zf_5w?=rt`TQ3!Y*X=Gq0G6VTguLwHH@=A;sm>Lygdm+vZY-bvJ*v7_#(<~*5tLQT5 zfDd+ov>h%*6IAx#f4i2dfuEN)XD=zoM9*4%@`Z`Ss${ZlXO0 z4=sx8ayIlhQl$|e;W+B`xF#=tt%Jl5X><`Ea8aThJ>DSD_iUw7j~@|Wp24&uZJk1? zyL!~xrauH?&py`4`Y_DXPk=^hBcJfF~iV|fyR&=BYZKYNKy{5C`U|JLsT30Dik2=j|*Bm?4 z$C}8_t9el+Ku*(tsEcjY=XC}bG!>j35&q)c)0TC)Ft&ZK_Q{qj_K9J;SDo+eRY)Cl zn{a8c_ee&qpW3-6{p6hJ@Kc>iH`NLlV6=I|?JJUkIEDI*+x-2DQi2-H2KCC9r<*ko z-;_!TDwEG=K_7&Cb}_Zl#i)xqL6w&zFkZ*UaXOX<(L=JMqpxXI1ivXWVH+9LdA}{` z3>!DTzn50198$75*`XlclId&~xBXS20eh0=>@|NB?Gd%_xV=X8(5~nZ+tGEyb=71; zkEJGBl~bvsUZMK_rN(qP%F|}$ykaU*u6-9FTq|g$c5F!HMu>uG_l!A_H)7PI5-ccz zYhj)4wY#}@Z;Ajp>oIN_pQO(_5mKRT$sZA}i~L{gy$M_s*Y-G$tyaZWYpYo622|@( zg9(HzxG#wNf>1$02_%T@AtC#0S%I)GB8XB^v_?g-iik^HDx%d2BG#qa)}=+OZLL=O zTHE=bnOh0^`ug7QyY~Nm1kcbjNRzFXDfQ$*tOvSpmEQO$iWKa%*-8?T_HpQ1)_76LlrjM`5@ZfaI=n=um zKhGVPF<>dvnI>mY3%yJIL=|b?Grn5;?O3bDbK+O;t)F;Qhw}ofx(1BVRdC;Q)Xnn6 zu(y*d6Xu=9)(^Y1(LL~WB4hZZjpFcI)Pm9Ey1Nm-kzGd~U0*H@CVqW;?uNja8vNnV z)0JJ~U&C*DF5g_6v<9p6DBj$p`%eFfd)cNtmQU0d-M4I5n|?@@;U2Z&#k}OyCquec z3O0MnzxLd^ou(0FBuZ%W{V`GwWOliXH)Q1zFx(^9&9he9QgfHuKg^;nJQ-t694Xe; zp0lNSaAs-aE?>(y&#lv*{UScg#$Tm7**Yo5PxPt2=-br1Z^tgff_~UnxPGD-Yj_-- z-8EpL;e($>X4TDFqr)H21qt(9wa33HThkmIr&@JA;eD`bm7bp++I2VLiDJ;T31Ce8 zq&RgoWqX(S0L6%}ODbxUq7{!?2fjC0y&!ec?a=Zj-7Qu8oqg-f_({#8dk4yd#yZ{V z?|YZtu|yeqJg^t9P0z>XJzQTT*!+|6hetk8d<{WH!UU(!krA757lGA?%T=B*Vj|eh z^B_Jwyb9YtjBog9_IlNM?pY&u{Ir!e{z(1sc~fTkiEbz^$3GH$J9cZVSH4}ae&V&{ zgZ4GkgQh-;-<%dayKBH#F;}d2=GV1MeH)+Qb=9Wt{y_+ejv8}V}D>+gLuwOsl`;)HVVDP7|Ea?iXW6Kaz}<)3AV$Hysrd0|-8>KL^Fr^yMXxrD4RAAiaIR`6ia!GT zK1wskhmZS-=){_#s}ykm$4Z8bPh3ASKJjuNaz)pGU*hWD%!#a8cK1{|DwH)1Avwf~+u<j>SmD~%1XNQ<^x4h6HdqeJ6H2H6OyuV~^dQ|=ekDg0k%*)Dq;3-ZHm!2a zCu?jV{`-&4&$4w5cxzkwXXP;L)onJOeGN?d)bcZR9`O1zs*HD{NPRaV?Y)B^|DZ3I z_S-oB%nl+j=Fap3Sv1>9|`; z8)HpoJbp{YxnwYqr*7?e;S+2@)~s!*7c+D(=J{^>@zQE7JPx*gcSWW(Z4kWAztz(K zuMC?neN_g-8iI`EsP8-VF__uu!l$BCLCgyS3%hy#Y*>-<5}0`3>2721q$ZBc$4mA5 z)gGMQ#*?~I-Fa?LYq8!9v+>Kas`X8TpXgCh1b&(NcI@VL7L&Va{lpJT4yT`mm-_j6 z8KxPgx>;`&q!oBu66PhYO5AWL4NSiL!nK>StfBJE&-2oX#o^;K-pNcVyBpzQDa{Bd zDVK_j5gCJv17m76cgcPQUE<4<7HOr~@OX&Vsow#UZ+hZNZGPrp^+EZUhThptI$YUA zWP`~!DYcI5o4YpsU1cs2l4IJCuk<3Das-h7cB4(Tt3G? zfMpOou}n(WL%`ek_8dn?Z-R8Lr+}*aWaj_Rd7bmeRGCz>2mhRE;PUD7=LfaNVSY1S zV;7g-_1eZOv+s{S46lsGxIM3bNEI;t<5W9AlHED;7q`=$lNa)7ANUt|W%SMX)RA60 zK_B?9r|RPJyT|?S_+dQn|EgZWtIhO{HeQ|b{_|g*0EKbOe8Twum@np^*@^srsQz#J zHGd59A347gN3I~;$a?d6E=epQb!qp;#*t7-C<`n}@;w4vX&TX#`q&t!$Rp~N zXTV?hJ~2#v2yfDr5HIKl5@tM`*oCzaLSrVe410~dW62^6`up(akwb)npQW@JL7GMo z*#?Y1ktUE|ktR;}Oq?U@`%|UK}08VKmOa$ zZ}8t>QBC!TMEo&Pgh@xYVt0wJ4gI()v8%)=!zmvZ>=Y59$AkwAyNGlhcWkMln0Q}% zW5P@WP8`&%nzBNlNHnNtPXAb&NHnUR%p9Y^i62sT%neePK`341LU;8s;;gc7@D%me zghAO55(~bnsY-oVxcVh>pmI#aX!Q%^3rg@)s(vAUR1~fFUiB04gW_@Rud1J6o2C(L zS8v%JF5B~tv~Hf4@MeMs7T^np2BLS72gjjXOq?z~&&9N2{Ka)Pev#%o!-#S}Q7?_R z;kR}7#?tEJhUx3pPfXOvi9>6Hrb@Is%-^i-8c?UJv1hJJn70+%Uz%9%9+-`T)=&{XdGn$*;_&@gcSp+VyPz56_Sr?{(rRqWj+Y7oV?MwSR}uML;z_c_ zQIcPqRA+42_(NWt;-=}P@`9Yf>J}ru=43{bu7NyX@;9>?#|Tl$49Kt7nS8q>3cq7n zMv6)v<7?A#c7Ivb2I_~B_sG)b9mLF%1u(OSAfthHb)}JU%=81O1o^ucyPIb(>}B#@ zQ{u?KrG7##wtH{}DV9lui8d{OCg^*aq;nJi}3=LGdRHwM8Jf{kbxvK1}*r4bV zKSbr7axSGd>9pEUK1dm-=%k&Nd^L5j`jO^Tl0wy_vun;Ld8y1e+AlPE>1Fc1syh}R z{I%3v)!Ov_PI}S&`fPuU(kU=RCb|Q9=GO_R?ks z?gB3eg6x^>nnUK-5a#Q-GrM^{#21+#rR^V6tS-$WAl0L zT=MuT-F6#)7#Xp8|4u*AY+}di#_D@xZ(*m3hgPqj=xsP$G+;;2R8m)&|N6GNS+g~@ z>H9Y(%oAxQn`P_W10QQ7c$ac(=sEq(6l|?H{6oXW#LZw-{9;%hFDWgTQrNfgpA-eg z+`?}pYqPt=k0V{wCQEJ7DN=&1H^eF4CuwRE=u%BanXb#5beZH(-H)tyHSFz^ck2UG|Ow1Ze>122!E)Gw} zC*hxy;CnF#<1yxPXXv8!LL?u?*d|Ew?2m|*Lf(*xP#TZ!6wo?+cW-@p% zf*zcziN6&rG}!o`Pq|s}SbuNqvT2$EqdsWrg=r)5^R;!ec+-B&>7z=R=QXt|`)#Fr zVBTa&)}j<^=+N=^GL|NZ!*j;oOz)p~H=@tjuIY{O<Ht9A^$TeDIW_;cF0?V1`JC?7;ewf#|Vr}}WvH68(SClp*NYeVtcLt+JHOSgO{cOp@384hn-K&fp511}Zl5fS5u7O%;^OkG z-_=hv#3m%YvGo(XT5E`fSlz4^<40Iu@Yjzseq~6;-2)dIpXg8G)=-Igg6<~VV3RCa z+Ros&&$o2d&Nq}xYphm{7W}X?vSzEtYig5ZIWMZC)NzXZoB?VNb(793^QbyNYsSMe zW7KPOLZc&Rp=uJ$udOZcOTDFAn?9weQR$&8ZAK6lnz7pqr)@VFdLd&(K-N;j$xDSJ zz#D;}jsL=_h*ih%dt(nZ2v&85SySnW<3%45K~v+7zh3kRuGOv&gA2x+t)ZiKPRo5c z1LoVdU(cSMbvNR|wsV=%{Br5L+keS8v??%WM-`dzS#g*6;GHu2xJ|y^$ZM zNZs8j+bbJhsA}hCy`I^mTXpc=ObN`)1RS}ZS&<_&E%hDsI1uvDYP1hfe zEIPZcv>8EI(8X@EBC&UxQy$b8hh>a0-T}WWf-vQo!8g_xpXY|y4aR9OBlVI!-dIuS zC;Bp-ZyZ;6Z|r-vW7Ip~JbGg4N*N1-rncbU67!1^=KTlm+CjH6Nisn_A=IW)7^-d!oS14ca=-)m(`LV9SV#Ih)y%Uf1*o#A9){B z>&LZ8Z|iT6Z=a4+ylg7RCY*vXKkak<@P;Pc8v7H&t$H(Fo%toz`-ISFvKul!IC01F zz0Fkc;?cF~zLqamkJ($=j37-T$jaT$pUPZE^kN;X<&$3EXh5)==SP~e*iP`P=rx$` zCd|n7)v6MX*lm1QE%=MF{6rC&bA@mnCO52bZhXM!k?{4b>9-n7CEqa6aW9mky@W8``7sk%i?_ zzvQaKlB~d(%;fQ@v1wi6M{4*~9XK30PlFOedbPZkM63N%y6C)WOFE zW?Z*&Roxiyx6WMp`2G6yJC@v)4I8Jy975m?KDdqxo zA}9gD#F0}i%hVX@!3nbjs`AM5+zFOfl+~o4sKC5BzApu)zj<2d1S522t7EFxBo2?Z z92q~$d^aM+v`wJ0luN&%4)d1418=i2hudoH62Hd0jkh0!>0?#-yl;t9+_j$a*=Pn& zq0NW)p}9%-$g1FQEMNy(Z;i6RG-Hgl(>rM(#5Sv%Gs#lgj3AWLWw%)&+Wex76wEp| z7Z-0sMP4D8eh4Ox9BXLEtsp!&!wsB#8@R^q>&qeOh>gES|4C_A!Wz0;-FP8WFAh&u z@4mDQd_IHJ!!9q^2gdYPAGVJ-L1s9?!q1u3tZ`1Jh0Y`4>OH zXz{Xo&6lTjG>ss`K|8;t^S$a@JW}-rj1&kaj(md8SNj;wbF&C6)vCES_Aa$PaiTJ4 zYK>`sthXXzUbf}c=uZ{R!TqfRCC8N3P_^~;a#|@4pJ>A(UrN0j5tO!f<)qYdY1j11 zWI0%#7t&Ux9Mg1(*V?L*Jq)!;9Lu{2Vlqzgv(Z0pqG_;tu5niUJ#bA8G7XkLG761T zOta<3jce1pn@%S6F_l&AqBbP21SPi`e@yZ+(KLdrIBkANXIFXF51BY}uwk^e5|ljB zPy(r(!3(P|RjmYvQ=0Bt;&*u0fIv;}Fu1Ov_cfQN>p|Hf&Gt#t^mikwRM$msgVOU- zeSJEC(#5LXJf6Nw{8sfk?{`4?b(**MkQhV3)xNh<*b8~t^ zkN?0_lsgQ1{5?}#VKh977n(ClPm@7Y7h4ndz6(8mWZJTeiDq$lNZJQi%Av=HroDA_ zuQ@PA0`i`P>5(&Om%r=;J^W$X+3S6vNB@{s^~G&-Y4gu%*;O9dyaikyhi>glR!3m_es&Cac{$6T@e|0Xaw9om-m4~K#IfY& z;0U8+>2$d@^i|`hp#gGGv$0`mH~HO&tH!aBFU!lN!%V$b4oC@%Nijym4^wuD-%M7; zk5<|_=WGylvK zOMCwxgTp*NbSKDudW7HahD(wy8hUf(LAj4=F7;u{Cnz=?36kJLAWoD@}qtZxz zW}~`ZZX*Y0-q8F;ET?RlV|1eIZl<)%QcPYJX}WIrqqaEY#^ZKR%k|ph)Z3X=)&VCT zlRYypSb|z=iD>&)bN&5sxG-G^#hE|Dx}|lZ5Dy`+Vz3+V5CZE0Lx2YczD*7cV4#`| z3J!r{IwfRgR0#PHB9ZImArNyr0DOHR;NQz5MA;$aOXL$=UdF)ph%F9g{}S?gEdxu* z0VhJp&SW+uo(dtmlF?+=4F+!zIFy*^I_wZ`nC6m1D9R5hR8&m)}arE{0_1X`K zRJ}qs;KXsFzrjTl)Dl2`Z|J4Ux^bHE!F?rE15h zN;1Jzr5zY>fShkyWXOz~Lgtu6u=|u-A||VYeBdIy6W%++ zF-nYuW7pGeh^`xQG13+k{1MiIueQ|7U5P&US+gj+3#GyaTI6K~)Hy81GT;QCYQ&e> z>hDJoTk!mJnm&Wi!!Mz^C3K1P_mj;2#M(rf9%M8TDM>6}PnYYk{uC!? z>$z1#daPqqmG_g(%GevC7G6vK)|7z(T3%wA1MUqWZ}0lo@XV-l+@|#o=$A{l=gVfB z;Og+O;teL~mp;E_Eg|J)Ndg~BpmvMnq_DeAr@CGnDE?H@A|G(#v|obaYC=#;mS30D zkK(d!)QCdVEf7M`+h;UZ8Ow6!^p7x`OiZhMV02DW$;gS0QJ-gyD2bbXLsXWzs=R05 zzC=3+BEfg?V0S#RncPyoVb*Ky|hLY)Y5&GVy#e+bz{`3eQOg0_4mCC zca=4YXgVve^P1t~SoWOj(wNO&EPJPM4R%oF7}aQejHRdE5cSKb#9n~A+0%w$m2ex) zv;|{3;WoOMwgl^H6J>|n{IP9m^0H6U-oeUjTO51RhhcA6uh)*xx@IVY5u`a!YlyW4 zwTv!UW2m)c-Qeer#A1x~_cvs$$0T5+2+g&a@b}v&DL!73f~+fsA=JToQ&r>wjbjvL zj3zgdH$>G&4=go(V8C|j75(>FLBVIJak_!InNbGgc%3b;UVhNzqraH@8?o5h6U)pI zWpmSZV7Zy{vVgQ5_?omWj+r(gk!QSKd(AYT>;uOi1Oz z%~(dhL&s{enV8yuqWeyWnjRXlc%h^GlPPEI+blU z0&9V%zcXC~*4{ha%d#f_H)7H0_ian_MA?Tb=Y{XM%!DQg387p3RKXrH;T9xYSk!s>ooirrN4-3ssA2hO_ulU0N3L(c8jX%o6Yy^OD9~4naU=AFfdP7LSGRKMFtuEQ>G}pTK@)q7W&$7ax-=yeT!pl+5ROGiUTze+{VHW`D08>q)~W&tx%lt<8)=6d-~;=_4K>$MN`aY=>x0Vk~31?>#T+}DXrGq1z5Zd{`lr!6Py z@4skjfpqOOebhAEjCU7 z#iV$VQItKDGN}qddFRR7$w8(q4lOw}A(FaYyOwNF41k^=Llzn9p!8HC;hNV-WZhVb zk1Q^O=iXv$Z1GWwrr$LjD*WEaDzEK**U4S1>4PPna9@6J@d}-*yCFJioEzH-8yFBq zyske27Rd@M7Ml;syJB#|HdFQTz4{OF8DNpz(`~|G8Y^3)4NYAJR#CI&z2u$xEspKl zOvx{r>$Pv{Zw0Sb4><7xwr1`Wbx_L|LL4woopoa+RT*G~p(E7zWKJ^-9p4$}2X)u5 z+&SN4o$RGxJM#8`h4O}BoMRanOp6Q&jx1_mK#qQ4WfHI_#kW*7gTWL^(JBLU>1>&YU5 zOEUcYdwibe{~9~e75;dTmuvCL#5h-xKrD-rN~9bKpC8E)2zfG&kGDX;@fAp9(cUs2 zNtCy&BZt?&M;Gak^8c^~=FC|vlcY!@<7MtDS&Cw1Qlh)Jw`<_!MRVMzyU&^buD|=V zK>tOH+^5Z7JkQm&d$KGg0kVSun!=sy+FkG3y?dlYA%o<9in#7VShU1^U}us#QI_&| zdsn0+r6!}j+}}TdD}#o$Nr}G`X?Gw|rco|$M+pvzyx|MZiAs@4lu0SeS4z7JA=jWt z#1(O*-a>BTSq69K7Cz>ae zam0}_Uydl63&|OUTv4P{*pZ#_|L{HEUNpwl$GG@9;(s9yxFi1e={mTM_+Qo^)Di#N z5&zo}|JxD&`!wanv+K}0;(t5he>>uTJK}#k;(t5he>>uTJK}#k;(z})v@ zNK=m>rw&1yMvy&)UC-t`1M&Hf_-4;w*R%aUozZT6n)5sqALtg2AgAu1<$Gh!MA`V> zoNY7JM!AI}xF@MLDAO#A>#X&8H`5#tzsUGru*G~buEM@MIL*8_ZqmA0ORQ!xF=w+T zWQDmY{@PAe;4zba1*dNIf}6%oQ8bMpE1Pp&7}Feb^viNf496zBg(J8pX`-!;vQFx( z?QV@UuAWq3&r3T^(vv5xyPvj*G)&Fe{Bp*}#Pq4xc5cs1!&9bk>Q-k*UmrPmrT| zUC>FBI7 zT0ec4TR4KUXnx8&I(zk=q$SCL+9B1Qwf$1w(mknOWW1XCSTFma!cJ>QjI;ZGp-sCP z+xWqxbptim4aaxoZ0@Cc$?#y;wVjWZ>-44%ICa-jaebGaG>stJe!F#2jGQRN*}E~> z_z|UBID&hU$`oAup{BFeUG0kd!L?Zo>!n`SSJ=G_-(&p^_X~AoKDHj@HXDPm*&ufc zb_I(9xsRpf<3cT`ZcxfCd^IF2L6B|t>3S$;-T`&@T^W@{GcdPs1otEr+LmTd#yV?{ z+WwX~3ahZ^W|U?A42`AQ|CaH&VbZ#z_HWah4LO@P+WTbQg2v?b0lD2VP91_w93`{O zHrBSj$=TX!!@O-F&>Dh!l1>xDw!dIlWc-vIzuf|&eMs%9dQ*SDFwaz1&DTv@S7m;2 zHx&Hc{EBJou2kK%oqLGGRj(L0bqLZlf^2Kf^-4^0=;m5T#O3xdxP>Dqixv~5dHX<< zGw=zk%M=y%udvpV{qp;TwV1B-Uh<@MH!)SoPWiQ+m+-IhtD)y0NYepz_rqH_yJa8J^1Y|or8p?~67=Q)=_m|?n4XAJ>iE@{uq`dNEzXCJ-i+?hH~ z9fCBCAVcZ7{5t3gJtSN<^GLUF1otEro2G5=4Y#b#JZncI6crj`{kD1~e!uXZZR-c? zpgXjt4ct8d%h~K=d$am$?Ap#K(~50l;UR$_O(V!Q*KQpUBMu5uzfJX7vr^?2j^Lzq z5yt6jNDZg1n{ntG8g3&5ne#h7{}~NDUH{|98R5$OGb@0mr@*AUYqU(}BaP;ZIMEUx zDTl}9`EqzNZvjW*&Gi-WxH2CumqGr|G~RJ;hXy({@V}}7=E2W=OljSa{m=YhcK)OM zKMXSSs!jKL*4{_^77{lI$W=ol*e*T>9iBza*}NK7_#()VYL|}%q1cEzt2dw^$fC5x zqaci_))OoBu#^-*7Nafx1YyjeM#dh1#heJDW}Nf6%r?UNXZE-gQ|o_n)h9p^L6)M^ zj&`DDB-f|9`am%=7P4qgJJ^Z#w)GNm5|&{j$fC8+d*DR;r}n86b;`k-!g~;niy%w0 zoqg%VJ83s)mz<($1X;XxcAyjQEA12FG)Rmfi}%!Sb0W>OwanZDAz28rNNx6(6Kj(C z%P;Oh+%tkKmeWphqP=PCJ=+h6A;_Y&**Q)u5AB7SE8yxQ$YMRa&KX_W!nDu7xNoLu z1X;9pc7~JOF6_yy&%r!JklFw5_4(8FfBqp0=FAWDcV9Gn<~;Wii{?+CIeFw?VG*DV zme6%90)*9k?bZN#3tV|z5iH8&@wn_a&)v%xHU#X3koopy4+y-O-vS@@+ZVotT&}y9 zw=X~*yTu$Aa+%{oE}#AOWk?CR0(UO~0EQN<5@f%{%s1PhkjFMCx9EngO;rQ@Hd=W3&n;#{TxWY0=u}`EV3YM(<`ud7EzA|5LPP7k$ z#uIx>d<7zzSif;(<`=sR5gY>4s-l<-4hKP+Mvz5i?Er=# zB6^Ito3`1&;UGxU2(p;0J>bL)C9AVPOyzJ81a}X+&0@Cm+cDdSa_Xvg(>`9y;UEaH zvFtXB|I|Iy7VpW_9CdL~@%!!X8Oz}yxMa!KzN-EG;%qjweeT?2U)_GsIGRS=ETw1d z2Slbdx3BHu2o49qB}?|^T5L1kS+(lh+%7irh;!#IvBR&Yr#PpfKj!!X-&+`0UXqve}7(KI^lRE?9) zKh@1s`-Va6%204gGo7F5P;)p4E?IKebZ+`lwMJ8Enl+T~BNnLYwY z(+H0_^VvMyh+2$Zc1fY*a1dOwWSaiSm3*B>6RdY!HtBZn-k@LGGEH~x+$Mcu%M`Ge z5FSg-X)iI%AxZ8MHO3Mphl3zZBgmq+*-cLDF~$&emoyFsL7GO8#dg|HPRXC`LQ9sw zHWc=@+1M0;L}evSXd&+E+&M^|38C;bn>6tE(kboiENAmHG2tLg5Xa^A|8_I~=Z%JW1jp=ph^`aQO~`p2(vvgdPBPdDJ_hhlt={9(5JA>E&an zxUd?+5sUDHQs1U-#HDM6QaqLyUL2XTHSeY0i~L3@5BE3#$)2WUS{BZ$O$ z)*rz*y&bOF%!{(59LP&-K15v43M#r~sx#WNf?D>QLQI-0nnsX4|LJ47%?@E^Zyc`c zVj~ibT*s`g(jL(_Il;lk$U3RTi(bAxVtrIMt|L~q?3>7q-a)CBr7e+ifg|HmP=j>Y zL}+Q@vgnah>GE&pA6&7+-{F`sKRIUI^q>~BP16XnEkA3wFlE{tuDnf-37;+u?mKKl z{rCY3=pmN!vE!6;gMG>3Jkgi{dg6qF6rp^YV^-&!6k)`a;NTbSgT$jI)619H-Wq>r zk|TDISu<_h1M!H&pj2IY616TdsAX>YDAEdvKoDdJJiQ=Jdjoa-ap?7oBL)hP3*&02F}>)$nYT- zhPu=Q6}@D9KQd}JU0!M)kW{zJ;rN@a6)Ua|+Ot06eA?n_`a^enLq6qc&5y|9x3{O5H!p{)%se}z7;dco=Iyq_a6@^S-!-2j zf>K+|yRnzZprRLS=j8iHy8I_wQPR((!|^2T=fn|I(4MR52a^O;P)l$7u+*F2I75(a zq|M*Nu)~;&4%ZT$f94xxaBzt(IQ=KMT}yOA`^!M}JzcNjEJ)^4sVgnr4O9?hsr$(VwxekZ9qCchY|%9kcdg)#=AcdbtF%H$PpmaQaKw^9sT$+;o%4VWI!@CFGITmV{}(jybpCIQA}T3f>Wb$7 zRwk~HrMNGatZ=bqF%kE)K^`;yM)zk5&ZR`2o@4YABn*B&0`> zQTTK7e-6hM!!}(2RQN=YMQO9^5s|OS$3!zc(hy`Z+U$9R@glX$a1byMM9n;FZzH@g z?S0$~>>$YEJvHOn>}rG=EF8UB3Auj|WHFz$gAv+TRlV_7C>($wi}tJ?iqJCcuO%-7 z84+y9pVN3mh)*o9+82W$2tLE$^Qga_e586QgQgL5a`-&nJiDWKVKGf3=w$JEyl5iD0(iS~ynJ}Bd;qZJ3xF$v z;5Yyf!RPM9^>!7(1|QHN=ugCl06~cT1HhaI2O(|`j5t07`oR-`Ion&rlnn6V`MB~# z?(BJD*z4o#>dghngU1ID;0j&6y#WdK`Y=cNu26!2-a7(T872%Y43fg*iDOb}k+3r)lGPT~8KHo=zHrTf4dx;W8Abq20EYnx8P)Mzg<@teA0WhbLVtl; z8Z0*=J`)Nm;zOf6zN<*cgn2@Z4Tf`P2xrH`{(pS5?r5+>1OK%eXtV$0C8;Z7(E8sg zviNwd`y6%$PZa4R;Ya#%BKZOzPNWp_0m=B0@D9(DNhDE1K@^Ow9cKT3?KSD3)}ev_ zDGmII{XZAg|5`L-W?&Fo|I2;ElsUove~Anr9q$0_JAiNdcK|Rhy;++PtY|RTzzBv~ zU|<0=-y-H4?0V)KOg^y~Aeek$;XYM9LI0cE`IGy9I=uSNU*JB=fAYLVe}$|+9ryfyy7Zq!D3l6) zgnY(^lX0Yc8Qj!d9+$)S_K}E%0;#W5BIls$Sj%9qp@f9pKjh~L?{SI3fe#@#v(4>jsbk7u)o+v07VN5$mq zj2cvW#TjSoJe)=;3b=@^cJZ~&nEh~=@8`bI5hiyr z=Gt8Wt0R}MOpH$I4%>Pl!R}yQ@w+D`DW7g9r>u;Ub?33Cu&@83=UjfQn@_;H`2?(+ zPrwy}n@x0n;nNqqM5&GlEf&PyN@fZ@8t`HLJ^exkV!Z^Nwkn75Q%skzBE!O@sapSc(5#> zWB&i2=(giHvRvUnRDiZc1-?p|1y@qAEp0iR=c$;0Kjbgg$n?P z1X0|mXqbuc5%@-PxX~~%;Tt6d0}GP%b0q?qFxoc?)-d|YqN2o+QgB3g`|vpM@R4u? zyl5%MN6htR>IaCK`AC5~-$xn=YXyCvL;#cfKUym0z?5ec)UT3p!Q(6v3w^vhoEFaw zNX+{q^KYK^5z7C?{9tx4`G3!xK0Sf?-5dTB7RcgND-~?+aV9X|qX&A)r)dQLXy5OC z0fq#lc#j@;i3Va8xk-4G@W<-N+jAYn1T2G0)LkITh%H2QZX9VP9uj?bt))ie<0-+x zTU0QfL1~+Rrn-{ZROz+t)D|)j(r_UCRH6_th`NrP4(S% zSka9?GmOKPbK79=88H|VR6;DHc>D+H1^z@I8i+LN^IXRe& zGAMC_=&>z2eIQJ8Ok!D&9+y(b82hZ4;^wAYX)KK0B-A8GjiKs>DF@>Q8~12$&s`IH zm3mX>8rmmzKlP1fZc=sZOU7}^MBV8)+<0G}Ye`5LXEG)~-1MvBlGT*bch~2sU)a_w z1P4XxrD+coAq`)uUrl>KQF?8w`mQA(a_6G@tp)Hrab& z-g;qO2NSo(^rz8DzweJ(od0(lr)X-S$>~hFyy0g z@?3qQ6ID@odv5)y7qg1f5_L0AWfpvBge%f;bk(O=-(B1jX{#y?f`d2eM;4vILK<$? zAI;a1S08RUG15FK57OeX=d(?;%l*sHXKI6b^vKH}XENk$5?b@^rcMP7Q%>gTOtQk! z(zBULBVIB$X`KB{(u=scEgd*2n4vf87E(qzPs5mJxe zOyl$|(9P$YbFn(&_S_K5$Le9^Xz3E$pybbBj98pr7Mo1vTD&sSV$!K|Yl_nP#B<@s zI%~yJ@<_qKOO`1bZ}PxxmHCP0CukJWWgC6QC&r}w_UI9ZEg`-or5?ku*KG^PhACl~ z+B6eJq+N#l*=2-lsFz`4@epEeQiQ&#g1~bv=XEb`eHpLL9iZ24nukB!^pk#5$%`;j z6&a@G+6cixDYnfx3x*LcHpnIfE{0<7+x+1+NA0j&JnMTyY|OzN)Eld&xLr29NAy`E z^|+w-#~+n9Oi9u=6T+(7bGPctaq*_n(oTjQ#_>gox?+95bhRnh(yY6dxkYzwO}Xx< zb*}E=rd7H%W=~z;T}EA{>7rI}FjD7bRca61?r(4-4rkIdYKLXx86O`SmT&8lV%~yF z@FO-lv4q$pJV(+h0VpNFcn13zF2Qap&rl4PAdb@GIpn!DzSLkW9aR1fwNk&E)HV+% z!cuyGu!v5Z%F*q?_yS*re~%tsmN&NkNKJA3)I4GHaZ2hDYpz+Zqb#Eznm#V=14H%- zQ+ZwnG+Sj{X+A)Vmew1277LN6+iawX{&0tGFwP`ih9TTx>`x9P9&Tzh4zw`3KWePC z)WJ|5U~0(;2X+pb`mX*0ZmZADk(=vbNJs6mY(3|rL?ho4>Q?4`;H#RTY%7&gk8kiM z|wawEAIoaQM_2ENuT>4?)2errW^S}RLZf@q${kQ%5 z(ewZ552pSf^Uol(um8g!Guf{ydWyFTo_dNy1Cfq79NsOj!&ib#e4=;o##_wN~xg}Qw@($;_=E4 zpxAE?bwDZ7`WGX5trdt~MirvRsYCP{k0W}DCPdHeDx$Zq710ZOs4;ZMKZUfDYK=-C zrb9dNR6bSzZNX!x=VG9G6zn%u*f(Yyiz;#d zVnnaC0@2H;Li9Lwh+gAyL{HI#=($}*^!BwPdSMSY>Idh32<+q3_h}8N{xX{XVMJj5 zE1t6&VV6q+I}hX(aXh-(IZJ_CsE)=aG09Y;BR<3zvj$w=yg296Zq$ zlkZ=Q=(ScLdKp!S9;Xh`YdntVDVh*Hx2uTWzE(sp?BR5LY*jz;_Un>H@@NWjuo&niFPV;?NDd+irXjy{a>^6NM5 z($OPu;R`05JuKEM7fulm+CR_i7XGuydp~a97xRno&cSM1nDV-B$%l~Dm52~SL5qY6 z`?zt9N4{C=UySIrRv>yARfry^4$*5oj_4_x5Iwi6h~BZtKy%0WAe)ua7s;!>fPyj50VzrOZ%Qp*zm zVnnaC0@2H;Li9Lwh+gAyL{HI#=($}*^!BwPdSMT7$4cEtb7}g)h9- zV5$$@10&xSGCbm=wQ+<8-tlWnauEnTb-D)G%dOhG~T{l_ml$tKRj{RoE|+y&_7K{>6x1YXzd0QHAJn z>JYugP+!o;p`^ zHOs#rb!NfN7P8f|=(KLTCe`kRor&3zne64)bf$FotfVIYF^%_kn<(YNPfsao-Ys(r zcR8isxn|A2n3o!M?|5@nnDX0GXSS}&f}!V=$GeVXRoGk4{IKIZ>0gZKwN@Z{8C8fL zrw-9;JdWronh-s=tBBsdRzxrCA$BUW%8&!E6^Hs9+FIc3fzQiXmag;i+p$<~=v&$3-%rvdW$_y2!n$bx*q003!fTfFOx>_< zU(83rrK!RVVag-HDVm=)(8Q)Nd$N6fg?(V8Yl>Hie=(xhT7l?gR3UntIz+GWIHIR$ zLiF6OB6|B;5xua7 z@H|sIPMl_H@*iu6j2&!JF1(UfC@CYMO9(@+-`c_0L$*II$-!Sjrz$Eic~8jmA-iY7$Q?JAo9u<;? z?is8QZSN9JDKbbO#~QVNzdq!}U9Fl{&j#}3CM#z5dPJ=#8V`oh7epuXaU+asM8EW} zFy+EVe0t?Zom;p&ap(Z9+81*Z53W0<2vf!o^S1C)XhJ~!Ry9CXVIM&Td~ihLUySIr zRv>yARfrypYAn6R{S0zkFVZh8^whFaINwE_V*H}{ zDxr$oASh)^tqbHgV6c@F2udWIuF$G4oIV+B3E?C**?-#x+Z%~wS;l0T1nIEro z3-272WI3>6UyL-W(a>{cnDXj)9qEW5wUB)TJHnk!4l+wT773rBU zWn8Ogc5wajmy+#X#Jn{tz13cRX|rOY>r_qtkLMqhE(8-vwtQj4b*)=?PV$M!BJIAI zuM9aWGj(Cgm&mEfZ$q)F>#5(YXh^BBS4&I6X2kgyBYLeBh+ak&qQ|L2^cs&NdWt4Q z&+RIrx33k^3wyW-zo>X0a?T6LqlS^Dwl4Mj?cJYH@6OZv_nS%Ww<7gAd)mK7C)z0{ibM8Oi0nV3?YkJE-DYxHpo@x?~Q; zoBX{>&L=6s;5KCrUa`gC79MO>te64@x7E}o`ICHq2${@@`Boz7h_((gZ*#7@Cay<3_ zE&uM@iT;}86q!P?d{Jr&EIU)kmis3pDcM!AF3e#@EHo>~RtEh$uOQ>muIYk2YzaL! z5T1B1;)>fmVya;fKGV~JO~XfHHJny`mi9HnP;rUoi0Y=KELp_R-m~!W_Wq!P z0xUVZ3eO*ygz+;cfhx{pBdtGU^zcl)3*mv+aDoY|wiQqC=|Qei)5K8mRq{J^7;$C7 zN$RXdr_Y}@&`4^Hsu{C-Q*qif1wB6!U#^K))&%G3b!xpTVX0JCsve^rDjBM`X!x2d z(GtUWZKO6YzS8he^MYC<{g-0tT*i@W*l8iO)=Ssnll)=!&pvSz7|Yo!-aYNl7Xt8&e}3oyGJ|KU2zj& zlTF`&s*W0h%!ff$X2a*k%{V=LgdrF!09DP_hp2NvRiA6$Q@)1}6;IZ_rp&{yOeoZy zQF!6`(<%)c6nn85v$kXP3M)p>HyS1=o3WZ;xh_jN9Zy)Q*IJcP_)y6^`q0!Lu`AK% zF_~%smKUEwY*n=yW~6*ZysJ85pw&x>o2hk%8f+YXF?EOGa`r*(c{O3kD=gP=)W;1o zO8aYkQs-iHd6_0kaUZLx4ApTICQ#8khBuXG@wcj54a-xH;xmq3)t}P(LJw-xyXy}S z@y*{Gel&aus!1lkgi=_4sG2r!D3kjB>HT!YEsNZ%xk%&>{EQT9pmyo-VCs~vfk^PV zN`8oc2Au}o7gr{n!Do_QWd5`;yf-NaSi z)l@*n!o7g-^5S2^RuL=787cGip~NPVR-1Gah$Ccz=|%l~VkgwE3?;rM`oX>MJKf)B z|AE!ttA#Mv^bPob%K6aV8;$eRBXw8Y)|eXYJvI3QJYWT3j0`8Svw8E$D-%A{*A8MCC?H;Ue*==pthQ&u&SLnR9d zS!rjI;k>LAx>@`p;&6!{a2#a#an%K~23w_HzUl#RKFUC^x

iUO{A+_>y^r$H<>b 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�sEslb`{_o+p3MRGmyKk7StqW&>O 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 diff --git a/indra/newview/app_settings/static_index.db2 b/indra/newview/app_settings/static_index.db2 deleted file mode 100644 index a5440f96f2b16bd93bb9eeffe561ea1db8b93c25..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9894 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

KmtC<(>d4qd0zj` zNBA}wKNj4ZH;-@6%SnwtK3avL$9m(m%?PchW{s<8AOuQ)3X=FMu|7gCWpaB{xKn&Y zgN8f)-NikUnAaM*SEqewW0L7zN#bo~1J3nYNWcgAvB2o9eCFlUmg6mEdVFTz#|dyB zMXZ_B_~(4*J;l1^-{~W{7IWNZ9q?|el_VBd5Fd1%)$0f3Ja~V$eTH>?X;!w=5u$=( Tu1Tg_{HGecd?G%d`H%P?%$X-n diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index f518704e06..6ede9ec0e7 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -98,6 +98,7 @@ #include "lllogininstance.h" #include "llprogressview.h" #include "llvocache.h" +#include "lldiskcache.h" #include "llvopartgroup.h" #include "llweb.h" #include "llfloatertexturefetchdebugger.h" @@ -115,8 +116,6 @@ #include "llprimitive.h" #include "llurlaction.h" #include "llurlentry.h" -#include "llvfile.h" -#include "llvfsthread.h" #include "llvolumemgr.h" #include "llxfermanager.h" #include "llphysicsextensions.h" @@ -340,9 +339,6 @@ bool gUseWireframe = FALSE; //use for remember deferred mode in wireframe switch bool gInitialDeferredModeForWireframe = FALSE; -// VFS globals - see llappviewer.h -LLVFS* gStaticVFS = NULL; - LLMemoryInfo gSysMemory; U64Bytes gMemoryAllocated(0); // updated in display_stats() in llviewerdisplay.cpp @@ -431,12 +427,6 @@ void init_default_trans_args() default_trans_args.insert("create_account_url"); } -//---------------------------------------------------------------------------- -// File scope definitons -const char *VFS_DATA_FILE_BASE = "data.db2.x."; -const char *VFS_INDEX_FILE_BASE = "index.db2.x."; - - struct SettingsFile : public LLInitParam::Block { Mandatory name; @@ -971,10 +961,6 @@ bool LLAppViewer::init() // *Note: this is where gViewerStats used to be created. - // - // Initialize the VFS, and gracefully handle initialization errors - // - if (!initCache()) { LL_WARNS("InitInfo") << "Failed to init cache" << LL_ENDL; @@ -1369,7 +1355,6 @@ static LLTrace::BlockTimerStatHandle FTM_TEXTURE_CACHE("Texture Cache"); static LLTrace::BlockTimerStatHandle FTM_DECODE("Image Decode"); static LLTrace::BlockTimerStatHandle FTM_FETCH("Image Fetch"); -static LLTrace::BlockTimerStatHandle FTM_VFS("VFS Thread"); static LLTrace::BlockTimerStatHandle FTM_LFS("LFS Thread"); static LLTrace::BlockTimerStatHandle FTM_PAUSE_THREADS("Pause Threads"); static LLTrace::BlockTimerStatHandle FTM_IDLE("Idle"); @@ -1603,10 +1588,6 @@ bool LLAppViewer::doFrame() work_pending += updateTextureThreads(max_time); - { - LL_RECORD_BLOCK_TIME(FTM_VFS); - io_pending += LLVFSThread::updateClass(1); - } { LL_RECORD_BLOCK_TIME(FTM_LFS); io_pending += LLLFSThread::updateClass(1); @@ -1614,7 +1595,7 @@ bool LLAppViewer::doFrame() if (io_pending > 1000) { - ms_sleep(llmin(io_pending/100,100)); // give the vfs some time to catch up + ms_sleep(llmin(io_pending/100,100)); // give the lfs some time to catch up } total_work_pending += work_pending ; @@ -1631,7 +1612,6 @@ bool LLAppViewer::doFrame() } if(!total_io_pending) //pause file threads if nothing to process. { - LLVFSThread::sLocal->pause(); LLLFSThread::sLocal->pause(); } @@ -1693,12 +1673,11 @@ S32 LLAppViewer::updateTextureThreads(F32 max_time) return work_pending; } -void LLAppViewer::flushVFSIO() +void LLAppViewer::flushLFSIO() { while (1) { - S32 pending = LLVFSThread::updateClass(0); - pending += LLLFSThread::updateClass(0); + S32 pending = LLLFSThread::updateClass(0); if (!pending) { break; @@ -1786,7 +1765,7 @@ bool LLAppViewer::cleanup() LLKeyframeDataCache::clear(); - // End TransferManager before deleting systems it depends on (Audio, VFS, AssetStorage) + // End TransferManager before deleting systems it depends on (Audio, AssetStorage) #if 0 // this seems to get us stuck in an infinite loop... gTransferManager.cleanup(); #endif @@ -1853,8 +1832,8 @@ bool LLAppViewer::cleanup() LL_INFOS() << "Cache files removed" << LL_ENDL; - // Wait for any pending VFS IO - flushVFSIO(); + // Wait for any pending LFS IO + flushLFSIO(); LL_INFOS() << "Shutting down Views" << LL_ENDL; // Destroy the UI @@ -1938,15 +1917,6 @@ bool LLAppViewer::cleanup() SUBSYSTEM_CLEANUP(LLWorldMapView); SUBSYSTEM_CLEANUP(LLFolderViewItem); - // - // Shut down the VFS's AFTER the decode manager cleans up (since it cleans up vfiles). - // Also after viewerwindow is deleted, since it may have image pointers (which have vfiles) - // Also after shutting down the messaging system since it has VFS dependencies - - // - LL_INFOS() << "Cleaning up VFS" << LL_ENDL; - SUBSYSTEM_CLEANUP(LLVFile); - LL_INFOS() << "Saving Data" << LL_ENDL; // Store the time of our current logoff @@ -2033,7 +2003,6 @@ bool LLAppViewer::cleanup() pending += LLAppViewer::getTextureCache()->update(1); // unpauses the worker thread pending += LLAppViewer::getImageDecodeThread()->update(1); // unpauses the image thread pending += LLAppViewer::getTextureFetch()->update(1); // unpauses the texture fetch thread - pending += LLVFSThread::updateClass(0); pending += LLLFSThread::updateClass(0); F64 idle_time = idleTimer.getElapsedTimeF64(); if(!pending) @@ -2108,28 +2077,11 @@ bool LLAppViewer::cleanup() gTextureList.shutdown(); // shutdown again in case a callback added something LLUIImageList::getInstance()->cleanUp(); - // This should eventually be done in LLAppViewer SUBSYSTEM_CLEANUP(LLImage); - SUBSYSTEM_CLEANUP(LLVFSThread); SUBSYSTEM_CLEANUP(LLLFSThread); -#ifndef LL_RELEASE_FOR_DOWNLOAD - LL_INFOS() << "Auditing VFS" << LL_ENDL; - if(gVFS) - { - gVFS->audit(); - } -#endif - LL_INFOS() << "Misc Cleanup" << LL_ENDL; - // For safety, the LLVFS has to be deleted *after* LLVFSThread. This should be cleaned up. - // (LLVFS doesn't know about LLVFSThread so can't kill pending requests) -Steve - delete gStaticVFS; - gStaticVFS = NULL; - delete gVFS; - gVFS = NULL; - gSavedSettings.cleanup(); LLUIColorTable::instance().clear(); @@ -2211,7 +2163,6 @@ bool LLAppViewer::initThreads() LLImage::initClass(gSavedSettings.getBOOL("TextureNewByteRange"),gSavedSettings.getS32("TextureReverseByteRange")); - LLVFSThread::initClass(enable_threads && false); LLLFSThread::initClass(enable_threads && false); // Image decoding @@ -3213,10 +3164,6 @@ LLSD LLAppViewer::getViewerInfo() const info["GPU_SHADERS"] = gSavedSettings.getBOOL("RenderDeferred") ? "Enabled" : "Disabled"; info["TEXTURE_MEMORY"] = gSavedSettings.getS32("TextureMemory"); - LLSD substitution; - substitution["datetime"] = (S32)(gVFS ? gVFS->creationTime() : 0); - info["VFS_TIME"] = LLTrans::getString("AboutTime", substitution); - #if LL_DARWIN info["HIDPI"] = gHiDPISupport; #endif @@ -3308,6 +3255,9 @@ LLSD LLAppViewer::getViewerInfo() const info["SERVER_RELEASE_NOTES_URL"] = mServerReleaseNotesURL; } + // populate field for new local disk cache with some details + info["DISK_CACHE_INFO"] = LLDiskCache::getInstance()->getCacheInfo(); + return info; } @@ -3957,7 +3907,7 @@ void LLAppViewer::forceQuit() void LLAppViewer::fastQuit(S32 error_code) { // finish pending transfers - flushVFSIO(); + flushLFSIO(); // let sim know we're logging out sendLogoutRequest(); // flush network buffers by shutting down messaging system @@ -4146,39 +4096,6 @@ void LLAppViewer::migrateCacheDirectory() #endif // LL_WINDOWS || LL_DARWIN } -void dumpVFSCaches() -{ - LL_INFOS() << "======= Static VFS ========" << LL_ENDL; - gStaticVFS->listFiles(); -#if LL_WINDOWS - LL_INFOS() << "======= Dumping static VFS to StaticVFSDump ========" << LL_ENDL; - WCHAR w_str[MAX_PATH]; - GetCurrentDirectory(MAX_PATH, w_str); - S32 res = LLFile::mkdir("StaticVFSDump"); - if (res == -1) - { - LL_WARNS() << "Couldn't create dir StaticVFSDump" << LL_ENDL; - } - SetCurrentDirectory(utf8str_to_utf16str("StaticVFSDump").c_str()); - gStaticVFS->dumpFiles(); - SetCurrentDirectory(w_str); -#endif - - LL_INFOS() << "========= Dynamic VFS ====" << LL_ENDL; - gVFS->listFiles(); -#if LL_WINDOWS - LL_INFOS() << "========= Dumping dynamic VFS to VFSDump ====" << LL_ENDL; - res = LLFile::mkdir("VFSDump"); - if (res == -1) - { - LL_WARNS() << "Couldn't create dir VFSDump" << LL_ENDL; - } - SetCurrentDirectory(utf8str_to_utf16str("VFSDump").c_str()); - gVFS->dumpFiles(); - SetCurrentDirectory(w_str); -#endif -} - //static U32 LLAppViewer::getTextureCacheVersion() { @@ -4205,6 +4122,17 @@ bool LLAppViewer::initCache() LLAppViewer::getTextureCache()->setReadOnly(read_only) ; LLVOCache::initParamSingleton(read_only); + // initialize the new disk cache using saved settings + const std::string cache_dir_name = gSavedSettings.getString("DiskCacheDirName"); + + // note that the maximum size of this cache is defined as a percentage of the + // total cache size - the 'CacheSize' pref - for all caches. + const unsigned int cache_total_size_mb = gSavedSettings.getU32("CacheSize"); + const double disk_cache_percent = gSavedSettings.getF32("DiskCachePercentOfTotal"); + const unsigned int disk_cache_mb = cache_total_size_mb * disk_cache_percent / 100; + const unsigned int disk_cache_bytes = disk_cache_mb * 1024 * 1024; + const bool enable_cache_debug_info = gSavedSettings.getBOOL("EnableDiskCacheDebugInfo"); + bool texture_cache_mismatch = false; if (gSavedSettings.getS32("LocalCacheVersion") != LLAppViewer::getTextureCacheVersion()) { @@ -4251,10 +4179,24 @@ bool LLAppViewer::initCache() gSavedSettings.setString("CacheLocationTopFolder", ""); } - if (mPurgeCache && !read_only) + const std::string cache_dir = gDirUtilp->getExpandedFilename(LL_PATH_CACHE, cache_dir_name); + LLDiskCache::initParamSingleton(cache_dir, disk_cache_bytes, enable_cache_debug_info); + + if (!read_only) { - LLSplashScreen::update(LLTrans::getString("StartupClearingCache")); - purgeCache(); + if (mPurgeCache) + { + LLSplashScreen::update(LLTrans::getString("StartupClearingCache")); + purgeCache(); + + // clear the new C++ file system based cache + LLDiskCache::getInstance()->clearCache(); + } + else + { + // purge excessive files from the new file system based cache + LLDiskCache::getInstance()->purge(); + } } LLSplashScreen::update(LLTrans::getString("StartupInitializingTextureCache")); @@ -4264,172 +4206,18 @@ bool LLAppViewer::initCache() const S32 MB = 1024 * 1024; const S64 MIN_CACHE_SIZE = 256 * MB; const S64 MAX_CACHE_SIZE = 9984ll * MB; - const S64 MAX_VFS_SIZE = 1024 * MB; // 1 GB S64 cache_size = (S64)(gSavedSettings.getU32("CacheSize")) * MB; cache_size = llclamp(cache_size, MIN_CACHE_SIZE, MAX_CACHE_SIZE); - S64 vfs_size = llmin((S64)((cache_size * 2) / 10), MAX_VFS_SIZE); - S64 texture_cache_size = cache_size - vfs_size; + S64 texture_cache_size = cache_size; S64 extra = LLAppViewer::getTextureCache()->initCache(LL_PATH_CACHE, texture_cache_size, texture_cache_mismatch); texture_cache_size -= extra; - LLVOCache::getInstance()->initCache(LL_PATH_CACHE, gSavedSettings.getU32("CacheNumberOfRegionsForObjects"), getObjectCacheVersion()); - LLSplashScreen::update(LLTrans::getString("StartupInitializingVFS")); - - // Init the VFS - vfs_size = llmin(vfs_size + extra, MAX_VFS_SIZE); - vfs_size = (vfs_size / MB) * MB; // make sure it is MB aligned - U32 vfs_size_u32 = (U32)vfs_size; - U32 old_vfs_size = gSavedSettings.getU32("VFSOldSize") * MB; - bool resize_vfs = (vfs_size_u32 != old_vfs_size); - if (resize_vfs) - { - gSavedSettings.setU32("VFSOldSize", vfs_size_u32 / MB); - } - LL_INFOS("AppCache") << "VFS CACHE SIZE: " << vfs_size / (1024*1024) << " MB" << LL_ENDL; - - // This has to happen BEFORE starting the vfs - // time_t ltime; - srand(time(NULL)); // Flawfinder: ignore - U32 old_salt = gSavedSettings.getU32("VFSSalt"); - U32 new_salt; - std::string old_vfs_data_file; - std::string old_vfs_index_file; - std::string new_vfs_data_file; - std::string new_vfs_index_file; - std::string static_vfs_index_file; - std::string static_vfs_data_file; - - if (gSavedSettings.getBOOL("AllowMultipleViewers")) - { - // don't mess with renaming the VFS in this case - new_salt = old_salt; - } - else - { - do - { - new_salt = rand(); - } while(new_salt == old_salt); - } - - old_vfs_data_file = gDirUtilp->getExpandedFilename(LL_PATH_CACHE, VFS_DATA_FILE_BASE) + llformat("%u", old_salt); - - // make sure this file exists - llstat s; - S32 stat_result = LLFile::stat(old_vfs_data_file, &s); - if (stat_result) - { - // doesn't exist, look for a data file - std::string mask; - mask = VFS_DATA_FILE_BASE; - mask += "*"; - - std::string dir; - dir = gDirUtilp->getExpandedFilename(LL_PATH_CACHE, ""); - - std::string found_file; - LLDirIterator iter(dir, mask); - if (iter.next(found_file)) - { - old_vfs_data_file = gDirUtilp->add(dir, found_file); - - S32 start_pos = found_file.find_last_of('.'); - if (start_pos > 0) - { - sscanf(found_file.substr(start_pos+1).c_str(), "%d", &old_salt); - } - LL_DEBUGS("AppCache") << "Default vfs data file not present, found: " << old_vfs_data_file << " Old salt: " << old_salt << LL_ENDL; - } - } - - old_vfs_index_file = gDirUtilp->getExpandedFilename(LL_PATH_CACHE, VFS_INDEX_FILE_BASE) + llformat("%u", old_salt); - - stat_result = LLFile::stat(old_vfs_index_file, &s); - if (stat_result) - { - // We've got a bad/missing index file, nukem! - LL_WARNS("AppCache") << "Bad or missing vfx index file " << old_vfs_index_file << LL_ENDL; - LL_WARNS("AppCache") << "Removing old vfs data file " << old_vfs_data_file << LL_ENDL; - LLFile::remove(old_vfs_data_file); - LLFile::remove(old_vfs_index_file); - - // Just in case, nuke any other old cache files in the directory. - std::string dir; - dir = gDirUtilp->getExpandedFilename(LL_PATH_CACHE, ""); - - std::string mask; - mask = VFS_DATA_FILE_BASE; - mask += "*"; - - gDirUtilp->deleteFilesInDir(dir, mask); - - mask = VFS_INDEX_FILE_BASE; - mask += "*"; - - gDirUtilp->deleteFilesInDir(dir, mask); - } - - new_vfs_data_file = gDirUtilp->getExpandedFilename(LL_PATH_CACHE, VFS_DATA_FILE_BASE) + llformat("%u", new_salt); - new_vfs_index_file = gDirUtilp->getExpandedFilename(LL_PATH_CACHE, VFS_INDEX_FILE_BASE) + llformat("%u", new_salt); - - static_vfs_data_file = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "static_data.db2"); - static_vfs_index_file = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "static_index.db2"); - - if (resize_vfs) - { - LL_DEBUGS("AppCache") << "Removing old vfs and re-sizing" << LL_ENDL; - - LLFile::remove(old_vfs_data_file); - LLFile::remove(old_vfs_index_file); - } - else if (old_salt != new_salt) - { - // move the vfs files to a new name before opening - LL_DEBUGS("AppCache") << "Renaming " << old_vfs_data_file << " to " << new_vfs_data_file << LL_ENDL; - LL_DEBUGS("AppCache") << "Renaming " << old_vfs_index_file << " to " << new_vfs_index_file << LL_ENDL; - LLFile::rename(old_vfs_data_file, new_vfs_data_file); - LLFile::rename(old_vfs_index_file, new_vfs_index_file); - } - - // Startup the VFS... - gSavedSettings.setU32("VFSSalt", new_salt); - - // Don't remove VFS after viewer crashes. If user has corrupt data, they can reinstall. JC - gVFS = LLVFS::createLLVFS(new_vfs_index_file, new_vfs_data_file, false, vfs_size_u32, false); - if (!gVFS) - { - return false; - } - - gStaticVFS = LLVFS::createLLVFS(static_vfs_index_file, static_vfs_data_file, true, 0, false); - if (!gStaticVFS) - { - return false; - } - - BOOL success = gVFS->isValid() && gStaticVFS->isValid(); - if (!success) - { - return false; - } - else - { - LLVFile::initClass(); - -#ifndef LL_RELEASE_FOR_DOWNLOAD - if (gSavedSettings.getBOOL("DumpVFSCaches")) - { - dumpVFSCaches(); - } -#endif - - return true; - } + return true; } void LLAppViewer::addOnIdleCallback(const boost::function& cb) diff --git a/indra/newview/llappviewer.h b/indra/newview/llappviewer.h index 5332fe2deb..902b94d495 100644 --- a/indra/newview/llappviewer.h +++ b/indra/newview/llappviewer.h @@ -1,4 +1,5 @@ /** + * @mainpage * @mainpage * * This is the sources for the Second Life Viewer; @@ -82,7 +83,7 @@ public: virtual bool frame(); // Override for application body logic // Application control - void flushVFSIO(); // waits for vfs transfers to complete + void flushLFSIO(); // waits for lfs transfers to complete void forceQuit(); // Puts the viewer into 'shutting down without error' mode. void fastQuit(S32 error_code = 0); // Shuts down the viewer immediately after sending a logout message void requestQuit(); // Request a quit. A kinder, gentler quit. @@ -381,12 +382,6 @@ extern BOOL gRestoreGL; extern bool gUseWireframe; extern bool gInitialDeferredModeForWireframe; -// VFS globals - gVFS is for general use -// gStaticVFS is read-only and is shipped w/ the viewer -// it has pre-cache data like the UI .TGAs -class LLVFS; -extern LLVFS *gStaticVFS; - extern LLMemoryInfo gSysMemory; extern U64Bytes gMemoryAllocated; diff --git a/indra/newview/llappviewerwin32.cpp b/indra/newview/llappviewerwin32.cpp index 9b1c0d1f8b..84ffb3551d 100644 --- a/indra/newview/llappviewerwin32.cpp +++ b/indra/newview/llappviewerwin32.cpp @@ -502,7 +502,7 @@ void LLAppViewerWin32::disableWinErrorReporting() } } -const S32 MAX_CONSOLE_LINES = 500; +const S32 MAX_CONSOLE_LINES = 7500; // Only defined in newer SDKs than we currently use #ifndef ENABLE_VIRTUAL_TERMINAL_PROCESSING #define ENABLE_VIRTUAL_TERMINAL_PROCESSING 4 diff --git a/indra/newview/llcompilequeue.cpp b/indra/newview/llcompilequeue.cpp index 3aaaaf52f5..5d010a6f1e 100644 --- a/indra/newview/llcompilequeue.cpp +++ b/indra/newview/llcompilequeue.cpp @@ -52,7 +52,7 @@ #include "lldir.h" #include "llnotificationsutil.h" #include "llviewerstats.h" -#include "llvfile.h" +#include "llfilesystem.h" #include "lluictrlfactory.h" #include "lltrans.h" @@ -116,7 +116,7 @@ namespace } // *NOTE$: A minor specialization of LLScriptAssetUpload, it does not require a buffer -// (and does not save a buffer to the vFS) and it finds the compile queue window and +// (and does not save a buffer to the cache) and it finds the compile queue window and // displays a compiling message. class LLQueuedScriptAssetUpload : public LLScriptAssetUpload { @@ -134,8 +134,8 @@ public: virtual LLSD prepareUpload() { /* *NOTE$: The parent class (LLScriptAssetUpload will attempt to save - * the script buffer into to the VFS. Since the resource is already in - * the VFS we don't want to do that. Just put a compiling message in + * the script buffer into to the cache. Since the resource is already in + * the cache we don't want to do that. Just put a compiling message in * the window and move on */ LLFloaterCompileQueue* queue = LLFloaterReg::findTypedInstance("compile_queue", LLSD(mQueueId)); @@ -283,11 +283,11 @@ void LLFloaterCompileQueue::handleHTTPResponse(std::string pumpName, const LLSD LLEventPumps::instance().post(pumpName, expresult); } -// *TODO: handleSCriptRetrieval is passed into the VFS via a legacy C function pointer +// *TODO: handleSCriptRetrieval is passed into the cache via a legacy C function pointer // future project would be to convert these to C++ callables (std::function<>) so that // we can use bind and remove the userData parameter. // -void LLFloaterCompileQueue::handleScriptRetrieval(LLVFS *vfs, const LLUUID& assetId, +void LLFloaterCompileQueue::handleScriptRetrieval(const LLUUID& assetId, LLAssetType::EType type, void* userData, S32 status, LLExtStat extStatus) { LLSD result(LLSD::emptyMap()); diff --git a/indra/newview/llcompilequeue.h b/indra/newview/llcompilequeue.h index adb854875a..a9bac345b5 100644 --- a/indra/newview/llcompilequeue.h +++ b/indra/newview/llcompilequeue.h @@ -135,7 +135,7 @@ protected: //bool checkAssetId(const LLUUID &assetId); static void handleHTTPResponse(std::string pumpName, const LLSD &expresult); - static void handleScriptRetrieval(LLVFS *vfs, const LLUUID& assetId, LLAssetType::EType type, void* userData, S32 status, LLExtStat extStatus); + static void handleScriptRetrieval(const LLUUID& assetId, LLAssetType::EType type, void* userData, S32 status, LLExtStat extStatus); private: static void processExperienceIdResults(LLSD result, LLUUID parent); diff --git a/indra/newview/llfilepicker.h b/indra/newview/llfilepicker.h index 2fc496a144..04ba4416d7 100644 --- a/indra/newview/llfilepicker.h +++ b/indra/newview/llfilepicker.h @@ -136,7 +136,7 @@ public: S32 getFileCount() const { return (S32)mFiles.size(); } - // See llvfs/lldir.h : getBaseFileName and getDirName to extract base or directory names + // see lldir.h : getBaseFileName and getDirName to extract base or directory names // clear any lists of buffers or whatever, and make sure the file // picker isn't locked. diff --git a/indra/newview/llfloaterauction.cpp b/indra/newview/llfloaterauction.cpp index 957b2e1e8e..9813156bf2 100644 --- a/indra/newview/llfloaterauction.cpp +++ b/indra/newview/llfloaterauction.cpp @@ -32,8 +32,7 @@ #include "llimagej2c.h" #include "llimagetga.h" #include "llparcel.h" -#include "llvfile.h" -#include "llvfs.h" +#include "llfilesystem.h" #include "llwindow.h" #include "message.h" @@ -202,7 +201,9 @@ void LLFloaterAuction::onClickSnapshot(void* data) LLPointer tga = new LLImageTGA; tga->encode(raw); - LLVFile::writeFile(tga->getData(), tga->getDataSize(), gVFS, self->mImageID, LLAssetType::AT_IMAGE_TGA); + + LLFileSystem tga_file(self->mImageID, LLAssetType::AT_IMAGE_TGA, LLFileSystem::WRITE); + tga_file.write(tga->getData(), tga->getDataSize()); raw->biasedScaleToPowerOfTwo(LLViewerTexture::MAX_IMAGE_SIZE_DEFAULT); @@ -210,7 +211,9 @@ void LLFloaterAuction::onClickSnapshot(void* data) LLPointer j2c = new LLImageJ2C; j2c->encode(raw, 0.0f); - LLVFile::writeFile(j2c->getData(), j2c->getDataSize(), gVFS, self->mImageID, LLAssetType::AT_TEXTURE); + + LLFileSystem j2c_file(self->mImageID, LLAssetType::AT_TEXTURE, LLFileSystem::WRITE); + j2c_file.write(j2c->getData(), j2c->getDataSize()); self->mImage = LLViewerTextureManager::getLocalTexture((LLImageRaw*)raw, FALSE); gGL.getTexUnit(0)->bind(self->mImage); diff --git a/indra/newview/llfloaterbvhpreview.cpp b/indra/newview/llfloaterbvhpreview.cpp index 131d9b077b..687d820a18 100644 --- a/indra/newview/llfloaterbvhpreview.cpp +++ b/indra/newview/llfloaterbvhpreview.cpp @@ -32,7 +32,7 @@ #include "lldatapacker.h" #include "lldir.h" #include "llnotificationsutil.h" -#include "llvfile.h" +#include "llfilesystem.h" #include "llapr.h" #include "llstring.h" @@ -997,10 +997,9 @@ void LLFloaterBvhPreview::onBtnOK(void* userdata) LLDataPackerBinaryBuffer dp(buffer, file_size); if (motionp->serialize(dp)) { - LLVFile file(gVFS, motionp->getID(), LLAssetType::AT_ANIMATION, LLVFile::APPEND); + LLFileSystem file(motionp->getID(), LLAssetType::AT_ANIMATION, LLFileSystem::APPEND); S32 size = dp.getCurrentSize(); - file.setMaxSize(size); if (file.write((U8*)buffer, size)) { std::string name = floaterp->getChild("name_form")->getValue().asString(); diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index b9c03f66a3..481a7dab66 100644 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -59,6 +59,7 @@ #include "llspinctrl.h" #include "lltabcontainer.h" #include "lltrans.h" +#include "llfilesystem.h" #include "llcallbacklist.h" #include "llviewertexteditor.h" #include "llviewernetwork.h" diff --git a/indra/newview/llfloaterpreference.h b/indra/newview/llfloaterpreference.h index 526214a617..f99d0e6150 100644 --- a/indra/newview/llfloaterpreference.h +++ b/indra/newview/llfloaterpreference.h @@ -107,7 +107,7 @@ protected: void onBtnOK(const LLSD& userdata); void onBtnCancel(const LLSD& userdata); - void onClickClearCache(); // Clear viewer texture cache, vfs, and VO cache on next startup + void onClickClearCache(); // Clear viewer texture cache, file cache on next startup void onClickBrowserClearCache(); // Clear web history and caches as well as viewer caches above void onLanguageChange(); void onNotificationsChange(const std::string& OptionName); diff --git a/indra/newview/llfloaterregioninfo.cpp b/indra/newview/llfloaterregioninfo.cpp index ec1909d02a..0375c15467 100644 --- a/indra/newview/llfloaterregioninfo.cpp +++ b/indra/newview/llfloaterregioninfo.cpp @@ -36,7 +36,7 @@ #include "llglheaders.h" #include "llregionflags.h" #include "llstl.h" -#include "llvfile.h" +#include "llfilesystem.h" #include "llxfermanager.h" #include "indra_constants.h" #include "message.h" @@ -2229,10 +2229,9 @@ void LLPanelEstateCovenant::loadInvItem(LLInventoryItem *itemp) } // static -void LLPanelEstateCovenant::onLoadComplete(LLVFS *vfs, - const LLUUID& asset_uuid, - LLAssetType::EType type, - void* user_data, S32 status, LLExtStat ext_status) +void LLPanelEstateCovenant::onLoadComplete(const LLUUID& asset_uuid, + LLAssetType::EType type, + void* user_data, S32 status, LLExtStat ext_status) { LL_INFOS() << "LLPanelEstateCovenant::onLoadComplete()" << LL_ENDL; LLPanelEstateCovenant* panelp = (LLPanelEstateCovenant*)user_data; @@ -2240,7 +2239,7 @@ void LLPanelEstateCovenant::onLoadComplete(LLVFS *vfs, { if(0 == status) { - LLVFile file(vfs, asset_uuid, type, LLVFile::READ); + LLFileSystem file(asset_uuid, type, LLFileSystem::READ); S32 file_length = file.getSize(); diff --git a/indra/newview/llfloaterregioninfo.h b/indra/newview/llfloaterregioninfo.h index 75d0c3ea5c..c34dbb62e8 100644 --- a/indra/newview/llfloaterregioninfo.h +++ b/indra/newview/llfloaterregioninfo.h @@ -55,7 +55,6 @@ class LLRadioGroup; class LLSliderCtrl; class LLSpinCtrl; class LLTextBox; -class LLVFS; class LLPanelRegionGeneralInfo; class LLPanelRegionDebugInfo; @@ -357,8 +356,7 @@ public: static bool confirmResetCovenantCallback(const LLSD& notification, const LLSD& response); void sendChangeCovenantID(const LLUUID &asset_id); void loadInvItem(LLInventoryItem *itemp); - static void onLoadComplete(LLVFS *vfs, - const LLUUID& asset_uuid, + static void onLoadComplete(const LLUUID& asset_uuid, LLAssetType::EType type, void* user_data, S32 status, LLExtStat ext_status); diff --git a/indra/newview/llfloaterreporter.cpp b/indra/newview/llfloaterreporter.cpp index 7bfba2a6d7..5d0e2bbc55 100644 --- a/indra/newview/llfloaterreporter.cpp +++ b/indra/newview/llfloaterreporter.cpp @@ -44,8 +44,7 @@ #include "llnotificationsutil.h" #include "llstring.h" #include "llsys.h" -#include "llvfile.h" -#include "llvfs.h" +#include "llfilesystem.h" #include "mean_collision_data.h" #include "message.h" #include "v3math.h" @@ -899,12 +898,9 @@ void LLFloaterReporter::takeScreenshot(bool use_prev_screenshot) mResourceDatap->mAssetInfo.setName("screenshot_name"); mResourceDatap->mAssetInfo.setDescription("screenshot_descr"); - // store in VFS - LLVFile::writeFile(upload_data->getData(), - upload_data->getDataSize(), - gVFS, - mResourceDatap->mAssetInfo.mUuid, - mResourceDatap->mAssetInfo.mType); + // store in cache + LLFileSystem j2c_file(mResourceDatap->mAssetInfo.mUuid, mResourceDatap->mAssetInfo.mType, LLFileSystem::WRITE); + j2c_file.write(upload_data->getData(), upload_data->getDataSize()); // store in the image list so it doesn't try to fetch from the server LLPointer image_in_list = diff --git a/indra/newview/llfloatertos.cpp b/indra/newview/llfloatertos.cpp index bd403f68d7..1aeb727172 100644 --- a/indra/newview/llfloatertos.cpp +++ b/indra/newview/llfloatertos.cpp @@ -40,7 +40,7 @@ #include "lltextbox.h" #include "llui.h" #include "lluictrlfactory.h" -#include "llvfile.h" +#include "llfilesystem.h" #include "message.h" #include "llstartup.h" // login_alert_done #include "llcorehttputil.h" diff --git a/indra/newview/llfloatertos.h b/indra/newview/llfloatertos.h index 85033acf4d..7c2f0705b7 100644 --- a/indra/newview/llfloatertos.h +++ b/indra/newview/llfloatertos.h @@ -36,7 +36,6 @@ class LLButton; class LLRadioGroup; -class LLVFS; class LLTextEditor; class LLUUID; diff --git a/indra/newview/llgesturemgr.cpp b/indra/newview/llgesturemgr.cpp index 950a6cfaef..9f2119281d 100644 --- a/indra/newview/llgesturemgr.cpp +++ b/indra/newview/llgesturemgr.cpp @@ -42,7 +42,7 @@ #include "llnotificationsutil.h" #include "llstl.h" #include "llstring.h" // todo: remove -#include "llvfile.h" +#include "llfilesystem.h" #include "message.h" // newview @@ -548,7 +548,7 @@ void LLGestureMgr::playGesture(LLMultiGesture* gesture) LLGestureStepAnimation* anim_step = (LLGestureStepAnimation*)step; const LLUUID& anim_id = anim_step->mAnimAssetID; - // Don't request the animation if this step stops it or if it is already in Static VFS + // Don't request the animation if this step stops it or if it is already in the cache if (!(anim_id.isNull() || anim_step->mFlags & ANIM_FLAG_STOP || gAssetStorage->hasLocalAsset(anim_id, LLAssetType::AT_ANIMATION))) @@ -1038,10 +1038,9 @@ void LLGestureMgr::runStep(LLMultiGesture* gesture, LLGestureStep* step) // static -void LLGestureMgr::onLoadComplete(LLVFS *vfs, - const LLUUID& asset_uuid, - LLAssetType::EType type, - void* user_data, S32 status, LLExtStat ext_status) +void LLGestureMgr::onLoadComplete(const LLUUID& asset_uuid, + LLAssetType::EType type, + void* user_data, S32 status, LLExtStat ext_status) { LLLoadInfo* info = (LLLoadInfo*)user_data; @@ -1056,7 +1055,7 @@ void LLGestureMgr::onLoadComplete(LLVFS *vfs, if (0 == status) { - LLVFile file(vfs, asset_uuid, type, LLVFile::READ); + LLFileSystem file(asset_uuid, type, LLFileSystem::READ); S32 size = file.getSize(); std::vector buffer(size+1); @@ -1159,8 +1158,7 @@ void LLGestureMgr::onLoadComplete(LLVFS *vfs, } // static -void LLGestureMgr::onAssetLoadComplete(LLVFS *vfs, - const LLUUID& asset_uuid, +void LLGestureMgr::onAssetLoadComplete(const LLUUID& asset_uuid, LLAssetType::EType type, void* user_data, S32 status, LLExtStat ext_status) { @@ -1172,7 +1170,7 @@ void LLGestureMgr::onAssetLoadComplete(LLVFS *vfs, { case LLAssetType::AT_ANIMATION: { - LLKeyframeMotion::onLoadComplete(vfs, asset_uuid, type, user_data, status, ext_status); + LLKeyframeMotion::onLoadComplete(asset_uuid, type, user_data, status, ext_status); self.mLoadingAssets.erase(asset_uuid); @@ -1180,7 +1178,7 @@ void LLGestureMgr::onAssetLoadComplete(LLVFS *vfs, } case LLAssetType::AT_SOUND: { - LLAudioEngine::assetCallback(vfs, asset_uuid, type, user_data, status, ext_status); + LLAudioEngine::assetCallback(asset_uuid, type, user_data, status, ext_status); self.mLoadingAssets.erase(asset_uuid); diff --git a/indra/newview/llgesturemgr.h b/indra/newview/llgesturemgr.h index 402bdf6039..91ab445273 100644 --- a/indra/newview/llgesturemgr.h +++ b/indra/newview/llgesturemgr.h @@ -40,7 +40,6 @@ class LLMultiGesture; class LLGestureListener; class LLGestureStep; class LLUUID; -class LLVFS; class LLGestureManagerObserver { @@ -154,15 +153,13 @@ protected: void done(); // Used by loadGesture - static void onLoadComplete(LLVFS *vfs, - const LLUUID& asset_uuid, - LLAssetType::EType type, - void* user_data, S32 status, LLExtStat ext_status); + static void onLoadComplete(const LLUUID& asset_uuid, + LLAssetType::EType type, + void* user_data, S32 status, LLExtStat ext_status); // Used by playGesture to load an asset file // required to play a gesture step - static void onAssetLoadComplete(LLVFS *vfs, - const LLUUID& asset_uuid, + static void onAssetLoadComplete(const LLUUID& asset_uuid, LLAssetType::EType type, void* user_data, S32 status, LLExtStat ext_status); diff --git a/indra/newview/lllandmarklist.cpp b/indra/newview/lllandmarklist.cpp index b4236c406b..2966ca1f10 100644 --- a/indra/newview/lllandmarklist.cpp +++ b/indra/newview/lllandmarklist.cpp @@ -33,7 +33,7 @@ #include "llappviewer.h" #include "llagent.h" -#include "llvfile.h" +#include "llfilesystem.h" #include "llviewerstats.h" // Globals @@ -118,7 +118,6 @@ LLLandmark* LLLandmarkList::getAsset(const LLUUID& asset_uuid, loaded_callback_t // static void LLLandmarkList::processGetAssetReply( - LLVFS *vfs, const LLUUID& uuid, LLAssetType::EType type, void* user_data, @@ -127,7 +126,7 @@ void LLLandmarkList::processGetAssetReply( { if( status == 0 ) { - LLVFile file(vfs, uuid, type); + LLFileSystem file(uuid, type); S32 file_length = file.getSize(); std::vector buffer(file_length + 1); diff --git a/indra/newview/lllandmarklist.h b/indra/newview/lllandmarklist.h index 2e7bd25610..0e4859dbc9 100644 --- a/indra/newview/lllandmarklist.h +++ b/indra/newview/lllandmarklist.h @@ -52,7 +52,6 @@ public: BOOL assetExists(const LLUUID& asset_uuid); LLLandmark* getAsset(const LLUUID& asset_uuid, loaded_callback_t cb = NULL); static void processGetAssetReply( - LLVFS *vfs, const LLUUID& uuid, LLAssetType::EType type, void* user_data, diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp index 3e8731dfe6..8e5bdc0225 100644 --- a/indra/newview/llmeshrepository.cpp +++ b/indra/newview/llmeshrepository.cpp @@ -49,7 +49,7 @@ #include "llsdutil_math.h" #include "llsdserialize.h" #include "llthread.h" -#include "llvfile.h" +#include "llfilesystem.h" #include "llviewercontrol.h" #include "llviewerinventory.h" #include "llviewermenufile.h" @@ -294,8 +294,6 @@ // * Header parse failures come without much explanation. Elaborate. // * Work queue for uploads? Any need for this or is the current scheme good // enough? -// * Various temp buffers used in VFS I/O might be allocated once or even -// statically. Look for some wins here. // * Move data structures holding mesh data used by main thread into main- // thread-only access so that no locking is needed. May require duplication // of some data so that worker thread has a minimal data set to guide @@ -1336,8 +1334,8 @@ bool LLMeshRepoThread::fetchMeshSkinInfo(const LLUUID& mesh_id) if (version <= MAX_MESH_VERSION && offset >= 0 && size > 0) { - //check VFS for mesh skin info - LLVFile file(gVFS, mesh_id, LLAssetType::AT_MESH); + //check cache for mesh skin info + LLFileSystem file(mesh_id, LLAssetType::AT_MESH); if (file.getSize() >= offset+size) { U8* buffer = new(std::nothrow) U8[size]; @@ -1370,7 +1368,7 @@ bool LLMeshRepoThread::fetchMeshSkinInfo(const LLUUID& mesh_id) delete[] buffer; } - //reading from VFS failed for whatever reason, fetch from sim + //reading from cache failed for whatever reason, fetch from sim std::string http_url; constructUrl(mesh_id, &http_url); @@ -1432,8 +1430,8 @@ bool LLMeshRepoThread::fetchMeshDecomposition(const LLUUID& mesh_id) if (version <= MAX_MESH_VERSION && offset >= 0 && size > 0) { - //check VFS for mesh skin info - LLVFile file(gVFS, mesh_id, LLAssetType::AT_MESH); + //check cache for mesh skin info + LLFileSystem file(mesh_id, LLAssetType::AT_MESH); if (file.getSize() >= offset+size) { U8* buffer = new(std::nothrow) U8[size]; @@ -1467,7 +1465,7 @@ bool LLMeshRepoThread::fetchMeshDecomposition(const LLUUID& mesh_id) delete[] buffer; } - //reading from VFS failed for whatever reason, fetch from sim + //reading from cache failed for whatever reason, fetch from sim std::string http_url; constructUrl(mesh_id, &http_url); @@ -1529,8 +1527,8 @@ bool LLMeshRepoThread::fetchMeshPhysicsShape(const LLUUID& mesh_id) if (version <= MAX_MESH_VERSION && offset >= 0 && size > 0) { - //check VFS for mesh physics shape info - LLVFile file(gVFS, mesh_id, LLAssetType::AT_MESH); + //check cache for mesh physics shape info + LLFileSystem file(mesh_id, LLAssetType::AT_MESH); if (file.getSize() >= offset+size) { LLMeshRepository::sCacheBytesRead += size; @@ -1563,7 +1561,7 @@ bool LLMeshRepoThread::fetchMeshPhysicsShape(const LLUUID& mesh_id) delete[] buffer; } - //reading from VFS failed for whatever reason, fetch from sim + //reading from cache failed for whatever reason, fetch from sim std::string http_url; constructUrl(mesh_id, &http_url); @@ -1634,8 +1632,8 @@ bool LLMeshRepoThread::fetchMeshHeader(const LLVolumeParams& mesh_params, bool c ++LLMeshRepository::sMeshRequestCount; { - //look for mesh in asset in vfs - LLVFile file(gVFS, mesh_params.getSculptID(), LLAssetType::AT_MESH); + //look for mesh in asset in cache + LLFileSystem file(mesh_params.getSculptID(), LLAssetType::AT_MESH); S32 size = file.getSize(); @@ -1649,7 +1647,7 @@ bool LLMeshRepoThread::fetchMeshHeader(const LLVolumeParams& mesh_params, bool c file.read(buffer, bytes); if (headerReceived(mesh_params, buffer, bytes) == MESH_OK) { - // Found mesh in VFS cache + // Found mesh in cache return true; } } @@ -1713,8 +1711,8 @@ bool LLMeshRepoThread::fetchMeshLOD(const LLVolumeParams& mesh_params, S32 lod, if (version <= MAX_MESH_VERSION && offset >= 0 && size > 0) { - //check VFS for mesh asset - LLVFile file(gVFS, mesh_id, LLAssetType::AT_MESH); + //check cache for mesh asset + LLFileSystem file(mesh_id, LLAssetType::AT_MESH); if (file.getSize() >= offset+size) { U8* buffer = new(std::nothrow) U8[size]; @@ -1749,7 +1747,7 @@ bool LLMeshRepoThread::fetchMeshLOD(const LLVolumeParams& mesh_params, S32 lod, delete[] buffer; } - //reading from VFS failed for whatever reason, fetch from sim + //reading from cache failed for whatever reason, fetch from sim std::string http_url; constructUrl(mesh_id, &http_url); @@ -3208,7 +3206,7 @@ void LLMeshHeaderHandler::processData(LLCore::BufferArray * /* body */, S32 /* b } else if (data && data_size > 0) { - // header was successfully retrieved from sim and parsed, cache in vfs + // header was successfully retrieved from sim and parsed and is in cache S32 header_bytes = 0; LLSD header; @@ -3247,31 +3245,16 @@ void LLMeshHeaderHandler::processData(LLCore::BufferArray * /* body */, S32 /* b // It's possible for the remote asset to have more data than is needed for the local cache - // only allocate as much space in the VFS as is needed for the local cache + // only allocate as much space in the cache as is needed for the local cache data_size = llmin(data_size, bytes); - LLVFile file(gVFS, mesh_id, LLAssetType::AT_MESH, LLVFile::WRITE); - if (file.getMaxSize() >= bytes || file.setMaxSize(bytes)) + LLFileSystem file(mesh_id, LLAssetType::AT_MESH, LLFileSystem::WRITE); + if (file.getMaxSize() >= bytes) { LLMeshRepository::sCacheBytesWritten += data_size; ++LLMeshRepository::sCacheWrites; file.write(data, data_size); - - // zero out the rest of the file - U8 block[MESH_HEADER_SIZE]; - memset(block, 0, sizeof(block)); - - while (bytes-file.tell() > sizeof(block)) - { - file.write(block, sizeof(block)); - } - - S32 remaining = bytes-file.tell(); - if (remaining > 0) - { - file.write(block, remaining); - } } } else @@ -3323,8 +3306,8 @@ void LLMeshLODHandler::processData(LLCore::BufferArray * /* body */, S32 /* body EMeshProcessingResult result = gMeshRepo.mThread->lodReceived(mMeshParams, mLOD, data, data_size); if (result == MESH_OK) { - // good fetch from sim, write to VFS for caching - LLVFile file(gVFS, mMeshParams.getSculptID(), LLAssetType::AT_MESH, LLVFile::WRITE); + // good fetch from sim, write to cache + LLFileSystem file(mMeshParams.getSculptID(), LLAssetType::AT_MESH, LLFileSystem::WRITE); S32 offset = mOffset; S32 size = mRequestedBytes; @@ -3387,8 +3370,8 @@ void LLMeshSkinInfoHandler::processData(LLCore::BufferArray * /* body */, S32 /* && ((data != NULL) == (data_size > 0)) // if we have data but no size or have size but no data, something is wrong && gMeshRepo.mThread->skinInfoReceived(mMeshID, data, data_size)) { - // good fetch from sim, write to VFS for caching - LLVFile file(gVFS, mMeshID, LLAssetType::AT_MESH, LLVFile::WRITE); + // good fetch from sim, write to cache + LLFileSystem file(mMeshID, LLAssetType::AT_MESH, LLFileSystem::WRITE); S32 offset = mOffset; S32 size = mRequestedBytes; @@ -3435,8 +3418,8 @@ void LLMeshDecompositionHandler::processData(LLCore::BufferArray * /* body */, S && ((data != NULL) == (data_size > 0)) // if we have data but no size or have size but no data, something is wrong && gMeshRepo.mThread->decompositionReceived(mMeshID, data, data_size)) { - // good fetch from sim, write to VFS for caching - LLVFile file(gVFS, mMeshID, LLAssetType::AT_MESH, LLVFile::WRITE); + // good fetch from sim, write to cache + LLFileSystem file(mMeshID, LLAssetType::AT_MESH, LLFileSystem::WRITE); S32 offset = mOffset; S32 size = mRequestedBytes; @@ -3482,8 +3465,8 @@ void LLMeshPhysicsShapeHandler::processData(LLCore::BufferArray * /* body */, S3 && ((data != NULL) == (data_size > 0)) // if we have data but no size or have size but no data, something is wrong && gMeshRepo.mThread->physicsShapeReceived(mMeshID, data, data_size) == MESH_OK) { - // good fetch from sim, write to VFS for caching - LLVFile file(gVFS, mMeshID, LLAssetType::AT_MESH, LLVFile::WRITE); + // good fetch from sim, write to cache for caching + LLFileSystem file(mMeshID, LLAssetType::AT_MESH, LLFileSystem::WRITE); S32 offset = mOffset; S32 size = mRequestedBytes; diff --git a/indra/newview/llmeshrepository.h b/indra/newview/llmeshrepository.h index 81e49cb1d8..441264d42f 100644 --- a/indra/newview/llmeshrepository.h +++ b/indra/newview/llmeshrepository.h @@ -48,7 +48,6 @@ class LLVOVolume; class LLMutex; class LLCondition; -class LLVFS; class LLMeshRepository; typedef enum e_mesh_processing_result_enum diff --git a/indra/newview/lloutfitgallery.cpp b/indra/newview/lloutfitgallery.cpp index 272e7ae351..90f6d23a61 100644 --- a/indra/newview/lloutfitgallery.cpp +++ b/indra/newview/lloutfitgallery.cpp @@ -32,7 +32,7 @@ // llcommon #include "llcommonutils.h" -#include "llvfile.h" +#include "llfilesystem.h" #include "llaccordionctrltab.h" #include "llappearancemgr.h" diff --git a/indra/newview/lloutfitgallery.h b/indra/newview/lloutfitgallery.h index 6dd8a6298f..ce5c090134 100644 --- a/indra/newview/lloutfitgallery.h +++ b/indra/newview/lloutfitgallery.h @@ -38,7 +38,6 @@ #include -class LLVFS; class LLOutfitGallery; class LLOutfitGalleryItem; class LLOutfitListGearMenuBase; diff --git a/indra/newview/llpostcard.cpp b/indra/newview/llpostcard.cpp index d5775042c1..071fc31d27 100644 --- a/indra/newview/llpostcard.cpp +++ b/indra/newview/llpostcard.cpp @@ -28,8 +28,7 @@ #include "llpostcard.h" -#include "llvfile.h" -#include "llvfs.h" +#include "llfilesystem.h" #include "llviewerregion.h" #include "message.h" diff --git a/indra/newview/llpreviewgesture.cpp b/indra/newview/llpreviewgesture.cpp index 70ce275734..4318a55704 100644 --- a/indra/newview/llpreviewgesture.cpp +++ b/indra/newview/llpreviewgesture.cpp @@ -30,7 +30,7 @@ #include "llagent.h" #include "llanimstatelabels.h" #include "llanimationstates.h" -#include "llappviewer.h" // gVFS +#include "llappviewer.h" #include "llcheckboxctrl.h" #include "llcombobox.h" #include "lldatapacker.h" @@ -47,7 +47,7 @@ #include "llradiogroup.h" #include "llresmgr.h" #include "lltrans.h" -#include "llvfile.h" +#include "llfilesystem.h" #include "llviewerobjectlist.h" #include "llviewerregion.h" #include "llviewerstats.h" @@ -841,10 +841,9 @@ void LLPreviewGesture::loadAsset() // static -void LLPreviewGesture::onLoadComplete(LLVFS *vfs, - const LLUUID& asset_uuid, - LLAssetType::EType type, - void* user_data, S32 status, LLExtStat ext_status) +void LLPreviewGesture::onLoadComplete(const LLUUID& asset_uuid, + LLAssetType::EType type, + void* user_data, S32 status, LLExtStat ext_status) { LLUUID* item_idp = (LLUUID*)user_data; @@ -853,7 +852,7 @@ void LLPreviewGesture::onLoadComplete(LLVFS *vfs, { if (0 == status) { - LLVFile file(vfs, asset_uuid, type, LLVFile::READ); + LLFileSystem file(asset_uuid, type, LLFileSystem::READ); S32 size = file.getSize(); std::vector buffer(size+1); @@ -1138,10 +1137,9 @@ void LLPreviewGesture::saveIfNeeded() tid.generate(); assetId = tid.makeAssetID(gAgent.getSecureSessionID()); - LLVFile file(gVFS, assetId, LLAssetType::AT_GESTURE, LLVFile::APPEND); + LLFileSystem file(assetId, LLAssetType::AT_GESTURE, LLFileSystem::APPEND); S32 size = dp.getCurrentSize(); - file.setMaxSize(size); file.write((U8*)buffer, size); LLLineEditor* descEditor = getChild("desc"); diff --git a/indra/newview/llpreviewgesture.h b/indra/newview/llpreviewgesture.h index 3ba4f56295..19bccf35bd 100644 --- a/indra/newview/llpreviewgesture.h +++ b/indra/newview/llpreviewgesture.h @@ -39,7 +39,6 @@ class LLScrollListCtrl; class LLScrollListItem; class LLButton; class LLRadioGroup; -class LLVFS; class LLPreviewGesture : public LLPreview { @@ -80,8 +79,7 @@ protected: void loadAsset(); - static void onLoadComplete(LLVFS *vfs, - const LLUUID& asset_uuid, + static void onLoadComplete(const LLUUID& asset_uuid, LLAssetType::EType type, void* user_data, S32 status, LLExtStat ext_status); diff --git a/indra/newview/llpreviewnotecard.cpp b/indra/newview/llpreviewnotecard.cpp index 1b60610668..a7bb5c8236 100644 --- a/indra/newview/llpreviewnotecard.cpp +++ b/indra/newview/llpreviewnotecard.cpp @@ -46,7 +46,7 @@ #include "llselectmgr.h" #include "lltrans.h" #include "llviewertexteditor.h" -#include "llvfile.h" +#include "llfilesystem.h" #include "llviewerinventory.h" #include "llviewerobject.h" #include "llviewerobjectlist.h" @@ -327,8 +327,7 @@ void LLPreviewNotecard::loadAsset() } // static -void LLPreviewNotecard::onLoadComplete(LLVFS *vfs, - const LLUUID& asset_uuid, +void LLPreviewNotecard::onLoadComplete(const LLUUID& asset_uuid, LLAssetType::EType type, void* user_data, S32 status, LLExtStat ext_status) { @@ -339,7 +338,7 @@ void LLPreviewNotecard::onLoadComplete(LLVFS *vfs, { if(0 == status) { - LLVFile file(vfs, asset_uuid, type, LLVFile::READ); + LLFileSystem file(asset_uuid, type, LLFileSystem::READ); S32 file_length = file.getSize(); @@ -446,7 +445,7 @@ void LLPreviewNotecard::finishInventoryUpload(LLUUID itemId, LLUUID newAssetId, LLPreviewNotecard* nc = LLFloaterReg::findTypedInstance("preview_notecard", LLSD(itemId)); if (nc) { - // *HACK: we have to delete the asset in the VFS so + // *HACK: we have to delete the asset in the cache so // that the viewer will redownload it. This is only // really necessary if the asset had to be modified by // the uploader, so this can be optimized away in some @@ -454,7 +453,7 @@ void LLPreviewNotecard::finishInventoryUpload(LLUUID itemId, LLUUID newAssetId, // script actually changed the asset. if (nc->hasEmbeddedInventory()) { - gVFS->removeFile(newAssetId, LLAssetType::AT_NOTECARD); + LLFileSystem::removeFile(newAssetId, LLAssetType::AT_NOTECARD); } if (newItemId.isNull()) { @@ -479,7 +478,7 @@ void LLPreviewNotecard::finishTaskUpload(LLUUID itemId, LLUUID newAssetId, LLUUI { if (nc->hasEmbeddedInventory()) { - gVFS->removeFile(newAssetId, LLAssetType::AT_NOTECARD); + LLFileSystem::removeFile(newAssetId, LLAssetType::AT_NOTECARD); } nc->setAssetId(newAssetId); nc->refreshFromInventory(); @@ -558,14 +557,13 @@ bool LLPreviewNotecard::saveIfNeeded(LLInventoryItem* copyitem, bool sync) tid.generate(); asset_id = tid.makeAssetID(gAgent.getSecureSessionID()); - LLVFile file(gVFS, asset_id, LLAssetType::AT_NOTECARD, LLVFile::APPEND); + LLFileSystem file(asset_id, LLAssetType::AT_NOTECARD, LLFileSystem::APPEND); LLSaveNotecardInfo* info = new LLSaveNotecardInfo(this, mItemUUID, mObjectUUID, tid, copyitem); S32 size = buffer.length() + 1; - file.setMaxSize(size); file.write((U8*)buffer.c_str(), size); gAssetStorage->storeAssetData(tid, LLAssetType::AT_NOTECARD, diff --git a/indra/newview/llpreviewnotecard.h b/indra/newview/llpreviewnotecard.h index d9c14815c1..063a01ca47 100644 --- a/indra/newview/llpreviewnotecard.h +++ b/indra/newview/llpreviewnotecard.h @@ -83,8 +83,7 @@ protected: void deleteNotecard(); - static void onLoadComplete(LLVFS *vfs, - const LLUUID& asset_uuid, + static void onLoadComplete(const LLUUID& asset_uuid, LLAssetType::EType type, void* user_data, S32 status, LLExtStat ext_status); diff --git a/indra/newview/llpreviewscript.cpp b/indra/newview/llpreviewscript.cpp index 5e81fa6402..379bc9871c 100644 --- a/indra/newview/llpreviewscript.cpp +++ b/indra/newview/llpreviewscript.cpp @@ -51,7 +51,7 @@ #include "llsdserialize.h" #include "llslider.h" #include "lltooldraganddrop.h" -#include "llvfile.h" +#include "llfilesystem.h" #include "llagent.h" #include "llmenugl.h" @@ -1685,8 +1685,11 @@ void LLPreviewLSL::saveIfNeeded(bool sync /*= true*/) { std::string buffer(mScriptEd->mEditor->getText()); + LLUUID old_asset_id = inv_item->getAssetUUID().isNull() ? mScriptEd->getAssetID() : inv_item->getAssetUUID(); + LLResourceUploadInfo::ptr_t uploadInfo(std::make_shared(mItemUUID, buffer, - [](LLUUID itemId, LLUUID, LLUUID, LLSD response) { + [old_asset_id](LLUUID itemId, LLUUID, LLUUID, LLSD response) { + LLFileSystem::removeFile(old_asset_id, LLAssetType::AT_LSL_TEXT); LLPreviewLSL::finishedLSLUpload(itemId, response); })); @@ -1696,8 +1699,8 @@ void LLPreviewLSL::saveIfNeeded(bool sync /*= true*/) } // static -void LLPreviewLSL::onLoadComplete( LLVFS *vfs, const LLUUID& asset_uuid, LLAssetType::EType type, - void* user_data, S32 status, LLExtStat ext_status) +void LLPreviewLSL::onLoadComplete(const LLUUID& asset_uuid, LLAssetType::EType type, + void* user_data, S32 status, LLExtStat ext_status) { LL_DEBUGS() << "LLPreviewLSL::onLoadComplete: got uuid " << asset_uuid << LL_ENDL; @@ -1707,7 +1710,7 @@ void LLPreviewLSL::onLoadComplete( LLVFS *vfs, const LLUUID& asset_uuid, LLAsset { if(0 == status) { - LLVFile file(vfs, asset_uuid, type); + LLFileSystem file(asset_uuid, type); S32 file_length = file.getSize(); std::vector buffer(file_length+1); @@ -1734,6 +1737,7 @@ void LLPreviewLSL::onLoadComplete( LLVFS *vfs, const LLUUID& asset_uuid, LLAsset } preview->mScriptEd->setScriptName(script_name); preview->mScriptEd->setEnableEditing(is_modifiable); + preview->mScriptEd->setAssetID(asset_uuid); preview->mAssetStatus = PREVIEW_ASSET_LOADED; } else @@ -1970,7 +1974,7 @@ void LLLiveLSLEditor::loadAsset() } // static -void LLLiveLSLEditor::onLoadComplete(LLVFS *vfs, const LLUUID& asset_id, +void LLLiveLSLEditor::onLoadComplete(const LLUUID& asset_id, LLAssetType::EType type, void* user_data, S32 status, LLExtStat ext_status) { @@ -1984,9 +1988,10 @@ void LLLiveLSLEditor::onLoadComplete(LLVFS *vfs, const LLUUID& asset_id, { if( LL_ERR_NOERR == status ) { - instance->loadScriptText(vfs, asset_id, type); + instance->loadScriptText(asset_id, type); instance->mScriptEd->setEnableEditing(TRUE); instance->mAssetStatus = PREVIEW_ASSET_LOADED; + instance->mScriptEd->setAssetID(asset_id); } else { @@ -2010,9 +2015,9 @@ void LLLiveLSLEditor::onLoadComplete(LLVFS *vfs, const LLUUID& asset_id, delete floater_key; } -void LLLiveLSLEditor::loadScriptText(LLVFS *vfs, const LLUUID &uuid, LLAssetType::EType type) +void LLLiveLSLEditor::loadScriptText(const LLUUID &uuid, LLAssetType::EType type) { - LLVFile file(vfs, uuid, type); + LLFileSystem file(uuid, type); S32 file_length = file.getSize(); std::vector buffer(file_length + 1); file.read((U8*)&buffer[0], file_length); @@ -2166,6 +2171,7 @@ void LLLiveLSLEditor::finishLSLUpload(LLUUID itemId, LLUUID taskId, LLUUID newAs if (preview) { preview->mItem->setAssetUUID(newAssetId); + preview->mScriptEd->setAssetID(newAssetId); // Bytecode save completed if (response["compiled"]) @@ -2236,12 +2242,14 @@ void LLLiveLSLEditor::saveIfNeeded(bool sync /*= true*/) if (!url.empty()) { std::string buffer(mScriptEd->mEditor->getText()); + LLUUID old_asset_id = mScriptEd->getAssetID(); LLResourceUploadInfo::ptr_t uploadInfo(std::make_shared(mObjectUUID, mItemUUID, monoChecked() ? LLScriptAssetUpload::MONO : LLScriptAssetUpload::LSL2, isRunning, mScriptEd->getAssociatedExperience(), buffer, - [isRunning](LLUUID itemId, LLUUID taskId, LLUUID newAssetId, LLSD response) { - LLLiveLSLEditor::finishLSLUpload(itemId, taskId, newAssetId, response, isRunning); + [isRunning, old_asset_id](LLUUID itemId, LLUUID taskId, LLUUID newAssetId, LLSD response) { + LLFileSystem::removeFile(old_asset_id, LLAssetType::AT_LSL_TEXT); + LLLiveLSLEditor::finishLSLUpload(itemId, taskId, newAssetId, response, isRunning); })); LLViewerAssetUpload::EnqueueInventoryUpload(url, uploadInfo); diff --git a/indra/newview/llpreviewscript.h b/indra/newview/llpreviewscript.h index 3cf22a0e6e..18c10ab365 100644 --- a/indra/newview/llpreviewscript.h +++ b/indra/newview/llpreviewscript.h @@ -48,7 +48,6 @@ struct LLEntryAndEdCore; class LLMenuBarGL; class LLFloaterScriptSearch; class LLKeywordToken; -class LLVFS; class LLViewerInventoryItem; class LLScriptEdContainer; class LLFloaterGotoLine; @@ -143,6 +142,9 @@ public: void setItemRemoved(bool script_removed){mScriptRemoved = script_removed;}; + void setAssetID( const LLUUID& asset_id){ mAssetID = asset_id; }; + LLUUID getAssetID() { return mAssetID; } + private: void onBtnDynamicHelp(); void onBtnUndoChanges(); @@ -188,6 +190,7 @@ private: LLUUID mAssociatedExperience; BOOL mScriptRemoved; BOOL mSaveDialogShown; + LLUUID mAssetID; LLScriptEdContainer* mContainer; // parent view @@ -234,7 +237,7 @@ protected: static void onLoad(void* userdata); static void onSave(void* userdata, BOOL close_after_save); - static void onLoadComplete(LLVFS *vfs, const LLUUID& uuid, + static void onLoadComplete(const LLUUID& uuid, LLAssetType::EType type, void* user_data, S32 status, LLExtStat ext_status); @@ -295,13 +298,13 @@ private: static void onLoad(void* userdata); static void onSave(void* userdata, BOOL close_after_save); - static void onLoadComplete(LLVFS *vfs, const LLUUID& asset_uuid, + static void onLoadComplete(const LLUUID& asset_uuid, LLAssetType::EType type, void* user_data, S32 status, LLExtStat ext_status); static void onRunningCheckboxClicked(LLUICtrl*, void* userdata); static void onReset(void* userdata); - void loadScriptText(LLVFS *vfs, const LLUUID &uuid, LLAssetType::EType type); + void loadScriptText(const LLUUID &uuid, LLAssetType::EType type); static void onErrorList(LLUICtrl*, void* user_data); diff --git a/indra/newview/llsettingsvo.cpp b/indra/newview/llsettingsvo.cpp index 1e5b893cbc..58cbe0e20a 100644 --- a/indra/newview/llsettingsvo.cpp +++ b/indra/newview/llsettingsvo.cpp @@ -57,7 +57,7 @@ #include "llinventorymodel.h" #include "llassetstorage.h" -#include "llvfile.h" +#include "llfilesystem.h" #include "lldrawpoolwater.h" #include @@ -292,18 +292,18 @@ void LLSettingsVOBase::onTaskAssetUploadComplete(LLUUID itemId, LLUUID taskId, L void LLSettingsVOBase::getSettingsAsset(const LLUUID &assetId, LLSettingsVOBase::asset_download_fn callback) { gAssetStorage->getAssetData(assetId, LLAssetType::AT_SETTINGS, - [callback](LLVFS *vfs, const LLUUID &asset_id, LLAssetType::EType, void *, S32 status, LLExtStat ext_status) - { onAssetDownloadComplete(vfs, asset_id, status, ext_status, callback); }, + [callback](const LLUUID &asset_id, LLAssetType::EType, void *, S32 status, LLExtStat ext_status) + { onAssetDownloadComplete(asset_id, status, ext_status, callback); }, nullptr, true); } -void LLSettingsVOBase::onAssetDownloadComplete(LLVFS *vfs, const LLUUID &asset_id, S32 status, LLExtStat ext_status, LLSettingsVOBase::asset_download_fn callback) +void LLSettingsVOBase::onAssetDownloadComplete(const LLUUID &asset_id, S32 status, LLExtStat ext_status, LLSettingsVOBase::asset_download_fn callback) { LLSettingsBase::ptr_t settings; if (!status) { - LLVFile file(vfs, asset_id, LLAssetType::AT_SETTINGS, LLVFile::READ); + LLFileSystem file(asset_id, LLAssetType::AT_SETTINGS, LLFileSystem::READ); S32 size = file.getSize(); std::string buffer(size + 1, '\0'); diff --git a/indra/newview/llsettingsvo.h b/indra/newview/llsettingsvo.h index 65136ad2f5..a1baf02fe7 100644 --- a/indra/newview/llsettingsvo.h +++ b/indra/newview/llsettingsvo.h @@ -38,7 +38,6 @@ #include "llextendedstatus.h" #include -class LLVFS; class LLInventoryItem; class LLGLSLShader; @@ -81,7 +80,7 @@ private: static void onAgentAssetUploadComplete(LLUUID itemId, LLUUID newAssetId, LLUUID newItemId, LLSD response, LLSettingsBase::ptr_t psettings, inventory_result_fn callback); static void onTaskAssetUploadComplete(LLUUID itemId, LLUUID taskId, LLUUID newAssetId, LLSD response, LLSettingsBase::ptr_t psettings, inventory_result_fn callback); - static void onAssetDownloadComplete(LLVFS *vfs, const LLUUID &asset_id, S32 status, LLExtStat ext_status, asset_download_fn callback); + static void onAssetDownloadComplete(const LLUUID &asset_id, S32 status, LLExtStat ext_status, asset_download_fn callback); }; //========================================================================= diff --git a/indra/newview/llsnapshotlivepreview.cpp b/indra/newview/llsnapshotlivepreview.cpp index 8369def968..8134187c21 100644 --- a/indra/newview/llsnapshotlivepreview.cpp +++ b/indra/newview/llsnapshotlivepreview.cpp @@ -31,6 +31,7 @@ #include "llagentbenefits.h" #include "llagentcamera.h" #include "llagentui.h" +#include "llfilesystem.h" #include "llcombobox.h" #include "llfloaterperms.h" #include "llfloaterreg.h" @@ -50,8 +51,6 @@ #include "llviewercontrol.h" #include "llviewermenufile.h" // upload_new_resource() #include "llviewerstats.h" -#include "llvfile.h" -#include "llvfs.h" #include "llwindow.h" #include "llworld.h" #include @@ -1006,7 +1005,8 @@ void LLSnapshotLivePreview::saveTexture(BOOL outfit_snapshot, std::string name) if (formatted->encode(scaled, 0.0f)) { - LLVFile::writeFile(formatted->getData(), formatted->getDataSize(), gVFS, new_asset_id, LLAssetType::AT_TEXTURE); + LLFileSystem fmt_file(new_asset_id, LLAssetType::AT_TEXTURE, LLFileSystem::WRITE); + fmt_file.write(formatted->getData(), formatted->getDataSize()); std::string pos_string; LLAgentUI::buildLocationString(pos_string, LLAgentUI::LOCATION_FORMAT_FULL); std::string who_took_it; diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index 17777c3ceb..f281b30a8e 100644 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -82,7 +82,6 @@ #include "llversioninfo.h" #include "llviewercontrol.h" #include "llviewerhelp.h" -#include "llvfs.h" #include "llxorcipher.h" // saved password, MAC address #include "llwindow.h" #include "message.h" @@ -268,7 +267,7 @@ bool login_alert_status(const LLSD& notification, const LLSD& response); void login_packet_failed(void**, S32 result); void use_circuit_callback(void**, S32 result); void register_viewer_callbacks(LLMessageSystem* msg); -void asset_callback_nothing(LLVFS*, const LLUUID&, LLAssetType::EType, void*, S32); +void asset_callback_nothing(const LLUUID&, LLAssetType::EType, void*, S32); bool callback_choose_gender(const LLSD& notification, const LLSD& response); void init_start_screen(S32 location_id); void release_start_screen(); @@ -580,7 +579,7 @@ bool idle_startup() // start the xfer system. by default, choke the downloads // a lot... const S32 VIEWER_MAX_XFER = 3; - start_xfer_manager(gVFS); + start_xfer_manager(); gXferManager->setMaxIncomingXfers(VIEWER_MAX_XFER); F32 xfer_throttle_bps = gSavedSettings.getF32("XferThrottle"); if (xfer_throttle_bps > 1.f) @@ -588,7 +587,7 @@ bool idle_startup() gXferManager->setUseAckThrottling(TRUE); gXferManager->setAckThrottleBPS(xfer_throttle_bps); } - gAssetStorage = new LLViewerAssetStorage(msg, gXferManager, gVFS, gStaticVFS); + gAssetStorage = new LLViewerAssetStorage(msg, gXferManager); F32 dropPercent = gSavedSettings.getF32("PacketDropPercentage"); @@ -1004,13 +1003,6 @@ bool idle_startup() gViewerWindow->revealIntroPanel(); - // Poke the VFS, which could potentially block for a while if - // Windows XP is acting up - set_startup_status(0.07f, LLTrans::getString("LoginVerifyingCache"), LLStringUtil::null); - display_startup(); - - gVFS->pokeFiles(); - LLStartUp::setStartupState( STATE_LOGIN_AUTH_INIT ); return FALSE; @@ -2589,7 +2581,7 @@ void register_viewer_callbacks(LLMessageSystem* msg) msg->setHandlerFuncFast(_PREHASH_FeatureDisabled, process_feature_disabled_message); } -void asset_callback_nothing(LLVFS*, const LLUUID&, LLAssetType::EType, void*, S32) +void asset_callback_nothing(const LLUUID&, LLAssetType::EType, void*, S32) { // nothing } diff --git a/indra/newview/lltexturecache.cpp b/indra/newview/lltexturecache.cpp index a9f19dc32d..d4fc6f3de2 100644 --- a/indra/newview/lltexturecache.cpp +++ b/indra/newview/lltexturecache.cpp @@ -55,6 +55,7 @@ const S32 TEXTURE_FAST_CACHE_ENTRY_OVERHEAD = sizeof(S32) * 4; //w, h, c, level const S32 TEXTURE_FAST_CACHE_DATA_SIZE = 16 * 16 * 4; const S32 TEXTURE_FAST_CACHE_ENTRY_SIZE = TEXTURE_FAST_CACHE_DATA_SIZE + TEXTURE_FAST_CACHE_ENTRY_OVERHEAD; const F32 TEXTURE_LAZY_PURGE_TIME_LIMIT = .004f; // 4ms. Would be better to autoadjust, but there is a major cache rework in progress. +const F32 TEXTURE_PRUNING_MAX_TIME = 15.f; class LLTextureCacheWorker : public LLWorkerClass { @@ -1551,7 +1552,6 @@ void LLTextureCache::readHeaderCache() if (num_entries - empty_entries > sCacheMaxEntries) { // Special case: cache size was reduced, need to remove entries - // Note: After we prune entries, we will call this again and create the LRU U32 entries_to_purge = (num_entries - empty_entries) - sCacheMaxEntries; LL_INFOS() << "Texture Cache Entries: " << num_entries << " Max: " << sCacheMaxEntries << " Empty: " << empty_entries << " Purging: " << entries_to_purge << LL_ENDL; // We can exit the following loop with the given condition, since if we'd reach the end of the lru set we'd have: @@ -1564,7 +1564,7 @@ void LLTextureCache::readHeaderCache() ++iter; } } - else + { S32 lru_entries = (S32)((F32)sCacheMaxEntries * TEXTURE_CACHE_LRU_SIZE); for (std::set::iterator iter = lru.begin(); iter != lru.end(); ++iter) @@ -1578,30 +1578,19 @@ void LLTextureCache::readHeaderCache() if (purge_list.size() > 0) { + LLTimer timer; for (std::set::iterator iter = purge_list.begin(); iter != purge_list.end(); ++iter) { std::string tex_filename = getTextureFileName(entries[*iter].mID); removeEntry((S32)*iter, entries[*iter], tex_filename); - } - // If we removed any entries, we need to rebuild the entries list, - // write the header, and call this again - std::vector new_entries; - for (U32 i=0; i 0) + + //make sure that pruning entries doesn't take too much time + if (timer.getElapsedTimeF32() > TEXTURE_PRUNING_MAX_TIME) { - new_entries.push_back(entry); + break; } } - mFreeList.clear(); // recreating list, no longer valid. - llassert_always(new_entries.size() <= sCacheMaxEntries); - mHeaderEntriesInfo.mEntries = new_entries.size(); - writeEntriesHeader(); - writeEntriesAndClose(new_entries); - mHeaderMutex.unlock(); // unlock the mutex before calling again - readHeaderCache(); // repeat with new entries file - mHeaderMutex.lock(); + writeEntriesAndClose(entries); } else { @@ -1724,7 +1713,7 @@ void LLTextureCache::purgeTexturesLazy(F32 time_limit_sec) } S64 cache_size = mTexturesSizeTotal; - S64 purged_cache_size = (sCacheMaxTexturesSize * (S64)((1.f - TEXTURE_CACHE_PURGE_AMOUNT) * 100)) / 100; + S64 purged_cache_size = (llmax(cache_size, sCacheMaxTexturesSize) * (S64)((1.f - TEXTURE_CACHE_PURGE_AMOUNT) * 100)) / 100; for (time_idx_set_t::iterator iter = time_idx_set.begin(); iter != time_idx_set.end(); ++iter) { @@ -1820,21 +1809,26 @@ void LLTextureCache::purgeTextures(bool validate) } S64 cache_size = mTexturesSizeTotal; - S64 purged_cache_size = (sCacheMaxTexturesSize * (S64)((1.f-TEXTURE_CACHE_PURGE_AMOUNT)*100)) / 100; + S64 purged_cache_size = (llmax(cache_size, sCacheMaxTexturesSize) * (S64)((1.f - TEXTURE_CACHE_PURGE_AMOUNT) * 100)) / 100; S32 purge_count = 0; for (time_idx_set_t::iterator iter = time_idx_set.begin(); iter != time_idx_set.end(); ++iter) { S32 idx = iter->second; bool purge_entry = false; - if (validate) + + if (cache_size >= purged_cache_size) + { + purge_entry = true; + } + else if (validate) { // make sure file exists and is the correct size U32 uuididx = entries[idx].mID.mData[0]; if (uuididx == validate_idx) { - std::string filename = getTextureFileName(entries[idx].mID); - LL_DEBUGS("TextureCache") << "Validating: " << filename << "Size: " << entries[idx].mBodySize << LL_ENDL; + std::string filename = getTextureFileName(entries[idx].mID); + LL_DEBUGS("TextureCache") << "Validating: " << filename << "Size: " << entries[idx].mBodySize << LL_ENDL; // mHeaderAPRFilePoolp because this is under header mutex in main thread S32 bodysize = LLAPRFile::size(filename, mHeaderAPRFilePoolp); if (bodysize != entries[idx].mBodySize) @@ -1844,10 +1838,6 @@ void LLTextureCache::purgeTextures(bool validate) } } } - else if (cache_size >= purged_cache_size) - { - purge_entry = true; - } else { break; diff --git a/indra/newview/llviewerassetstorage.cpp b/indra/newview/llviewerassetstorage.cpp index 54f80a2995..0f2901406a 100644 --- a/indra/newview/llviewerassetstorage.cpp +++ b/indra/newview/llviewerassetstorage.cpp @@ -28,8 +28,7 @@ #include "llviewerassetstorage.h" -#include "llvfile.h" -#include "llvfs.h" +#include "llfilesystem.h" #include "message.h" #include "llagent.h" @@ -104,10 +103,8 @@ public: ///---------------------------------------------------------------------------- // Unused? -LLViewerAssetStorage::LLViewerAssetStorage(LLMessageSystem *msg, LLXferManager *xfer, - LLVFS *vfs, LLVFS *static_vfs, - const LLHost &upstream_host) - : LLAssetStorage(msg, xfer, vfs, static_vfs, upstream_host), +LLViewerAssetStorage::LLViewerAssetStorage(LLMessageSystem *msg, LLXferManager *xfer, const LLHost &upstream_host) + : LLAssetStorage(msg, xfer, upstream_host), mAssetCoroCount(0), mCountRequests(0), mCountStarted(0), @@ -117,10 +114,8 @@ LLViewerAssetStorage::LLViewerAssetStorage(LLMessageSystem *msg, LLXferManager * { } - -LLViewerAssetStorage::LLViewerAssetStorage(LLMessageSystem *msg, LLXferManager *xfer, - LLVFS *vfs, LLVFS *static_vfs) - : LLAssetStorage(msg, xfer, vfs, static_vfs), +LLViewerAssetStorage::LLViewerAssetStorage(LLMessageSystem *msg, LLXferManager *xfer) + : LLAssetStorage(msg, xfer), mAssetCoroCount(0), mCountRequests(0), mCountStarted(0), @@ -157,13 +152,13 @@ void LLViewerAssetStorage::storeAssetData( if (mUpstreamHost.isOk()) { - if (mVFS->getExists(asset_id, asset_type)) + if (LLFileSystem::getExists(asset_id, asset_type)) { // Pack data into this packet if we can fit it. U8 buffer[MTUBYTES]; buffer[0] = 0; - LLVFile vfile(mVFS, asset_id, asset_type, LLVFile::READ); + LLFileSystem vfile(asset_id, asset_type, LLFileSystem::READ); S32 asset_size = vfile.getSize(); LLAssetRequest *req = new LLAssetRequest(asset_id, asset_type); @@ -172,22 +167,20 @@ void LLViewerAssetStorage::storeAssetData( if (asset_size < 1) { - // This can happen if there's a bug in our code or if the VFS has been corrupted. - LL_WARNS("AssetStorage") << "LLViewerAssetStorage::storeAssetData() Data _should_ already be in the VFS, but it's not! " << asset_id << LL_ENDL; - // LLAssetStorage metric: Zero size VFS - reportMetric( asset_id, asset_type, LLStringUtil::null, LLUUID::null, 0, MR_ZERO_SIZE, __FILE__, __LINE__, "The file didn't exist or was zero length (VFS - can't tell which)" ); + // This can happen if there's a bug in our code or if the cache has been corrupted. + LL_WARNS("AssetStorage") << "LLViewerAssetStorage::storeAssetData() Data _should_ already be in the cache, but it's not! " << asset_id << LL_ENDL; delete req; if (callback) { - callback(asset_id, user_data, LL_ERR_ASSET_REQUEST_FAILED, LLExtStat::VFS_CORRUPT); + callback(asset_id, user_data, LL_ERR_ASSET_REQUEST_FAILED, LLExtStat::CACHE_CORRUPT); } return; } else { // LLAssetStorage metric: Successful Request - S32 size = mVFS->getSize(asset_id, asset_type); + S32 size = LLFileSystem::getFileSize(asset_id, asset_type); const char *message = "Added to upload queue"; reportMetric( asset_id, asset_type, LLStringUtil::null, LLUUID::null, size, MR_OKAY, __FILE__, __LINE__, message ); @@ -201,7 +194,7 @@ void LLViewerAssetStorage::storeAssetData( } } - // Read the data from the VFS if it'll fit in this packet. + // Read the data from the cache if it'll fit in this packet. if (asset_size + 100 < MTUBYTES) { BOOL res = vfile.read(buffer, asset_size); /* Flawfinder: ignore */ @@ -214,14 +207,11 @@ void LLViewerAssetStorage::storeAssetData( } else { - LL_WARNS("AssetStorage") << "Probable corruption in VFS file, aborting store asset data" << LL_ENDL; - - // LLAssetStorage metric: VFS corrupt - bogus size - reportMetric( asset_id, asset_type, LLStringUtil::null, LLUUID::null, asset_size, MR_VFS_CORRUPTION, __FILE__, __LINE__, "VFS corruption" ); + LL_WARNS("AssetStorage") << "Probable corruption in cache file, aborting store asset data" << LL_ENDL; if (callback) { - callback(asset_id, user_data, LL_ERR_ASSET_REQUEST_NONEXISTENT_FILE, LLExtStat::VFS_CORRUPT); + callback(asset_id, user_data, LL_ERR_ASSET_REQUEST_NONEXISTENT_FILE, LLExtStat::CACHE_CORRUPT); } return; } @@ -244,8 +234,7 @@ void LLViewerAssetStorage::storeAssetData( else { LL_WARNS("AssetStorage") << "AssetStorage: attempt to upload non-existent vfile " << asset_id << ":" << LLAssetType::lookup(asset_type) << LL_ENDL; - // LLAssetStorage metric: Zero size VFS - reportMetric( asset_id, asset_type, LLStringUtil::null, LLUUID::null, 0, MR_ZERO_SIZE, __FILE__, __LINE__, "The file didn't exist or was zero length (VFS - can't tell which)" ); + reportMetric( asset_id, asset_type, LLStringUtil::null, LLUUID::null, 0, MR_ZERO_SIZE, __FILE__, __LINE__, "The file didn't exist or was zero length (cache - can't tell which)" ); if (callback) { callback(asset_id, user_data, LL_ERR_ASSET_REQUEST_NONEXISTENT_FILE, LLExtStat::NONEXISTENT_FILE); @@ -278,7 +267,6 @@ void LLViewerAssetStorage::storeAssetData( if(filename.empty()) { // LLAssetStorage metric: no filename - reportMetric( LLUUID::null, asset_type, LLStringUtil::null, LLUUID::null, 0, MR_VFS_CORRUPTION, __FILE__, __LINE__, "Filename missing" ); LL_ERRS() << "No filename specified" << LL_ENDL; return; } @@ -303,9 +291,7 @@ void LLViewerAssetStorage::storeAssetData( legacy->mUpCallback = callback; legacy->mUserData = user_data; - LLVFile file(mVFS, asset_id, asset_type, LLVFile::WRITE); - - file.setMaxSize(size); + LLFileSystem file(asset_id, asset_type, LLFileSystem::APPEND); const S32 buf_size = 65536; U8 copy_buf[buf_size]; @@ -539,21 +525,20 @@ void LLViewerAssetStorage::assetRequestCoro( // case. LLUUID temp_id; temp_id.generate(); - LLVFile vf(gAssetStorage->mVFS, temp_id, atype, LLVFile::WRITE); - vf.setMaxSize(size); + LLFileSystem vf(temp_id, atype, LLFileSystem::WRITE); req->mBytesFetched = size; if (!vf.write(raw.data(),size)) { // TODO asset-http: handle error LL_WARNS("ViewerAsset") << "Failure in vf.write()" << LL_ENDL; result_code = LL_ERR_ASSET_REQUEST_FAILED; - ext_status = LLExtStat::VFS_CORRUPT; + ext_status = LLExtStat::CACHE_CORRUPT; } else if (!vf.rename(uuid, atype)) { LL_WARNS("ViewerAsset") << "rename failed" << LL_ENDL; result_code = LL_ERR_ASSET_REQUEST_FAILED; - ext_status = LLExtStat::VFS_CORRUPT; + ext_status = LLExtStat::CACHE_CORRUPT; } else { diff --git a/indra/newview/llviewerassetstorage.h b/indra/newview/llviewerassetstorage.h index ef01d179b7..972c89de34 100644 --- a/indra/newview/llviewerassetstorage.h +++ b/indra/newview/llviewerassetstorage.h @@ -30,18 +30,16 @@ #include "llassetstorage.h" #include "llcorehttputil.h" -class LLVFile; +class LLFileSystem; class LLViewerAssetRequest; class LLViewerAssetStorage : public LLAssetStorage { public: - LLViewerAssetStorage(LLMessageSystem *msg, LLXferManager *xfer, - LLVFS *vfs, LLVFS *static_vfs, const LLHost &upstream_host); + LLViewerAssetStorage(LLMessageSystem *msg, LLXferManager *xfer, const LLHost &upstream_host); - LLViewerAssetStorage(LLMessageSystem *msg, LLXferManager *xfer, - LLVFS *vfs, LLVFS *static_vfs); + LLViewerAssetStorage(LLMessageSystem *msg, LLXferManager *xfer); ~LLViewerAssetStorage(); diff --git a/indra/newview/llviewerassetupload.cpp b/indra/newview/llviewerassetupload.cpp index f2e887a678..7b5229d312 100644 --- a/indra/newview/llviewerassetupload.cpp +++ b/indra/newview/llviewerassetupload.cpp @@ -45,7 +45,7 @@ #include "llviewerassetupload.h" #include "llappviewer.h" #include "llviewerstats.h" -#include "llvfile.h" +#include "llfilesystem.h" #include "llgesturemgr.h" #include "llpreviewnotecard.h" #include "llpreviewgesture.h" @@ -467,7 +467,7 @@ LLSD LLNewFileResourceUploadInfo::exportTempFile() setAssetType(assetType); - // copy this file into the vfs for upload + // copy this file into the cache for upload S32 file_size; LLAPRFile infile; infile.open(filename, LL_APR_RB, NULL, &file_size); @@ -505,7 +505,7 @@ LLBufferedAssetUploadInfo::LLBufferedAssetUploadInfo(LLUUID itemId, LLAssetType: mContents(buffer), mInvnFinishFn(finish), mTaskFinishFn(nullptr), - mStoredToVFS(false) + mStoredToCache(false) { setItemId(itemId); setAssetType(assetType); @@ -519,7 +519,7 @@ LLBufferedAssetUploadInfo::LLBufferedAssetUploadInfo(LLUUID itemId, LLPointerrenameFile(getAssetId(), assetType, newAssetId, assetType); + LLFileSystem::renameFile(getAssetId(), assetType, newAssetId, assetType); } if (mTaskUpload) diff --git a/indra/newview/llviewerassetupload.h b/indra/newview/llviewerassetupload.h index d9eacf3167..e56ba7d8f7 100644 --- a/indra/newview/llviewerassetupload.h +++ b/indra/newview/llviewerassetupload.h @@ -197,7 +197,7 @@ private: std::string mContents; invnUploadFinish_f mInvnFinishFn; taskUploadFinish_f mTaskFinishFn; - bool mStoredToVFS; + bool mStoredToCache; }; //------------------------------------------------------------------------- diff --git a/indra/newview/llviewermedia_streamingaudio.cpp b/indra/newview/llviewermedia_streamingaudio.cpp index 3ccf3070ab..d3e24aece5 100644 --- a/indra/newview/llviewermedia_streamingaudio.cpp +++ b/indra/newview/llviewermedia_streamingaudio.cpp @@ -33,10 +33,8 @@ #include "llviewermedia_streamingaudio.h" #include "llmimetypes.h" -#include "llvfs.h" #include "lldir.h" - LLStreamingAudio_MediaPlugins::LLStreamingAudio_MediaPlugins() : mMediaPlugin(NULL), mGain(1.0) diff --git a/indra/newview/llviewermenufile.cpp b/indra/newview/llviewermenufile.cpp index 4b231c7067..e59a263adc 100644 --- a/indra/newview/llviewermenufile.cpp +++ b/indra/newview/llviewermenufile.cpp @@ -53,8 +53,6 @@ #include "llviewercontrol.h" // gSavedSettings #include "llviewertexturelist.h" #include "lluictrlfactory.h" -#include "llvfile.h" -#include "llvfs.h" #include "llviewerinventory.h" #include "llviewermenu.h" // gMenuHolder #include "llviewerparcelmgr.h" diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp index 458fc3b13d..6ef452bd92 100644 --- a/indra/newview/llviewermessage.cpp +++ b/indra/newview/llviewermessage.cpp @@ -44,8 +44,7 @@ #include "llteleportflags.h" #include "lltoastnotifypanel.h" #include "lltransactionflags.h" -#include "llvfile.h" -#include "llvfs.h" +#include "llfilesystem.h" #include "llxfermanager.h" #include "mean_collision_data.h" @@ -6844,16 +6843,15 @@ void process_covenant_reply(LLMessageSystem* msg, void**) } } -void onCovenantLoadComplete(LLVFS *vfs, - const LLUUID& asset_uuid, - LLAssetType::EType type, - void* user_data, S32 status, LLExtStat ext_status) +void onCovenantLoadComplete(const LLUUID& asset_uuid, + LLAssetType::EType type, + void* user_data, S32 status, LLExtStat ext_status) { LL_DEBUGS("Messaging") << "onCovenantLoadComplete()" << LL_ENDL; std::string covenant_text; if(0 == status) { - LLVFile file(vfs, asset_uuid, type, LLVFile::READ); + LLFileSystem file(asset_uuid, type, LLFileSystem::READ); S32 file_length = file.getSize(); diff --git a/indra/newview/llviewermessage.h b/indra/newview/llviewermessage.h index 78829a6a56..1e5a69ae13 100644 --- a/indra/newview/llviewermessage.h +++ b/indra/newview/llviewermessage.h @@ -47,7 +47,6 @@ class LLInventoryObject; class LLInventoryItem; class LLMeanCollisionData; class LLMessageSystem; -class LLVFS; class LLViewerObject; class LLViewerRegion; @@ -189,8 +188,7 @@ void process_script_dialog(LLMessageSystem* msg, void**); void process_load_url(LLMessageSystem* msg, void**); void process_script_teleport_request(LLMessageSystem* msg, void**); void process_covenant_reply(LLMessageSystem* msg, void**); -void onCovenantLoadComplete(LLVFS *vfs, - const LLUUID& asset_uuid, +void onCovenantLoadComplete(const LLUUID& asset_uuid, LLAssetType::EType type, void* user_data, S32 status, LLExtStat ext_status); diff --git a/indra/newview/llviewerprecompiledheaders.h b/indra/newview/llviewerprecompiledheaders.h index bbbacce8fa..e378c2448a 100644 --- a/indra/newview/llviewerprecompiledheaders.h +++ b/indra/newview/llviewerprecompiledheaders.h @@ -101,7 +101,6 @@ #include "v4math.h" #include "xform.h" -// Library includes from llvfs #include "lldir.h" // Library includes from llmessage project diff --git a/indra/newview/llviewerstats.cpp b/indra/newview/llviewerstats.cpp index 05f88b0a75..35fb4de5a9 100644 --- a/indra/newview/llviewerstats.cpp +++ b/indra/newview/llviewerstats.cpp @@ -33,7 +33,6 @@ #include "llfloaterreg.h" #include "llmemory.h" #include "lltimer.h" -#include "llvfile.h" #include "llappviewer.h" @@ -145,7 +144,6 @@ LLTrace::SampleStatHandle<> FPS_SAMPLE("fpssample"), VISIBLE_AVATARS("visibleavatars", "Visible Avatars"), SHADER_OBJECTS("shaderobjects", "Object Shaders"), DRAW_DISTANCE("drawdistance", "Draw Distance"), - PENDING_VFS_OPERATIONS("vfspendingoperations"), WINDOW_WIDTH("windowwidth", "Window width"), WINDOW_HEIGHT("windowheight", "Window height"); @@ -383,7 +381,6 @@ void update_statistics() F64Bits layer_bits = gVLManager.getLandBits() + gVLManager.getWindBits() + gVLManager.getCloudBits(); add(LLStatViewer::LAYERS_NETWORK_DATA_RECEIVED, layer_bits); add(LLStatViewer::OBJECT_NETWORK_DATA_RECEIVED, gObjectData); - sample(LLStatViewer::PENDING_VFS_OPERATIONS, LLVFile::getVFSThread()->getPending()); add(LLStatViewer::ASSET_UDP_DATA_RECEIVED, F64Bits(gTransferManager.getTransferBitsIn(LLTCT_ASSET))); gTransferManager.resetTransferBitsIn(LLTCT_ASSET); diff --git a/indra/newview/llviewerstats.h b/indra/newview/llviewerstats.h index 04870e0c26..72ce336664 100644 --- a/indra/newview/llviewerstats.h +++ b/indra/newview/llviewerstats.h @@ -186,7 +186,6 @@ extern LLTrace::SampleStatHandle<> FPS_SAMPLE, VISIBLE_AVATARS, SHADER_OBJECTS, DRAW_DISTANCE, - PENDING_VFS_OPERATIONS, WINDOW_WIDTH, WINDOW_HEIGHT; diff --git a/indra/newview/llviewertexlayer.cpp b/indra/newview/llviewertexlayer.cpp index c501dd0035..4c2fbcf837 100644 --- a/indra/newview/llviewertexlayer.cpp +++ b/indra/newview/llviewertexlayer.cpp @@ -31,8 +31,6 @@ #include "llagent.h" #include "llimagej2c.h" #include "llnotificationsutil.h" -#include "llvfile.h" -#include "llvfs.h" #include "llviewerregion.h" #include "llglslshader.h" #include "llvoavatarself.h" diff --git a/indra/newview/llviewertexture.cpp b/indra/newview/llviewertexture.cpp index 20a22ba45e..d69ab1b110 100644 --- a/indra/newview/llviewertexture.cpp +++ b/indra/newview/llviewertexture.cpp @@ -39,8 +39,6 @@ #include "llimagej2c.h" #include "llimagetga.h" #include "llstl.h" -#include "llvfile.h" -#include "llvfs.h" #include "message.h" #include "lltimer.h" diff --git a/indra/newview/llviewertexture.h b/indra/newview/llviewertexture.h index 69568cc825..07997e02a5 100644 --- a/indra/newview/llviewertexture.h +++ b/indra/newview/llviewertexture.h @@ -54,7 +54,7 @@ class LLTexturePipelineTester ; typedef void (*loaded_callback_func)( BOOL success, LLViewerFetchedTexture *src_vi, LLImageRaw* src, LLImageRaw* src_aux, S32 discard_level, BOOL final, void* userdata ); -class LLVFile; +class LLFileSystem; class LLMessageSystem; class LLViewerMediaImpl ; class LLVOVolume ; diff --git a/indra/newview/llviewertexturelist.cpp b/indra/newview/llviewertexturelist.cpp index 561319ca5d..38fccba169 100644 --- a/indra/newview/llviewertexturelist.cpp +++ b/indra/newview/llviewertexturelist.cpp @@ -41,9 +41,7 @@ #include "llsdserialize.h" #include "llsys.h" -#include "llvfs.h" -#include "llvfile.h" -#include "llvfsthread.h" +#include "llfilesystem.h" #include "llxmltree.h" #include "message.h" diff --git a/indra/newview/llviewerwearable.cpp b/indra/newview/llviewerwearable.cpp index 9c4dfd1ca2..9a4607bb60 100644 --- a/indra/newview/llviewerwearable.cpp +++ b/indra/newview/llviewerwearable.cpp @@ -107,7 +107,6 @@ LLWearable::EImportResult LLViewerWearable::importStream( std::istream& input_st // Shouldn't really log the asset id for security reasons, but // we need it in this case. LL_WARNS() << "Bad Wearable asset header: " << mAssetID << LL_ENDL; - //gVFS->dumpMap(); return result; } diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp index f69b9b3861..414a1da4fe 100644 --- a/indra/newview/llvoavatar.cpp +++ b/indra/newview/llvoavatar.cpp @@ -1140,7 +1140,6 @@ void LLVOAvatar::initInstance() //------------------------------------------------------------------------- if (LLCharacter::sInstances.size() == 1) { - LLKeyframeMotion::setVFS(gStaticVFS); registerMotion( ANIM_AGENT_DO_NOT_DISTURB, LLNullMotion::create ); registerMotion( ANIM_AGENT_CROUCH, LLKeyframeStandMotion::create ); registerMotion( ANIM_AGENT_CROUCHWALK, LLKeyframeWalkMotion::create ); diff --git a/indra/newview/llvovolume.h b/indra/newview/llvovolume.h index ce400a3498..73eeec813c 100644 --- a/indra/newview/llvovolume.h +++ b/indra/newview/llvovolume.h @@ -218,10 +218,9 @@ public: void updateSculptTexture(); void setIndexInTex(U32 ch, S32 index) { mIndexInTex[ch] = index ;} void sculpt(); - static void rebuildMeshAssetCallback(LLVFS *vfs, - const LLUUID& asset_uuid, - LLAssetType::EType type, - void* user_data, S32 status, LLExtStat ext_status); + static void rebuildMeshAssetCallback(const LLUUID& asset_uuid, + LLAssetType::EType type, + void* user_data, S32 status, LLExtStat ext_status); void updateRelativeXform(bool force_identity = false); /*virtual*/ BOOL updateGeometry(LLDrawable *drawable); diff --git a/indra/newview/skins/default/xui/da/floater_stats.xml b/indra/newview/skins/default/xui/da/floater_stats.xml index fe3fa9626e..d07f9e48ca 100644 --- a/indra/newview/skins/default/xui/da/floater_stats.xml +++ b/indra/newview/skins/default/xui/da/floater_stats.xml @@ -32,7 +32,6 @@ - diff --git a/indra/newview/skins/default/xui/da/strings.xml b/indra/newview/skins/default/xui/da/strings.xml index ec6ba4800d..814305c1bc 100644 --- a/indra/newview/skins/default/xui/da/strings.xml +++ b/indra/newview/skins/default/xui/da/strings.xml @@ -22,9 +22,6 @@ Initialiserer tekstur cache... - - Initialiserer VFS... - Gendanner... diff --git a/indra/newview/skins/default/xui/de/floater_scene_load_stats.xml b/indra/newview/skins/default/xui/de/floater_scene_load_stats.xml index dff462a594..a3749f1cfa 100644 --- a/indra/newview/skins/default/xui/de/floater_scene_load_stats.xml +++ b/indra/newview/skins/default/xui/de/floater_scene_load_stats.xml @@ -29,7 +29,6 @@ - diff --git a/indra/newview/skins/default/xui/de/floater_stats.xml b/indra/newview/skins/default/xui/de/floater_stats.xml index 4e6f56cd94..1838c2081a 100644 --- a/indra/newview/skins/default/xui/de/floater_stats.xml +++ b/indra/newview/skins/default/xui/de/floater_stats.xml @@ -56,7 +56,6 @@ - diff --git a/indra/newview/skins/default/xui/de/strings.xml b/indra/newview/skins/default/xui/de/strings.xml index 43327c132d..f021e03dc7 100644 --- a/indra/newview/skins/default/xui/de/strings.xml +++ b/indra/newview/skins/default/xui/de/strings.xml @@ -31,9 +31,6 @@ Textur-Cache wird initialisiert... - - VFS wird initialisiert... - Grafikinitialisierung fehlgeschlagen. Bitte aktualisieren Sie Ihren Grafiktreiber. @@ -73,7 +70,6 @@ LOD-Faktor: [LOD_FACTOR] Darstellungsqualität: [RENDER_QUALITY] Erweitertes Beleuchtungsmodell: [GPU_SHADERS] Texturspeicher: [TEXTURE_MEMORY] MB -Erstellungszeit VFS (Cache): [VFS_TIME] HiDPI-Anzeigemodus: [HIDPI] diff --git a/indra/newview/skins/default/xui/en/floater_scene_load_stats.xml b/indra/newview/skins/default/xui/en/floater_scene_load_stats.xml index 62cce3a1e3..35d4385487 100644 --- a/indra/newview/skins/default/xui/en/floater_scene_load_stats.xml +++ b/indra/newview/skins/default/xui/en/floater_scene_load_stats.xml @@ -206,12 +206,6 @@ bar_max="1024.f" tick_spacing="128.f" precision="1" - show_bar="false"/> - diff --git a/indra/newview/skins/default/xui/en/floater_stats.xml b/indra/newview/skins/default/xui/en/floater_stats.xml index e4f735740b..f9d44b2c69 100644 --- a/indra/newview/skins/default/xui/en/floater_stats.xml +++ b/indra/newview/skins/default/xui/en/floater_stats.xml @@ -198,10 +198,6 @@ stat="messagedataout" decimal_digits="1" show_history="false"/> - diff --git a/indra/newview/skins/default/xui/en/strings.xml b/indra/newview/skins/default/xui/en/strings.xml index f9f12e7f5c..619c869a3d 100644 --- a/indra/newview/skins/default/xui/en/strings.xml +++ b/indra/newview/skins/default/xui/en/strings.xml @@ -17,7 +17,6 @@ Loading [APP_NAME]... Clearing cache... Initializing texture cache... - Initializing VFS... Graphics initialization failed. Please update your graphics driver! @@ -56,9 +55,9 @@ LOD factor: [LOD_FACTOR] Render quality: [RENDER_QUALITY] Advanced Lighting Model: [GPU_SHADERS] Texture memory: [TEXTURE_MEMORY]MB -VFS (cache) creation time: [VFS_TIME] +Disk cache: [DISK_CACHE_INFO] - + HiDPI display mode: [HIDPI] diff --git a/indra/newview/skins/default/xui/es/floater_scene_load_stats.xml b/indra/newview/skins/default/xui/es/floater_scene_load_stats.xml index f625d5257c..cfc5e524b5 100644 --- a/indra/newview/skins/default/xui/es/floater_scene_load_stats.xml +++ b/indra/newview/skins/default/xui/es/floater_scene_load_stats.xml @@ -29,7 +29,6 @@ - diff --git a/indra/newview/skins/default/xui/es/floater_stats.xml b/indra/newview/skins/default/xui/es/floater_stats.xml index d1c5e867db..0aec786f25 100644 --- a/indra/newview/skins/default/xui/es/floater_stats.xml +++ b/indra/newview/skins/default/xui/es/floater_stats.xml @@ -56,7 +56,6 @@ - diff --git a/indra/newview/skins/default/xui/es/strings.xml b/indra/newview/skins/default/xui/es/strings.xml index f5e7d0bf4e..ebb4ceaa7e 100644 --- a/indra/newview/skins/default/xui/es/strings.xml +++ b/indra/newview/skins/default/xui/es/strings.xml @@ -22,9 +22,6 @@ Iniciando la caché de las texturas... - - Iniciando VFS... - Error de inicialización de gráficos. Actualiza tu controlador de gráficos. @@ -65,7 +62,6 @@ Factor LOD: [LOD_FACTOR] Calidad de renderización: [RENDER_QUALITY] Modelo de iluminación avanzado: [GPU_SHADERS] Memoria de textura: [TEXTURE_MEMORY]MB -VFS (cache) hora de creación: [VFS_TIME] Modo de visualización HiDPi: [HIDPI] diff --git a/indra/newview/skins/default/xui/fr/floater_scene_load_stats.xml b/indra/newview/skins/default/xui/fr/floater_scene_load_stats.xml index 62830054bf..3889b13f0c 100644 --- a/indra/newview/skins/default/xui/fr/floater_scene_load_stats.xml +++ b/indra/newview/skins/default/xui/fr/floater_scene_load_stats.xml @@ -29,7 +29,6 @@ - diff --git a/indra/newview/skins/default/xui/fr/floater_stats.xml b/indra/newview/skins/default/xui/fr/floater_stats.xml index fae17e3608..d0f7f42939 100644 --- a/indra/newview/skins/default/xui/fr/floater_stats.xml +++ b/indra/newview/skins/default/xui/fr/floater_stats.xml @@ -56,7 +56,6 @@ - diff --git a/indra/newview/skins/default/xui/fr/strings.xml b/indra/newview/skins/default/xui/fr/strings.xml index f26eac545a..9fde703d6c 100644 --- a/indra/newview/skins/default/xui/fr/strings.xml +++ b/indra/newview/skins/default/xui/fr/strings.xml @@ -31,9 +31,6 @@ Initialisation du cache des textures... - - Initialisation VFS... - Échec d'initialisation des graphiques. Veuillez mettre votre pilote graphique à jour. @@ -74,7 +71,6 @@ Facteur LOD (niveau de détail) : [LOD_FACTOR] Qualité de rendu : [RENDER_QUALITY] Modèle d’éclairage avancé : [GPU_SHADERS] Mémoire textures : [TEXTURE_MEMORY] Mo -Heure de création VFS (cache) : [VFS_TIME] Mode d'affichage HiDPI : [HIDPI] diff --git a/indra/newview/skins/default/xui/it/floater_scene_load_stats.xml b/indra/newview/skins/default/xui/it/floater_scene_load_stats.xml index ca18812eb7..efceb05298 100644 --- a/indra/newview/skins/default/xui/it/floater_scene_load_stats.xml +++ b/indra/newview/skins/default/xui/it/floater_scene_load_stats.xml @@ -29,7 +29,6 @@ - diff --git a/indra/newview/skins/default/xui/it/floater_stats.xml b/indra/newview/skins/default/xui/it/floater_stats.xml index 7ef13aa37f..6434c3b66b 100644 --- a/indra/newview/skins/default/xui/it/floater_stats.xml +++ b/indra/newview/skins/default/xui/it/floater_stats.xml @@ -56,7 +56,6 @@ - diff --git a/indra/newview/skins/default/xui/it/strings.xml b/indra/newview/skins/default/xui/it/strings.xml index f0466cea81..3049828f46 100644 --- a/indra/newview/skins/default/xui/it/strings.xml +++ b/indra/newview/skins/default/xui/it/strings.xml @@ -28,9 +28,6 @@ Inizializzazione della cache texture... - - Inizializzazione VFS... - Inizializzazione grafica non riuscita. Aggiorna il driver della scheda grafica! @@ -71,7 +68,6 @@ Fattore livello di dettaglio: [LOD_FACTOR] Qualità di rendering: [RENDER_QUALITY] Modello illuminazione avanzato: [GPU_SHADERS] Memoria texture: [TEXTURE_MEMORY]MB -Data/ora creazione VFS (cache): [VFS_TIME] Modalità display HiDPI: [HIDPI] diff --git a/indra/newview/skins/default/xui/ja/floater_scene_load_stats.xml b/indra/newview/skins/default/xui/ja/floater_scene_load_stats.xml index f6edce026f..f348ce3c4d 100644 --- a/indra/newview/skins/default/xui/ja/floater_scene_load_stats.xml +++ b/indra/newview/skins/default/xui/ja/floater_scene_load_stats.xml @@ -29,7 +29,6 @@ - diff --git a/indra/newview/skins/default/xui/ja/floater_stats.xml b/indra/newview/skins/default/xui/ja/floater_stats.xml index 3bc343639b..1da0e5ebc9 100644 --- a/indra/newview/skins/default/xui/ja/floater_stats.xml +++ b/indra/newview/skins/default/xui/ja/floater_stats.xml @@ -56,7 +56,6 @@ - diff --git a/indra/newview/skins/default/xui/ja/strings.xml b/indra/newview/skins/default/xui/ja/strings.xml index 52d6fb0c2b..dcd6e65d34 100644 --- a/indra/newview/skins/default/xui/ja/strings.xml +++ b/indra/newview/skins/default/xui/ja/strings.xml @@ -31,9 +31,6 @@ テクスチャキャッシュを初期化中です... - - VFS を初期化中です... - グラフィックを初期化できませんでした。グラフィックドライバを更新してください。 @@ -74,7 +71,6 @@ LOD 係数: [LOD_FACTOR] 描画の質: [RENDER_QUALITY] 高度なライティングモデル: [GPU_SHADERS] テクスチャメモリ: [TEXTURE_MEMORY]MB -VFS(キャッシュ)作成時間: [VFS_TIME] HiDPI 表示モード: [HIDPI] diff --git a/indra/newview/skins/default/xui/pl/floater_scene_load_stats.xml b/indra/newview/skins/default/xui/pl/floater_scene_load_stats.xml index 6fdc7e19f6..8f5d0c5c70 100644 --- a/indra/newview/skins/default/xui/pl/floater_scene_load_stats.xml +++ b/indra/newview/skins/default/xui/pl/floater_scene_load_stats.xml @@ -29,7 +29,6 @@ - diff --git a/indra/newview/skins/default/xui/pl/floater_stats.xml b/indra/newview/skins/default/xui/pl/floater_stats.xml index 5dd7d19bab..21e37717c2 100644 --- a/indra/newview/skins/default/xui/pl/floater_stats.xml +++ b/indra/newview/skins/default/xui/pl/floater_stats.xml @@ -55,7 +55,6 @@ - diff --git a/indra/newview/skins/default/xui/pl/strings.xml b/indra/newview/skins/default/xui/pl/strings.xml index 91fea234d2..cf033df3c9 100644 --- a/indra/newview/skins/default/xui/pl/strings.xml +++ b/indra/newview/skins/default/xui/pl/strings.xml @@ -15,9 +15,6 @@ Inicjowanie bufora danych tekstur... - - Inicjowanie wirtualnego systemu plików... - Nie można zainicjować grafiki. Zaktualizuj sterowniki! diff --git a/indra/newview/skins/default/xui/pt/floater_scene_load_stats.xml b/indra/newview/skins/default/xui/pt/floater_scene_load_stats.xml index 027e1ef311..dbaab1d782 100644 --- a/indra/newview/skins/default/xui/pt/floater_scene_load_stats.xml +++ b/indra/newview/skins/default/xui/pt/floater_scene_load_stats.xml @@ -29,7 +29,6 @@ - diff --git a/indra/newview/skins/default/xui/pt/floater_stats.xml b/indra/newview/skins/default/xui/pt/floater_stats.xml index f41fe17778..3253984268 100644 --- a/indra/newview/skins/default/xui/pt/floater_stats.xml +++ b/indra/newview/skins/default/xui/pt/floater_stats.xml @@ -56,7 +56,6 @@ - diff --git a/indra/newview/skins/default/xui/pt/strings.xml b/indra/newview/skins/default/xui/pt/strings.xml index ee982b5b22..c72a41fd3a 100644 --- a/indra/newview/skins/default/xui/pt/strings.xml +++ b/indra/newview/skins/default/xui/pt/strings.xml @@ -22,9 +22,6 @@ Iniciando cache de texturas... - - Iniciando VFS... - Falha na inicialização dos gráficos. Atualize seu driver gráfico! @@ -65,7 +62,6 @@ LOD fator: [LOD_FACTOR] Qualidade de renderização: [RENDER_QUALITY] Modelo avançado de luzes: [GPU_SHADERS] Memória de textura: [TEXTURE_MEMORY]MB -VFS (cache) tempo de criação: [VFS_TIME] HiDPI modo de exibição: [HIDPI] diff --git a/indra/newview/skins/default/xui/ru/floater_scene_load_stats.xml b/indra/newview/skins/default/xui/ru/floater_scene_load_stats.xml index a101e62627..c4f432023c 100644 --- a/indra/newview/skins/default/xui/ru/floater_scene_load_stats.xml +++ b/indra/newview/skins/default/xui/ru/floater_scene_load_stats.xml @@ -29,7 +29,6 @@ - diff --git a/indra/newview/skins/default/xui/ru/floater_stats.xml b/indra/newview/skins/default/xui/ru/floater_stats.xml index 10e9f5a7f4..a7d26029c2 100644 --- a/indra/newview/skins/default/xui/ru/floater_stats.xml +++ b/indra/newview/skins/default/xui/ru/floater_stats.xml @@ -56,7 +56,6 @@ - diff --git a/indra/newview/skins/default/xui/ru/strings.xml b/indra/newview/skins/default/xui/ru/strings.xml index e9592a0476..43a87b2b18 100644 --- a/indra/newview/skins/default/xui/ru/strings.xml +++ b/indra/newview/skins/default/xui/ru/strings.xml @@ -31,9 +31,6 @@ Инициализация кэша текстур... - - Инициализация виртуальной файловой системы... - Ошибка инициализации графики. Обновите графический драйвер! @@ -74,7 +71,6 @@ SLURL: <nolink>[SLURL]</nolink> Качество визуализации: [RENDER_QUALITY] Расширенная модель освещения: [GPU_SHADERS] Память текстур: [TEXTURE_MEMORY] МБ -Время создания VFS (кэш): [VFS_TIME] Режим отображения HiDPI: [HIDPI] diff --git a/indra/newview/skins/default/xui/tr/floater_scene_load_stats.xml b/indra/newview/skins/default/xui/tr/floater_scene_load_stats.xml index ae0a94595d..7d5f4adb02 100644 --- a/indra/newview/skins/default/xui/tr/floater_scene_load_stats.xml +++ b/indra/newview/skins/default/xui/tr/floater_scene_load_stats.xml @@ -29,7 +29,6 @@ - diff --git a/indra/newview/skins/default/xui/tr/floater_stats.xml b/indra/newview/skins/default/xui/tr/floater_stats.xml index 1ae42ad382..bd36d4916f 100644 --- a/indra/newview/skins/default/xui/tr/floater_stats.xml +++ b/indra/newview/skins/default/xui/tr/floater_stats.xml @@ -56,7 +56,6 @@ - diff --git a/indra/newview/skins/default/xui/tr/strings.xml b/indra/newview/skins/default/xui/tr/strings.xml index 56fad978f5..982de76a5b 100644 --- a/indra/newview/skins/default/xui/tr/strings.xml +++ b/indra/newview/skins/default/xui/tr/strings.xml @@ -31,9 +31,6 @@ Doku önbelleği başlatılıyor... - - VFS Başlatılıyor... - Grafik başlatma başarılamadı. Lütfen grafik sürücünüzü güncelleştirin! @@ -74,7 +71,6 @@ LOD faktörü: [LOD_FACTOR] İşleme kalitesi: [RENDER_QUALITY] Gelişmiş Aydınlatma Modeli: [GPU_SHADERS] Doku belleği: [TEXTURE_MEMORY]MB -VFS (önbellek) oluşturma saati: [VFS_TIME] HiDPI görüntü modu: [HIDPI] diff --git a/indra/newview/skins/default/xui/zh/floater_scene_load_stats.xml b/indra/newview/skins/default/xui/zh/floater_scene_load_stats.xml index 1a5c20abeb..20344e299f 100644 --- a/indra/newview/skins/default/xui/zh/floater_scene_load_stats.xml +++ b/indra/newview/skins/default/xui/zh/floater_scene_load_stats.xml @@ -29,7 +29,6 @@ - diff --git a/indra/newview/skins/default/xui/zh/floater_stats.xml b/indra/newview/skins/default/xui/zh/floater_stats.xml index f06eb5e78f..e233ece527 100644 --- a/indra/newview/skins/default/xui/zh/floater_stats.xml +++ b/indra/newview/skins/default/xui/zh/floater_stats.xml @@ -56,7 +56,6 @@ - diff --git a/indra/newview/skins/default/xui/zh/strings.xml b/indra/newview/skins/default/xui/zh/strings.xml index e6c61a5d94..3221cde3b7 100644 --- a/indra/newview/skins/default/xui/zh/strings.xml +++ b/indra/newview/skins/default/xui/zh/strings.xml @@ -31,9 +31,6 @@ 正在初始化材質快取... - - VFS 初始化中... - 顯像初始化失敗。 請更新你的顯像卡驅動程式! @@ -74,7 +71,6 @@ 呈像品質:[RENDER_QUALITY] 進階照明模型:[GPU_SHADERS] 材質記憶體:[TEXTURE_MEMORY]MB -VFS(快取)建立時間:[VFS_TIME] HiDPI顯示模式:[HIDPI] diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py index 6d231040f7..8eee583a48 100755 --- a/indra/newview/viewer_manifest.py +++ b/indra/newview/viewer_manifest.py @@ -69,7 +69,6 @@ class ViewerManifest(LLManifest): self.exclude("logcontrol-dev.xml") self.path("*.ini") self.path("*.xml") - self.path("*.db2") # include the entire shaders directory recursively self.path("shaders") diff --git a/indra/test/CMakeLists.txt b/indra/test/CMakeLists.txt index 87536e146b..b3bff3611a 100644 --- a/indra/test/CMakeLists.txt +++ b/indra/test/CMakeLists.txt @@ -8,12 +8,11 @@ include(LLCoreHttp) include(LLInventory) include(LLMath) include(LLMessage) -include(LLVFS) +include(LLFileSystem) include(LLXML) include(Linking) include(Tut) include(LLAddBuildTest) - include(GoogleMock) include_directories( @@ -23,7 +22,7 @@ include_directories( ${LLMATH_INCLUDE_DIRS} ${LLMESSAGE_INCLUDE_DIRS} ${LLINVENTORY_INCLUDE_DIRS} - ${LLVFS_INCLUDE_DIRS} + ${LLFILESYSTEM_INCLUDE_DIRS} ${LLXML_INCLUDE_DIRS} ${LSCRIPT_INCLUDE_DIRS} ${GOOGLEMOCK_INCLUDE_DIRS} @@ -89,7 +88,7 @@ target_link_libraries(lltest ${LLINVENTORY_LIBRARIES} ${LLMESSAGE_LIBRARIES} ${LLMATH_LIBRARIES} - ${LLVFS_LIBRARIES} + ${LLFILESYSTEM_LIBRARIES} ${LLXML_LIBRARIES} ${LSCRIPT_LIBRARIES} ${LLCOMMON_LIBRARIES} diff --git a/indra/win_crash_logger/CMakeLists.txt b/indra/win_crash_logger/CMakeLists.txt index 86aa655f03..1b187d624a 100644 --- a/indra/win_crash_logger/CMakeLists.txt +++ b/indra/win_crash_logger/CMakeLists.txt @@ -8,7 +8,7 @@ include(LLCoreHttp) include(LLCrashLogger) include(LLMath) include(LLMessage) -include(LLVFS) +include(LLFileSystem) include(LLWindow) include(LLXML) include(Linking) @@ -23,7 +23,7 @@ include_directories( ${LLMATH_INCLUDE_DIRS} ${LLWINDOW_INCLUDE_DIRS} ${LLXML_INCLUDE_DIRS} - ${LLVFS_INCLUDE_DIRS} + ${LLFILESYSTEM_INCLUDE_DIRS} ${BREAKPAD_INCLUDE_DIRECTORIES} ) include_directories(SYSTEM @@ -76,7 +76,7 @@ target_link_libraries(windows-crash-logger ${BREAKPAD_EXCEPTION_HANDLER_LIBRARIES} ${LLCRASHLOGGER_LIBRARIES} ${LLWINDOW_LIBRARIES} - ${LLVFS_LIBRARIES} + ${LLFILESYSTEM_LIBRARIES} ${LLXML_LIBRARIES} ${LLMESSAGE_LIBRARIES} ${LLMATH_LIBRARIES} From d7518c7b4f5eca731d0ea143bab34b279bd4ee13 Mon Sep 17 00:00:00 2001 From: Callum Prentice Date: Tue, 9 Mar 2021 18:33:35 -0800 Subject: [PATCH 091/443] Ansariel kindly offered their patch to help mitigate this round of file system issues - taken from https://vcs.firestormviewer.org/phoenix-firestorm/changeset/104a8600946be01e2de44d10ad069ba854272d1f --- indra/llfilesystem/lldiskcache.cpp | 4 ++-- indra/llfilesystem/llfilesystem.cpp | 27 +++++++++++++++++++++++ indra/newview/llmeshrepository.cpp | 34 ++++++++++++++++++++++++----- 3 files changed, 58 insertions(+), 7 deletions(-) diff --git a/indra/llfilesystem/lldiskcache.cpp b/indra/llfilesystem/lldiskcache.cpp index c9f7684b5a..61eb654693 100644 --- a/indra/llfilesystem/lldiskcache.cpp +++ b/indra/llfilesystem/lldiskcache.cpp @@ -192,8 +192,8 @@ const std::string LLDiskCache::metaDataToFilepath(const std::string id, file_path << id; file_path << "_"; file_path << (extra_info.empty() ? "0" : extra_info); - //file_path << "_"; - //file_path << assetTypeToString(at); // see SL-14210 Prune descriptive tag from new cache filenames + file_path << "_"; + file_path << assetTypeToString(at); // see SL-14210 Prune descriptive tag from new cache filenames // for details of why it was removed. Note that if you put it // back or change the format of the filename, the cache files // files will be invalidated (and perhaps, more importantly, diff --git a/indra/llfilesystem/llfilesystem.cpp b/indra/llfilesystem/llfilesystem.cpp index 053b52014e..da44e8d98c 100644 --- a/indra/llfilesystem/llfilesystem.cpp +++ b/indra/llfilesystem/llfilesystem.cpp @@ -200,9 +200,36 @@ BOOL LLFileSystem::write(const U8* buffer, S32 bytes) { ofs.write((const char*)buffer, bytes); + mPosition = ofs.tellp(); // Fix asset caching + success = TRUE; } } + // Fix asset caching + else if (mMode == READ_WRITE) + { + // Don't truncate if file already exists + llofstream ofs(filename, std::ios::in | std::ios::binary); + if (ofs) + { + ofs.seekp(mPosition, std::ios::beg); + ofs.write((const char*)buffer, bytes); + mPosition += bytes; + success = TRUE; + } + else + { + // File doesn't exist - open in write mode + ofs.open(filename, std::ios::binary); + if (ofs.is_open()) + { + ofs.write((const char*)buffer, bytes); + mPosition += bytes; + success = TRUE; + } + } + } + // else { llofstream ofs(filename, std::ios::binary); diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp index 8e5bdc0225..c2404a7e67 100644 --- a/indra/newview/llmeshrepository.cpp +++ b/indra/newview/llmeshrepository.cpp @@ -3248,13 +3248,29 @@ void LLMeshHeaderHandler::processData(LLCore::BufferArray * /* body */, S32 /* b // only allocate as much space in the cache as is needed for the local cache data_size = llmin(data_size, bytes); - LLFileSystem file(mesh_id, LLAssetType::AT_MESH, LLFileSystem::WRITE); + // Fix asset caching + //LLFileSystem file(mesh_id, LLAssetType::AT_MESH, LLFileSystem::WRITE); + LLFileSystem file(mesh_id, LLAssetType::AT_MESH, LLFileSystem::READ_WRITE); if (file.getMaxSize() >= bytes) { LLMeshRepository::sCacheBytesWritten += data_size; ++LLMeshRepository::sCacheWrites; file.write(data, data_size); + + // Fix asset caching + S32 remaining = bytes - file.tell(); + if (remaining > 0) + { + U8* block = new(std::nothrow) U8[remaining]; + if (block) + { + memset(block, 0, remaining); + file.write(block, remaining); + delete[] block; + } + } + // } } else @@ -3307,7 +3323,9 @@ void LLMeshLODHandler::processData(LLCore::BufferArray * /* body */, S32 /* body if (result == MESH_OK) { // good fetch from sim, write to cache - LLFileSystem file(mMeshParams.getSculptID(), LLAssetType::AT_MESH, LLFileSystem::WRITE); + // Fix asset caching + //LLFileSystem file(mMeshParams.getSculptID(), LLAssetType::AT_MESH, LLFileSystem::WRITE); + LLFileSystem file(mMeshParams.getSculptID(), LLAssetType::AT_MESH, LLFileSystem::READ_WRITE); S32 offset = mOffset; S32 size = mRequestedBytes; @@ -3371,7 +3389,9 @@ void LLMeshSkinInfoHandler::processData(LLCore::BufferArray * /* body */, S32 /* && gMeshRepo.mThread->skinInfoReceived(mMeshID, data, data_size)) { // good fetch from sim, write to cache - LLFileSystem file(mMeshID, LLAssetType::AT_MESH, LLFileSystem::WRITE); + // Fix asset caching + //LLFileSystem file(mMeshID, LLAssetType::AT_MESH, LLFileSystem::WRITE); + LLFileSystem file(mMeshID, LLAssetType::AT_MESH, LLFileSystem::READ_WRITE); S32 offset = mOffset; S32 size = mRequestedBytes; @@ -3419,7 +3439,9 @@ void LLMeshDecompositionHandler::processData(LLCore::BufferArray * /* body */, S && gMeshRepo.mThread->decompositionReceived(mMeshID, data, data_size)) { // good fetch from sim, write to cache - LLFileSystem file(mMeshID, LLAssetType::AT_MESH, LLFileSystem::WRITE); + // Fix asset caching + //LLFileSystem file(mMeshID, LLAssetType::AT_MESH, LLFileSystem::WRITE); + LLFileSystem file(mMeshID, LLAssetType::AT_MESH, LLFileSystem::READ_WRITE); S32 offset = mOffset; S32 size = mRequestedBytes; @@ -3466,7 +3488,9 @@ void LLMeshPhysicsShapeHandler::processData(LLCore::BufferArray * /* body */, S3 && gMeshRepo.mThread->physicsShapeReceived(mMeshID, data, data_size) == MESH_OK) { // good fetch from sim, write to cache for caching - LLFileSystem file(mMeshID, LLAssetType::AT_MESH, LLFileSystem::WRITE); + // Fix asset caching + //LLFileSystem file(mMeshID, LLAssetType::AT_MESH, LLFileSystem::WRITE); + LLFileSystem file(mMeshID, LLAssetType::AT_MESH, LLFileSystem::READ_WRITE); S32 offset = mOffset; S32 size = mRequestedBytes; From ad2edc1d8336c745fc897197e2e85debf3654c17 Mon Sep 17 00:00:00 2001 From: Callum Prentice Date: Tue, 9 Mar 2021 18:35:30 -0800 Subject: [PATCH 092/443] Remove debugging tags --- indra/llfilesystem/lldiskcache.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/indra/llfilesystem/lldiskcache.cpp b/indra/llfilesystem/lldiskcache.cpp index 61eb654693..c9f7684b5a 100644 --- a/indra/llfilesystem/lldiskcache.cpp +++ b/indra/llfilesystem/lldiskcache.cpp @@ -192,8 +192,8 @@ const std::string LLDiskCache::metaDataToFilepath(const std::string id, file_path << id; file_path << "_"; file_path << (extra_info.empty() ? "0" : extra_info); - file_path << "_"; - file_path << assetTypeToString(at); // see SL-14210 Prune descriptive tag from new cache filenames + //file_path << "_"; + //file_path << assetTypeToString(at); // see SL-14210 Prune descriptive tag from new cache filenames // for details of why it was removed. Note that if you put it // back or change the format of the filename, the cache files // files will be invalidated (and perhaps, more importantly, From 5f5e52b5219d6f8f9ad284c90e66199a29531371 Mon Sep 17 00:00:00 2001 From: Callum Prentice Date: Wed, 10 Mar 2021 17:03:56 -0800 Subject: [PATCH 093/443] Fix for SL-14985 - bump the texture cache version so the texture cache is purged on startup after running an older version of the Viewer --- indra/newview/llappviewer.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 6ede9ec0e7..a1e9ac2f87 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -4099,8 +4099,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 ; } From 6b73a8331f558f29903b797dedc09c7419958fdb Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Wed, 17 Mar 2021 00:19:38 +0200 Subject: [PATCH 094/443] SL-14541 removed breakpad, win_crash_logger, updated zlib --- autobuild.xml | 214 ++----- indra/CMakeLists.txt | 3 - indra/cmake/CMakeLists.txt | 2 - indra/cmake/FindGoogleBreakpad.cmake | 40 -- indra/cmake/GoogleBreakpad.cmake | 22 - indra/llcommon/CMakeLists.txt | 3 - indra/llcommon/llapp.cpp | 169 ------ indra/llcommon/llapp.h | 8 - indra/newview/CMakeLists.txt | 61 +- indra/newview/generate_breakpad_symbols.py | 166 ------ indra/newview/llappviewer.cpp | 2 +- indra/newview/llappviewer.h | 1 - indra/newview/llappviewerwin32.cpp | 54 -- indra/newview/llappviewerwin32.h | 1 - indra/newview/viewer_manifest.py | 5 - indra/win_crash_logger/CMakeLists.txt | 105 ---- indra/win_crash_logger/StdAfx.cpp | 34 -- indra/win_crash_logger/StdAfx.h | 56 -- indra/win_crash_logger/ll_icon.ico | Bin 2238 -> 0 bytes .../win_crash_logger/llcrashloggerwindows.cpp | 536 ------------------ indra/win_crash_logger/llcrashloggerwindows.h | 86 --- indra/win_crash_logger/resource.h | 63 -- indra/win_crash_logger/win_crash_logger.cpp | 70 --- indra/win_crash_logger/win_crash_logger.h | 38 -- indra/win_crash_logger/win_crash_logger.ico | Bin 1078 -> 0 bytes indra/win_crash_logger/win_crash_logger.rc | 188 ------ 26 files changed, 65 insertions(+), 1862 deletions(-) delete mode 100644 indra/cmake/FindGoogleBreakpad.cmake delete mode 100644 indra/cmake/GoogleBreakpad.cmake delete mode 100755 indra/newview/generate_breakpad_symbols.py delete mode 100644 indra/win_crash_logger/CMakeLists.txt delete mode 100644 indra/win_crash_logger/StdAfx.cpp delete mode 100644 indra/win_crash_logger/StdAfx.h delete mode 100644 indra/win_crash_logger/ll_icon.ico delete mode 100644 indra/win_crash_logger/llcrashloggerwindows.cpp delete mode 100644 indra/win_crash_logger/llcrashloggerwindows.h delete mode 100644 indra/win_crash_logger/resource.h delete mode 100644 indra/win_crash_logger/win_crash_logger.cpp delete mode 100644 indra/win_crash_logger/win_crash_logger.h delete mode 100644 indra/win_crash_logger/win_crash_logger.ico delete mode 100755 indra/win_crash_logger/win_crash_logger.rc diff --git a/autobuild.xml b/autobuild.xml index c3d7c03121..6c43fa7bc2 100644 --- a/autobuild.xml +++ b/autobuild.xml @@ -166,9 +166,9 @@ archive hash - 3c0e9cfeb2a1c099a068aa999a54a1ce + 35cc090d942b85c9126ceac9912d52d6 url - https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/77456/734789/boost-1.72-darwin64-556301.tar.bz2 + https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/78585/744021/boost-1.72-darwin64-557045.tar.bz2 name darwin64 @@ -202,9 +202,9 @@ archive hash - 2f5b314539617871e9d104f1f83f0ccd + 9aa4ce32df5f5e36124c990e2d77b885 url - https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/77458/734770/boost-1.72-windows-556301.tar.bz2 + https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/78586/743982/boost-1.72-windows-557045.tar.bz2 name windows @@ -214,9 +214,9 @@ archive hash - e8cdfffa30c85229befb0c901fedb7e3 + a79511c9d8b956767ebaa405155d4238 url - https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/77459/734776/boost-1.72-windows64-556301.tar.bz2 + https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/78584/743961/boost-1.72-windows64-557045.tar.bz2 name windows64 @@ -308,9 +308,9 @@ archive hash - 3250ad7a5e12e8656b0aa4701b38ad3a + 1d063cf1783e7788f17486c234adb1db url - https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/77469/734822/colladadom-2.3.556305-darwin64-556305.tar.bz2 + https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/78635/744249/colladadom-2.3.557064-darwin64-557064.tar.bz2 name darwin64 @@ -344,9 +344,9 @@ archive hash - 20b8a8395bbd8e86f48c75bf8fc2e642 + e78ecf919eee01567556787c3a358d15 url - https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/77468/734828/colladadom-2.3.556305-windows-556305.tar.bz2 + https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/78637/744269/colladadom-2.3.557064-windows-557064.tar.bz2 name windows @@ -356,16 +356,16 @@ archive hash - bc88fdd32fd7d005c7dfc58c82260a29 + 7e63a212c8909a25236138422fe01298 url - https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/77470/734834/colladadom-2.3.556305-windows64-556305.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.556305 + 2.3.557064 curl @@ -398,9 +398,9 @@ archive hash - d4c8b00a88e879bd1a7e6805af2ccb1c + 7295ca3234ab21a98c39604f3b0985cb url - https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/76361/727381/curl-7.54.1.555526-darwin64-555526.tar.bz2 + https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/78596/744055/curl-7.54.1.557049-darwin64-557049.tar.bz2 name darwin64 @@ -434,11 +434,11 @@ archive hash - 0bca1f79fc78b0045de18f69fea03093 + 0c31fa12a33ecc946c0c69259b6367a9 hash_algorithm md5 url - https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/76362/727375/curl-7.54.1.555526-windows-555526.tar.bz2 + https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/78598/744050/curl-7.54.1.557049-windows-557049.tar.bz2 name windows @@ -448,16 +448,16 @@ archive hash - cca8ff1d59fcfc64e99c79a950f3abc1 + 4c4d5971a59ae2e1f4467667df2a9aa4 url - https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/76360/727374/curl-7.54.1.555526-windows64-555526.tar.bz2 + https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/78597/744044/curl-7.54.1.557049-windows64-557049.tar.bz2 name windows64 version - 7.54.1.555526 + 7.54.1.557049 db @@ -880,9 +880,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 @@ -916,9 +916,9 @@ archive hash - 1d1c7b60f71a5152ced60bee87f5bba8 + 7ee200d6b5fa282c7f973ade5615aa86 url - http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/56312/526734/freetype-2.4.4.539865-windows-539865.tar.bz2 + https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/78594/744011/freetype-2.4.4.557047-windows-557047.tar.bz2 name windows @@ -928,16 +928,16 @@ archive hash - 53e78d4a607e959637e98a82a3cf5bea + 69307aaba16ac71531c9c4d930ace993 url - http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/56310/526723/freetype-2.4.4.539865-windows64-539865.tar.bz2 + https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/78593/744010/freetype-2.4.4.557047-windows64-557047.tar.bz2 name windows64 version - 2.4.4.539865 + 2.4.4.557047 glext @@ -1141,96 +1141,6 @@ version 1.0pre3.555522 - 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 - 352e673897e8f36f8470150b8ace6ce9 - url - http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/p64_3p-google-breakpad/rev/314225/arch/Linux/installer/google_breakpad-1413.314225-linux-314225.tar.bz2 - - name - linux - - linux64 - - archive - - hash - 6bddcc1ac470dd5eab459220102df9e9 - url - http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/1835/4114/google_breakpad-1413.501824-linux64-501824.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 @@ -1262,9 +1172,9 @@ archive hash - e280519baadf8369b4d7d1cd00506b49 + 19e925604bc1a91efb4b130e1edd8bf2 url - https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/77465/734807/googlemock-1.7.0.556304-darwin64-556304.tar.bz2 + https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/78620/744140/googlemock-1.7.0.557057-darwin64-557057.tar.bz2 name darwin64 @@ -1298,9 +1208,9 @@ archive hash - d4d5b681cb2d0a214bba2ad54a36dea9 + eed7b41d0d1f41b24f315349ef78c728 url - https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/77466/734805/googlemock-1.7.0.556304-windows-556304.tar.bz2 + https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/78622/744148/googlemock-1.7.0.557057-windows-557057.tar.bz2 name windows @@ -1310,16 +1220,16 @@ archive hash - 5dfc8cc3160a6954757cebdeaaa30376 + a6ad6fe722d2fe4e8137495af3f374c9 url - https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/77467/734815/googlemock-1.7.0.556304-windows64-556304.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.556304 + 1.7.0.557057 gstreamer @@ -1948,9 +1858,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 @@ -1984,9 +1894,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 @@ -1996,16 +1906,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 @@ -2080,9 +1990,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 @@ -2116,9 +2026,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 @@ -2128,16 +2038,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 @@ -2828,9 +2738,9 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors archive hash - 18aef0c8fc471b6539addbdc019aea25 + 166aa05b379b13156de5821252040498 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/78582/743936/openssl-1.0.2l.557043-darwin64-557043.tar.bz2 name darwin64 @@ -2864,9 +2774,9 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors archive hash - 2b2f61313b1cbd2893c1ba5bf15061fa + 68aae05216c035283c79aad6dd88d8da 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/78590/743992/openssl-1.0.2l.557043-windows-557043.tar.bz2 name windows @@ -2876,16 +2786,16 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors archive hash - 59aae854155bc7119e0dca25e65828c0 + d2576a386559cefb654154d8f0de6337 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/78588/743976/openssl-1.0.2l.557043-windows64-557043.tar.bz2 name windows64 version - 1.0.2l.539874 + 1.0.2l.557043 pcre @@ -3430,9 +3340,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 @@ -3468,9 +3378,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 @@ -3480,16 +3390,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/indra/CMakeLists.txt b/indra/CMakeLists.txt index 53e5d7b6a5..f5e814187d 100644 --- a/indra/CMakeLists.txt +++ b/indra/CMakeLists.txt @@ -74,13 +74,10 @@ elseif (DARWIN) add_subdirectory(${VIEWER_PREFIX}mac_crash_logger) add_dependencies(viewer mac-crash-logger) elseif (WINDOWS) - add_subdirectory(${VIEWER_PREFIX}win_crash_logger) # cmake EXISTS requires an absolute path, see indra/cmake/Variables.cmake if (EXISTS ${VIEWER_DIR}win_setup) add_subdirectory(${VIEWER_DIR}win_setup) endif (EXISTS ${VIEWER_DIR}win_setup) - # add_dependencies(viewer windows-setup windows-crash-logger) - add_dependencies(viewer windows-crash-logger) endif (LINUX) add_subdirectory(${VIEWER_PREFIX}newview) diff --git a/indra/cmake/CMakeLists.txt b/indra/cmake/CMakeLists.txt index a17e37cd32..cca305c741 100644 --- a/indra/cmake/CMakeLists.txt +++ b/indra/cmake/CMakeLists.txt @@ -28,7 +28,6 @@ set(cmake_SOURCE_FILES FindAutobuild.cmake FindBerkeleyDB.cmake FindGLH.cmake - FindGoogleBreakpad.cmake FindHUNSPELL.cmake FindJsonCpp.cmake FindNDOF.cmake @@ -43,7 +42,6 @@ set(cmake_SOURCE_FILES GLH.cmake GLOD.cmake ## GStreamer010Plugin.cmake - GoogleBreakpad.cmake GoogleMock.cmake Havok.cmake Hunspell.cmake diff --git a/indra/cmake/FindGoogleBreakpad.cmake b/indra/cmake/FindGoogleBreakpad.cmake deleted file mode 100644 index 1a0493be5e..0000000000 --- a/indra/cmake/FindGoogleBreakpad.cmake +++ /dev/null @@ -1,40 +0,0 @@ -# -*- cmake -*- - -# - Find Google BreakPad -# Find the Google BreakPad includes and library -# This module defines -# BREAKPAD_EXCEPTION_HANDLER_INCLUDE_DIR, where to find exception_handler.h, etc. -# BREAKPAD_EXCEPTION_HANDLER_LIBRARIES, the libraries needed to use Google BreakPad. -# BREAKPAD_EXCEPTION_HANDLER_FOUND, If false, do not try to use Google BreakPad. -# also defined, but not for general use are -# BREAKPAD_EXCEPTION_HANDLER_LIBRARY, where to find the Google BreakPad library. - -FIND_PATH(BREAKPAD_EXCEPTION_HANDLER_INCLUDE_DIR google_breakpad/exception_handler.h) - -SET(BREAKPAD_EXCEPTION_HANDLER_NAMES ${BREAKPAD_EXCEPTION_HANDLER_NAMES} breakpad_client) -FIND_LIBRARY(BREAKPAD_EXCEPTION_HANDLER_LIBRARY - NAMES ${BREAKPAD_EXCEPTION_HANDLER_NAMES} - ) - -IF (BREAKPAD_EXCEPTION_HANDLER_LIBRARY AND BREAKPAD_EXCEPTION_HANDLER_INCLUDE_DIR) - SET(BREAKPAD_EXCEPTION_HANDLER_LIBRARIES ${BREAKPAD_EXCEPTION_HANDLER_LIBRARY}) - SET(BREAKPAD_EXCEPTION_HANDLER_FOUND "YES") -ELSE (BREAKPAD_EXCEPTION_HANDLER_LIBRARY AND BREAKPAD_EXCEPTION_HANDLER_INCLUDE_DIR) - SET(BREAKPAD_EXCEPTION_HANDLER_FOUND "NO") -ENDIF (BREAKPAD_EXCEPTION_HANDLER_LIBRARY AND BREAKPAD_EXCEPTION_HANDLER_INCLUDE_DIR) - - -IF (BREAKPAD_EXCEPTION_HANDLER_FOUND) - IF (NOT BREAKPAD_EXCEPTION_HANDLER_FIND_QUIETLY) - MESSAGE(STATUS "Found Google BreakPad: ${BREAKPAD_EXCEPTION_HANDLER_LIBRARIES}") - ENDIF (NOT BREAKPAD_EXCEPTION_HANDLER_FIND_QUIETLY) -ELSE (BREAKPAD_EXCEPTION_HANDLER_FOUND) - IF (BREAKPAD_EXCEPTION_HANDLER_FIND_REQUIRED) - MESSAGE(FATAL_ERROR "Could not find Google BreakPad library") - ENDIF (BREAKPAD_EXCEPTION_HANDLER_FIND_REQUIRED) -ENDIF (BREAKPAD_EXCEPTION_HANDLER_FOUND) - -MARK_AS_ADVANCED( - BREAKPAD_EXCEPTION_HANDLER_LIBRARY - BREAKPAD_EXCEPTION_HANDLER_INCLUDE_DIR - ) diff --git a/indra/cmake/GoogleBreakpad.cmake b/indra/cmake/GoogleBreakpad.cmake deleted file mode 100644 index 829e1ac08a..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/llcommon/CMakeLists.txt b/indra/llcommon/CMakeLists.txt index eeb315ead6..9cc7121253 100644 --- a/indra/llcommon/CMakeLists.txt +++ b/indra/llcommon/CMakeLists.txt @@ -8,7 +8,6 @@ include(Linking) include(Boost) include(LLSharedLibs) include(JsonCpp) -include(GoogleBreakpad) include(Copy3rdPartyLibs) include(ZLIB) include(URIPARSER) @@ -18,7 +17,6 @@ include_directories( ${LLCOMMON_INCLUDE_DIRS} ${JSONCPP_INCLUDE_DIR} ${ZLIB_INCLUDE_DIRS} - ${BREAKPAD_INCLUDE_DIRECTORIES} ${URIPARSER_INCLUDE_DIRS} ) @@ -285,7 +283,6 @@ endif(LLCOMMON_LINK_SHARED) target_link_libraries( llcommon - ${BREAKPAD_EXCEPTION_HANDLER_LIBRARIES} ${APRUTIL_LIBRARIES} ${APR_LIBRARIES} ${EXPAT_LIBRARIES} diff --git a/indra/llcommon/llapp.cpp b/indra/llcommon/llapp.cpp index a90b294550..c9e4cf2ab3 100644 --- a/indra/llcommon/llapp.cpp +++ b/indra/llcommon/llapp.cpp @@ -46,7 +46,6 @@ #include "llstl.h" // for DeletePointer() #include "llstring.h" #include "lleventtimer.h" -#include "google_breakpad/exception_handler.h" #include "stringize.h" #include "llcleanup.h" #include "llevents.h" @@ -62,12 +61,6 @@ LONG WINAPI default_windows_exception_handler(struct _EXCEPTION_POINTERS *exception_infop); BOOL ConsoleCtrlHandler(DWORD fdwCtrlType); -bool windows_post_minidump_callback(const wchar_t* dump_path, - const wchar_t* minidump_id, - void* context, - EXCEPTION_POINTERS* exinfo, - MDRawAssertionInfo* assertion, - bool succeeded); #else # include # include // for fork() @@ -146,8 +139,6 @@ void LLApp::commonCtor() // Set the application to this instance. sApplication = this; - - mExceptionHandler = 0; // initialize the buffer to write the minidump filename to // (this is used to avoid allocating memory in the crash handler) @@ -177,8 +168,6 @@ LLApp::~LLApp() delete mThreadErrorp; mThreadErrorp = NULL; } - - if(mExceptionHandler != 0) delete mExceptionHandler; SUBSYSTEM_CLEANUP_DBG(LLCommon); } @@ -394,69 +383,6 @@ void LLApp::setupErrorHandling(bool second_instance) #if LL_WINDOWS -#if LL_SEND_CRASH_REPORTS && ! defined(LL_BUGSPLAT) - EnableCrashingOnCrashes(); - - // This sets a callback to handle w32 signals to the console window. - // The viewer shouldn't be affected, sicne its a windowed app. - SetConsoleCtrlHandler( (PHANDLER_ROUTINE) ConsoleCtrlHandler, TRUE); - - // Install the Google Breakpad crash handler for Windows - if(mExceptionHandler == 0) - { - if ( second_instance ) //BUG-5707 Firing teleport from a web browser causes second - { - mExceptionHandler = new google_breakpad::ExceptionHandler( - L"C:\\Temp\\", - 0, //No filter - windows_post_minidump_callback, - 0, - google_breakpad::ExceptionHandler::HANDLER_ALL); //No custom client info. - } - else - { - LL_WARNS() << "adding breakpad exception handler" << LL_ENDL; - - std::wstring wpipe_name; - wpipe_name = mCrashReportPipeStr + wstringize(getPid()); - - const std::wstring wdump_path(utf8str_to_utf16str(mDumpPath)); - - int retries = 30; - for (; retries > 0; --retries) - { - if (mExceptionHandler != 0) delete mExceptionHandler; - - mExceptionHandler = new google_breakpad::ExceptionHandler( - wdump_path, - NULL, //No filter - windows_post_minidump_callback, - 0, - google_breakpad::ExceptionHandler::HANDLER_ALL, - MiniDumpNormal, //Generate a 'normal' minidump. - wpipe_name.c_str(), - NULL); //No custom client info. - if (mExceptionHandler->IsOutOfProcess()) - { - LL_INFOS("CRASHREPORT") << "Successfully attached to Out of Process exception handler." << LL_ENDL; - break; - } - else - { - LL_WARNS("CRASHREPORT") << "Unable to attach to Out of Process exception handler. " << retries << " retries remaining." << LL_ENDL; - ::Sleep(100); //Wait a tick and try again. - } - } - - if (retries == 0) LL_WARNS("CRASHREPORT") << "Unable to attach to Out of Process exception handler." << LL_ENDL; - } - - if (mExceptionHandler) - { - mExceptionHandler->set_handle_debug_exceptions(true); - } - } -#endif // LL_SEND_CRASH_REPORTS && ! defined(LL_BUGSPLAT) #else // ! LL_WINDOWS #if defined(LL_BUGSPLAT) @@ -609,31 +535,6 @@ void LLApp::setError() setStatus(APP_STATUS_ERROR); } -void LLApp::setMiniDumpDir(const std::string &path) -{ - if (path.empty()) - { - mDumpPath = "/tmp"; - } - else - { - mDumpPath = path; - } - - if(mExceptionHandler == 0) return; -#ifdef LL_WINDOWS - std::wstring buffer(utf8str_to_utf16str(mDumpPath)); - if (buffer.size() > MAX_MINDUMP_PATH_LENGTH) buffer.resize(MAX_MINDUMP_PATH_LENGTH); - mExceptionHandler->set_dump_path(buffer); -#elif LL_LINUX - //google_breakpad::MinidumpDescriptor desc("/tmp"); //path works in debug fails in production inside breakpad lib so linux gets a little less stack reporting until it is patched. - google_breakpad::MinidumpDescriptor desc(mDumpPath); //path works in debug fails in production inside breakpad lib so linux gets a little less stack reporting until it is patched. - mExceptionHandler->set_minidump_descriptor(desc); -#else - mExceptionHandler->set_dump_path(mDumpPath); -#endif -} - void LLApp::setDebugFileNames(const std::string &path) { mStaticDebugFileName = path + "static_debug_info.log"; @@ -642,8 +543,6 @@ void LLApp::setDebugFileNames(const std::string &path) void LLApp::writeMiniDump() { - if(mExceptionHandler == 0) return; - mExceptionHandler->WriteMinidump(); } // static @@ -700,13 +599,6 @@ bool LLApp::isExiting() void LLApp::disableCrashlogger() { - // Disable Breakpad exception handler. - if (mExceptionHandler != 0) - { - delete mExceptionHandler; - mExceptionHandler = 0; - } - sDisableCrashlogger = TRUE; } @@ -1095,64 +987,3 @@ bool unix_post_minidump_callback(const char *dump_dir, } #endif // !WINDOWS -#ifdef LL_WINDOWS -bool windows_post_minidump_callback(const wchar_t* dump_path, - const wchar_t* minidump_id, - void* context, - EXCEPTION_POINTERS* exinfo, - MDRawAssertionInfo* assertion, - bool succeeded) -{ - char * path = LLApp::instance()->getMiniDumpFilename(); - S32 remaining = LLApp::MAX_MINDUMP_PATH_LENGTH; - size_t bytesUsed; - - LL_INFOS("MINIDUMPCALLBACK") << "Dump file was generated." << LL_ENDL; - bytesUsed = wcstombs(path, dump_path, static_cast(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); - } - - 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 245c73e3a2..e590e5eafd 100644 --- a/indra/llcommon/llapp.h +++ b/indra/llcommon/llapp.h @@ -49,10 +49,6 @@ void clear_signals(); #endif -namespace google_breakpad { - class ExceptionHandler; // See exception_handler.h -} - class LL_COMMON_API LLApp { friend class LLErrorThread; @@ -236,7 +232,6 @@ 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. @@ -312,9 +307,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/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index 3439951e80..1caf591860 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -1830,7 +1830,6 @@ if (WINDOWS) media_plugin_libvlc media_plugin_example winmm_shim - windows-crash-logger ) if (ADDRESS_SIZE EQUAL 64) @@ -1897,7 +1896,6 @@ if (WINDOWS) add_dependencies(${VIEWER_BINARY_NAME} SLPlugin - windows-crash-logger ) # sets the 'working directory' for debugging from visual studio. @@ -2246,62 +2244,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 BUGSPLAT_DB) - # 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 mac-crash-logger") - set(VIEWER_EXE_GLOBS "'${product}' mac-crash-logger") - set(VIEWER_LIB_GLOB "*.dylib") - endif (DARWIN) - if (LINUX) - list(APPEND SYMBOL_SEARCH_DIRS "${CMAKE_CURRENT_BINARY_DIR}/packaged") - set(VIEWER_EXE_GLOBS "do-not-directly-run-secondlife-bin SLPlugin") - set(VIEWER_EXE_GLOBS "do-not-directly-run-secondlife-bin") - set(VIEWER_LIB_GLOB "*${CMAKE_SHARED_MODULE_SUFFIX}*") - set(VIEWER_COPY_MANIFEST copy_l_viewer_manifest) - endif (LINUX) - - if(CMAKE_CFG_INTDIR STREQUAL ".") - set(LLBUILD_CONFIG ${CMAKE_BUILD_TYPE}) - else(CMAKE_CFG_INTDIR STREQUAL ".") - # set LLBUILD_CONFIG to be a shell variable evaluated at build time - # reflecting the configuration we are currently building. - set(LLBUILD_CONFIG ${CMAKE_CFG_INTDIR}) - endif(CMAKE_CFG_INTDIR STREQUAL ".") - add_custom_command(OUTPUT "${VIEWER_SYMBOL_FILE}" - COMMAND "${PYTHON_EXECUTABLE}" - ARGS - "${CMAKE_CURRENT_SOURCE_DIR}/generate_breakpad_symbols.py" - "${LLBUILD_CONFIG}" - "${SYMBOL_SEARCH_DIRS}" - "${VIEWER_EXE_GLOBS}" - "${VIEWER_LIB_GLOB}" - "${AUTOBUILD_INSTALL_DIR}/bin/dump_syms" - "${VIEWER_SYMBOL_FILE}" - DEPENDS generate_breakpad_symbols.py - VERBATIM) - - add_custom_target(generate_symbols DEPENDS "${VIEWER_SYMBOL_FILE}" ${VIEWER_BINARY_NAME} "${VIEWER_COPY_MANIFEST}") - add_dependencies(generate_symbols ${VIEWER_BINARY_NAME}) - if (WINDOWS OR LINUX) - add_dependencies(generate_symbols "${VIEWER_COPY_MANIFEST}") - endif (WINDOWS OR LINUX) - - else (NOT BUGSPLAT_DB) + if (BUGSPLAT_DB) # BugSplat symbol-file generation if (WINDOWS) # Just pack up a tarball containing only the .pdb file for the @@ -2385,7 +2328,7 @@ if (PACKAGE AND (RELEASE_CRASH_REPORTING OR NON_RELEASE_CRASH_REPORTING) AND VIE if (LINUX) # TBD endif (LINUX) - endif (NOT BUGSPLAT_DB) + endif (BUGSPLAT_DB) # for both BUGSPLAT_DB and Breakpad add_dependencies(llpackage generate_symbols) 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/llappviewer.cpp b/indra/newview/llappviewer.cpp index f518704e06..fd06e39245 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -736,7 +736,7 @@ LLAppViewer::LLAppViewer() std::string logdir = gDirUtilp->getExpandedFilename(LL_PATH_DUMP, ""); #endif // ! LL_BUGSPLAT mDumpPath = logdir; - setMiniDumpDir(logdir); + setDebugFileNames(logdir); } diff --git a/indra/newview/llappviewer.h b/indra/newview/llappviewer.h index 5332fe2deb..5240ae17d0 100644 --- a/indra/newview/llappviewer.h +++ b/indra/newview/llappviewer.h @@ -108,7 +108,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(); diff --git a/indra/newview/llappviewerwin32.cpp b/indra/newview/llappviewerwin32.cpp index 9b1c0d1f8b..f0bede5321 100644 --- a/indra/newview/llappviewerwin32.cpp +++ b/indra/newview/llappviewerwin32.cpp @@ -603,9 +603,6 @@ bool LLAppViewerWin32::init() #if ! defined(LL_BUGSPLAT) #pragma message("Building without BugSplat") - LLAppViewer* pApp = LLAppViewer::instance(); - pApp->initCrashReporting(); - #else // LL_BUGSPLAT #pragma message("Building with BugSplat") @@ -817,57 +814,6 @@ bool LLAppViewerWin32::restoreErrorTrap() //return LLWinDebug::checkExceptionHandler(); } -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 c5fae6a3a3..2699224e58 100644 --- a/indra/newview/llappviewerwin32.h +++ b/indra/newview/llappviewerwin32.h @@ -51,7 +51,6 @@ protected: virtual bool beingDebugged(); virtual bool restoreErrorTrap(); - virtual void initCrashReporting(bool reportFreeze); virtual bool sendURLToOtherInstance(const std::string& url); diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py index 6d231040f7..af7e799269 100755 --- a/indra/newview/viewer_manifest.py +++ b/indra/newview/viewer_manifest.py @@ -680,11 +680,6 @@ class WindowsManifest(ViewerManifest): self.path("libvlccore.dll") self.path("plugins/") - # pull in the crash logger from other projects - # tag:"crash-logger" here as a cue to the exporter - self.path(src='../win_crash_logger/%s/windows-crash-logger.exe' % self.args['configuration'], - dst="win_crash_logger.exe") - if not self.is_packaging_viewer(): self.package_file = "copied_deps" diff --git a/indra/win_crash_logger/CMakeLists.txt b/indra/win_crash_logger/CMakeLists.txt deleted file mode 100644 index 86aa655f03..0000000000 --- a/indra/win_crash_logger/CMakeLists.txt +++ /dev/null @@ -1,105 +0,0 @@ -# -*- cmake -*- - -project(win_crash_logger) - -include(00-Common) -include(LLCommon) -include(LLCoreHttp) -include(LLCrashLogger) -include(LLMath) -include(LLMessage) -include(LLVFS) -include(LLWindow) -include(LLXML) -include(Linking) -include(LLSharedLibs) -include(GoogleBreakpad) -include(Boost) - -include_directories( - ${LLCOREHTTP_INCLUDE_DIRS} - ${LLCOMMON_INCLUDE_DIRS} - ${LLCRASHLOGGER_INCLUDE_DIRS} - ${LLMATH_INCLUDE_DIRS} - ${LLWINDOW_INCLUDE_DIRS} - ${LLXML_INCLUDE_DIRS} - ${LLVFS_INCLUDE_DIRS} - ${BREAKPAD_INCLUDE_DIRECTORIES} - ) -include_directories(SYSTEM - ${LLCOMMON_SYSTEM_INCLUDE_DIRS} - ${LLXML_SYSTEM_INCLUDE_DIRS} - ) - -set(win_crash_logger_SOURCE_FILES - win_crash_logger.cpp - llcrashloggerwindows.cpp - ) - -set(win_crash_logger_HEADER_FILES - CMakeLists.txt - - llcrashloggerwindows.h - resource.h - StdAfx.h - win_crash_logger.h - ) - -set_source_files_properties(${win_crash_logger_HEADER_FILES} - PROPERTIES HEADER_FILE_ONLY TRUE) - -set(win_crash_logger_RESOURCE_FILES - ll_icon.ico - ) - -set_source_files_properties(${win_crash_logger_RESOURCE_FILES} - PROPERTIES HEADER_FILE_ONLY TRUE) - -set(win_crash_logger_RESOURCE_FILES - win_crash_logger.rc - ${win_crash_logger_RESOURCE_FILES} - ) - -SOURCE_GROUP("Resource Files" FILES ${win_crash_logger_RESOURCE_FILES}) - -list(APPEND - win_crash_logger_SOURCE_FILES - ${win_crash_logger_HEADER_FILES} - ${win_crash_logger_RESOURCE_FILES} - ) - -add_executable(windows-crash-logger WIN32 ${win_crash_logger_SOURCE_FILES}) - - -target_link_libraries(windows-crash-logger - ${LEGACY_STDIO_LIBS} - ${BREAKPAD_EXCEPTION_HANDLER_LIBRARIES} - ${LLCRASHLOGGER_LIBRARIES} - ${LLWINDOW_LIBRARIES} - ${LLVFS_LIBRARIES} - ${LLXML_LIBRARIES} - ${LLMESSAGE_LIBRARIES} - ${LLMATH_LIBRARIES} - ${LLCOREHTTP_LIBRARIES} - ${LLCOMMON_LIBRARIES} - ${BOOST_CONTEXT_LIBRARY} - ${BOOST_FIBER_LIBRARY} - ${WINDOWS_LIBRARIES} - dxguid - ${GOOGLE_PERFTOOLS_LIBRARIES} - user32 - gdi32 - oleaut32 - wininet - Wldap32 - ) - -if (WINDOWS) - set_target_properties(windows-crash-logger - PROPERTIES - LINK_FLAGS "/NODEFAULTLIB:LIBCMT" - LINK_FLAGS_DEBUG "/NODEFAULTLIB:\"LIBCMT;LIBCMTD;MSVCRT\"" - ) -endif (WINDOWS) - -ll_deploy_sharedlibs_command(windows-crash-logger) diff --git a/indra/win_crash_logger/StdAfx.cpp b/indra/win_crash_logger/StdAfx.cpp deleted file mode 100644 index f56711af73..0000000000 --- a/indra/win_crash_logger/StdAfx.cpp +++ /dev/null @@ -1,34 +0,0 @@ -/** - * @file StdAfx.cpp - * @brief windows crash logger source file for includes - * - * $LicenseInfo:firstyear=2003&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -// stdafx.cpp : source file that includes just the standard includes -// win_crash_logger.pch will be the pre-compiled header -// stdafx.obj will contain the pre-compiled type information - -#include "stdafx.h" - -// TODO: reference any additional headers you need in STDAFX.H -// and not in this file diff --git a/indra/win_crash_logger/StdAfx.h b/indra/win_crash_logger/StdAfx.h deleted file mode 100644 index 35976658ac..0000000000 --- a/indra/win_crash_logger/StdAfx.h +++ /dev/null @@ -1,56 +0,0 @@ -/** - * @file StdAfx.h - * @brief standard system includes - * - * $LicenseInfo:firstyear=2003&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -// stdafx.h : include file for standard system include files, -// or project specific include files that are used frequently, but -// are changed infrequently -// - -#if !defined(AFX_STDAFX_H__A9DB83DB_A9FD_11D0_BFD1_444553540000__INCLUDED_) -#define AFX_STDAFX_H__A9DB83DB_A9FD_11D0_BFD1_444553540000__INCLUDED_ - -#if _MSC_VER > 1000 -#pragma once -#endif // _MSC_VER > 1000 - -#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers - -// Windows Header Files: -#include - -// C RunTime Header Files -#include -#include -#include - -// Local Header Files - -// TODO: reference additional headers your program requires here - -//{{AFX_INSERT_LOCATION}} -// Microsoft Visual C++ will insert additional declarations immediately before the previous line. - -#endif // !defined(AFX_STDAFX_H__A9DB83DB_A9FD_11D0_BFD1_444553540000__INCLUDED_) diff --git a/indra/win_crash_logger/ll_icon.ico b/indra/win_crash_logger/ll_icon.ico deleted file mode 100644 index 566346dfe301eec04d1fb819ecec2f2dd8d2483c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2238 zcmc&!-ES0C96fhtciXi#L~4tniK1>MzL=O0o*E+oAB;3H(P{_^u|O#W+q>H@XlbRT z*&?M~`aMv(?G|WlM{S7%J|Hy_1D4^VxNZ~s*gt}VH#~QCci2Ys)jPR!cYYuDob&tL zyMW-cWeeOfn-7%m*IS%hIJa{O(8$r@bC-3m!mV3T_`yzyfuDhyByiy#MD!Zacmdkp zR*2s3vADR17s}p;s67u+AA>maBM`rZyd59WHVz~lh}aGITE@8k0`dCW!1x`A#%XNa z{06j^d1zlTZ}3;3;Uao_d!a>t050B#=($CVpWy$Z4x;TU%FD~4M=iwTaR?s?M-mX5 zLlEH+yu7gpIR85^_7J`kL;kYtI)-Q;%u&}TIj4pBBC+8{XHSBTKIK+wT@HNJe z|8Wg@@!X9)BKL>DrDdKWp6R9pG)`Z&3E!c9VD>Ngk4^&3Q|#3wxlAJ(jY4CuMC=+i z6>owT9>wFwj~P!p&(f18PayhkV{L7Xb!FbUy9n%yL96XTOG^uUhr4)Iy5Rq`587Ft z)6Y)xE?h$KYi}}slIO1tsGZ|IypG`ZT4*P2V1T`AU=Q}6M(|)0{8b(BH}H-%lk@3C zVCXjVL#;exH=zyABk*Azg5_TVFO?urUWwp)N0Gm)9s0?68o - -#include "boost/tokenizer.hpp" - -#include "indra_constants.h" // CRASH_BEHAVIOR_ASK, CRASH_SETTING_NAME -#include "llerror.h" -#include "llfile.h" -#include "lltimer.h" -#include "llstring.h" -#include "lldxhardware.h" -#include "lldir.h" -#include "llsdserialize.h" -#include "llsdutil.h" -#include "stringize.h" - -#include -#include - -#define MAX_LOADSTRING 100 -#define MAX_STRING 2048 -const char* const SETTINGS_FILE_HEADER = "version"; -const S32 SETTINGS_FILE_VERSION = 101; - -// Windows Message Handlers - -// Global Variables: -HINSTANCE hInst= NULL; // current instance -TCHAR szTitle[MAX_LOADSTRING]; /* Flawfinder: ignore */ // The title bar text -TCHAR szWindowClass[MAX_LOADSTRING]; /* Flawfinder: ignore */ // The title bar text - -std::string gProductName; -HWND gHwndReport = NULL; // Send/Don't Send dialog -HWND gHwndProgress = NULL; // Progress window -HCURSOR gCursorArrow = NULL; -HCURSOR gCursorWait = NULL; -BOOL gFirstDialog = TRUE; // Are we currently handling the Send/Don't Send dialog? -std::stringstream gDXInfo; -bool gSendLogs = false; - -LLCrashLoggerWindows* LLCrashLoggerWindows::sInstance = NULL; - -//Conversion from char* to wchar* -//Replacement for ATL macros, doesn't allocate memory -//For more info see: http://www.codeguru.com/forum/showthread.php?t=337247 -void ConvertLPCSTRToLPWSTR (const char* pCstring, WCHAR* outStr) -{ - if (pCstring != NULL) - { - int nInputStrLen = strlen (pCstring); - // Double NULL Termination - int nOutputStrLen = MultiByteToWideChar(CP_ACP, 0, pCstring, nInputStrLen, NULL, 0) + 2; - if (outStr) - { - memset (outStr, 0x00, sizeof (WCHAR)*nOutputStrLen); - MultiByteToWideChar (CP_ACP, 0, pCstring, nInputStrLen, outStr, nInputStrLen); - } - } -} - -void write_debug(const char *str) -{ - gDXInfo << str; /* Flawfinder: ignore */ -} - -void write_debug(std::string& str) -{ - write_debug(str.c_str()); -} - -void show_progress(const std::string& message) -{ - std::wstring msg = wstring_to_utf16str(utf8str_to_wstring(message)); - if (gHwndProgress) - { - SendDlgItemMessage(gHwndProgress, // handle to destination window - IDC_LOG, - WM_SETTEXT, // message to send - FALSE, // undo option - (LPARAM)msg.c_str()); - } -} - -void update_messages() -{ - MSG msg; - while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) - { - if (msg.message == WM_QUIT) - { - exit(0); - } - TranslateMessage(&msg); - DispatchMessage(&msg); - } -} - -void sleep_and_pump_messages( U32 seconds ) -{ - const U32 CYCLES_PER_SECOND = 10; - U32 cycles = seconds * CYCLES_PER_SECOND; - while( cycles-- ) - { - update_messages(); - ms_sleep(1000 / CYCLES_PER_SECOND); - } -} - -// Include product name in the window caption. -void LLCrashLoggerWindows::ProcessCaption(HWND hWnd) -{ - TCHAR templateText[MAX_STRING]; /* Flawfinder: ignore */ - TCHAR header[MAX_STRING]; - std::string final; - GetWindowText(hWnd, templateText, sizeof(templateText)); - final = llformat(ll_convert_wide_to_string(templateText, CP_ACP).c_str(), gProductName.c_str()); - ConvertLPCSTRToLPWSTR(final.c_str(), header); - SetWindowText(hWnd, header); -} - - -// Include product name in the diaog item text. -void LLCrashLoggerWindows::ProcessDlgItemText(HWND hWnd, int nIDDlgItem) -{ - TCHAR templateText[MAX_STRING]; /* Flawfinder: ignore */ - TCHAR header[MAX_STRING]; - std::string final; - GetDlgItemText(hWnd, nIDDlgItem, templateText, sizeof(templateText)); - final = llformat(ll_convert_wide_to_string(templateText, CP_ACP).c_str(), gProductName.c_str()); - ConvertLPCSTRToLPWSTR(final.c_str(), header); - SetDlgItemText(hWnd, nIDDlgItem, header); -} - -bool handle_button_click(WORD button_id) -{ - // Is this something other than Send or Don't Send? - if (button_id != IDOK - && button_id != IDCANCEL) - { - return false; - } - - // We're done with this dialog. - gFirstDialog = FALSE; - - // Send the crash report if requested - if (button_id == IDOK) - { - gSendLogs = TRUE; - WCHAR wbuffer[20000]; - GetDlgItemText(gHwndReport, // handle to dialog box - IDC_EDIT1, // control identifier - wbuffer, // pointer to buffer for text - 20000 // maximum size of string - ); - std::string user_text(ll_convert_wide_to_string(wbuffer, CP_ACP)); - // Activate and show the window. - ShowWindow(gHwndProgress, SW_SHOW); - // Try doing this second to make the progress window go frontmost. - ShowWindow(gHwndReport, SW_HIDE); - ((LLCrashLoggerWindows*)LLCrashLogger::instance())->setUserText(user_text); - ((LLCrashLoggerWindows*)LLCrashLogger::instance())->sendCrashLogs(); - } - // Quit the app - LLApp::setQuitting(); - return true; -} - - -LRESULT CALLBACK WndProc( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam ) -{ - switch( message ) - { - case WM_CREATE: - return 0; - - case WM_COMMAND: - if( gFirstDialog ) - { - WORD button_id = LOWORD(wParam); - bool handled = handle_button_click(button_id); - if (handled) - { - return 0; - } - } - break; - - case WM_DESTROY: - // Closing the window cancels - LLApp::setQuitting(); - PostQuitMessage(0); - return 0; - } - - return DefWindowProc(hwnd, message, wParam, lParam); -} - - -LLCrashLoggerWindows::LLCrashLoggerWindows(void) -{ - if (LLCrashLoggerWindows::sInstance==NULL) - { - sInstance = this; - } -} - -LLCrashLoggerWindows::~LLCrashLoggerWindows(void) -{ - sInstance = NULL; -} - -bool LLCrashLoggerWindows::getMessageWithTimeout(MSG *msg, UINT to) -{ - bool res; - UINT_PTR timerID = SetTimer(NULL, NULL, to, NULL); - res = GetMessage(msg, NULL, 0, 0); - KillTimer(NULL, timerID); - if (!res) - return false; - if (msg->message == WM_TIMER && msg->hwnd == NULL && msg->wParam == 1) - return false; //TIMEOUT! You could call SetLastError() or something... - return true; -} - -int LLCrashLoggerWindows::processingLoop() { - const int millisecs=1000; - int retries = 0; - const int max_retries = 60; - - LL_DEBUGS("CRASHREPORT") << "Entering processing loop for OOP server" << LL_ENDL; - - LLSD options = getOptionData( LLApp::PRIORITY_COMMAND_LINE ); - - MSG msg; - - bool result; - - while (1) - { - result = getMessageWithTimeout(&msg, millisecs); - if ( result ) - { - TranslateMessage(&msg); - DispatchMessage(&msg); - } - - if ( retries < max_retries ) //Wait up to 1 minute for the viewer to say hello. - { - if (mClientsConnected == 0) - { - LL_DEBUGS("CRASHREPORT") << "Waiting for client to connect." << LL_ENDL; - ++retries; - } - else - { - LL_INFOS("CRASHREPORT") << "Client has connected!" << LL_ENDL; - retries = max_retries; - } - } - else - { - if (mClientsConnected == 0) - { - break; - } - if (!mKeyMaster.isProcessAlive(mPID, mProcName) ) - { - break; - } - } - } - - LL_INFOS() << "session ending.." << LL_ENDL; - - std::string per_run_dir = options["dumpdir"].asString(); - std::string per_run_file = per_run_dir + "\\SecondLife.log"; - std::string log_file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,"SecondLife.log"); - - if (gDirUtilp->fileExists(per_run_dir)) - { - LL_INFOS ("CRASHREPORT") << "Copying " << log_file << " to " << per_run_file << LL_ENDL; - LLFile::copy(log_file, per_run_file); - } - return 0; -} - - -void LLCrashLoggerWindows::OnClientConnected(void* context, - const google_breakpad::ClientInfo* client_info) -{ - sInstance->mClientsConnected++; - LL_INFOS("CRASHREPORT") << "Client connected. pid = " << client_info->pid() << " total clients " << sInstance->mClientsConnected << LL_ENDL; -} - -void LLCrashLoggerWindows::OnClientExited(void* context, - const google_breakpad::ClientInfo* client_info) -{ - sInstance->mClientsConnected--; - LL_INFOS("CRASHREPORT") << "Client disconnected. pid = " << client_info->pid() << " total clients " << sInstance->mClientsConnected << LL_ENDL; -} - - -void LLCrashLoggerWindows::OnClientDumpRequest(void* context, - const google_breakpad::ClientInfo* client_info, - const std::wstring* file_path) -{ - if (!file_path) - { - LL_WARNS() << "dump with no file path" << LL_ENDL; - return; - } - if (!client_info) - { - LL_WARNS() << "dump with no client info" << LL_ENDL; - return; - } - - LLCrashLoggerWindows* self = static_cast(context); - if (!self) - { - LL_WARNS() << "dump with no context" << LL_ENDL; - return; - } - - //DWORD pid = client_info->pid(); -} - - -bool LLCrashLoggerWindows::initCrashServer() -{ - //For Breakpad on Windows we need a full Out of Process service to get good data. - //This routine starts up the service on a named pipe that the viewer will then - //communicate with. - using namespace google_breakpad; - - LLSD options = getOptionData( LLApp::PRIORITY_COMMAND_LINE ); - std::string dump_path = options["dumpdir"].asString(); - mClientsConnected = 0; - mPID = options["pid"].asInteger(); - mProcName = options["procname"].asString(); - - //Generate a quasi-uniq name for the named pipe. For our purposes - //this is unique-enough with least hassle. Worst case for duplicate name - //is a second instance of the viewer will not do crash reporting. - std::wstring wpipe_name; - wpipe_name = mCrashReportPipeStr + std::wstring(wstringize(mPID)); - - std::wstring wdump_path(utf8str_to_utf16str(dump_path)); - - //Pipe naming conventions: http://msdn.microsoft.com/en-us/library/aa365783%28v=vs.85%29.aspx - mCrashHandler = new CrashGenerationServer( wpipe_name, - NULL, - &LLCrashLoggerWindows::OnClientConnected, this, - /*NULL, NULL, */ &LLCrashLoggerWindows::OnClientDumpRequest, this, - &LLCrashLoggerWindows::OnClientExited, this, - NULL, NULL, - true, &wdump_path); - - if (!mCrashHandler) { - //Failed to start the crash server. - LL_WARNS() << "Failed to init crash server." << LL_ENDL; - return false; - } - - // Start servicing clients. - if (!mCrashHandler->Start()) { - LL_WARNS() << "Failed to start crash server." << LL_ENDL; - return false; - } - - LL_INFOS("CRASHREPORT") << "Initialized OOP server with pipe named " << stringize(wpipe_name) << LL_ENDL; - return true; -} - -bool LLCrashLoggerWindows::init(void) -{ - bool ok = LLCrashLogger::init(); - if(!ok) return false; - - initCrashServer(); - - /* - mbstowcs( gProductName, mProductName.c_str(), LL_ARRAY_SIZE(gProductName) ); - gProductName[ LL_ARRY_SIZE(gProductName) - 1 ] = 0; - swprintf(gProductName, L"Second Life"); - */ - - LL_INFOS() << "Loading dialogs" << LL_ENDL; - - // Initialize global strings - LoadString(mhInst, IDS_APP_TITLE, szTitle, MAX_LOADSTRING); - LoadString(mhInst, IDC_WIN_CRASH_LOGGER, szWindowClass, MAX_LOADSTRING); - - gCursorArrow = LoadCursor(NULL, IDC_ARROW); - gCursorWait = LoadCursor(NULL, IDC_WAIT); - - // Register a window class that will be used by our dialogs - WNDCLASS wndclass; - wndclass.style = CS_HREDRAW | CS_VREDRAW; - wndclass.lpfnWndProc = WndProc; - wndclass.cbClsExtra = 0; - wndclass.cbWndExtra = DLGWINDOWEXTRA; // Required, since this is used for dialogs! - wndclass.hInstance = mhInst; - wndclass.hIcon = LoadIcon(hInst, MAKEINTRESOURCE( IDI_WIN_CRASH_LOGGER ) ); - wndclass.hCursor = gCursorArrow; - wndclass.hbrBackground = (HBRUSH) (COLOR_BTNFACE + 1); - wndclass.lpszMenuName = NULL; - wndclass.lpszClassName = szWindowClass; - RegisterClass( &wndclass ); - - return true; -} - -void LLCrashLoggerWindows::gatherPlatformSpecificFiles() -{ - updateApplication("Gathering hardware information. App may appear frozen."); - // DX hardware probe blocks, so we can't cancel during it - //Generate our dx_info.log file - SetCursor(gCursorWait); - // At this point we're responsive enough the user could click the close button - SetCursor(gCursorArrow); - //mDebugLog["DisplayDeviceInfo"] = gDXHardware.getDisplayInfo(); //Not initialized. -} - -bool LLCrashLoggerWindows::frame() -{ - LL_INFOS() << "CrashSubmitBehavior is " << mCrashBehavior << LL_ENDL; - - // Note: parent hwnd is 0 (the desktop). No dlg proc. See Petzold (5th ed) HexCalc example, Chapter 11, p529 - // win_crash_logger.rc has been edited by hand. - // Dialogs defined with CLASS "WIN_CRASH_LOGGER" (must be same as szWindowClass) - gProductName = mProductName; - gHwndProgress = CreateDialog(hInst, MAKEINTRESOURCE(IDD_PROGRESS), 0, NULL); - ProcessCaption(gHwndProgress); - ShowWindow(gHwndProgress, SW_HIDE ); - - if (mCrashBehavior == CRASH_BEHAVIOR_ALWAYS_SEND) - { - LL_INFOS() << "Showing crash report submit progress window." << LL_ENDL; - //ShowWindow(gHwndProgress, SW_SHOW ); Maint-5707 - sendCrashLogs(); - } - else if (mCrashBehavior == CRASH_BEHAVIOR_ASK) - { - gHwndReport = CreateDialog(hInst, MAKEINTRESOURCE(IDD_PREVREPORTBOX), 0, NULL); - // Ignore result - (void) SendDlgItemMessage(gHwndReport, IDC_CHECK_AUTO, BM_SETCHECK, 0, 0); - // Include the product name in the caption and various dialog items. - ProcessCaption(gHwndReport); - ProcessDlgItemText(gHwndReport, IDC_STATIC_MSG); - - // Update the header to include whether or not we crashed on the last run. - std::string headerStr; - TCHAR header[MAX_STRING]; - if (mCrashInPreviousExec) - { - headerStr = llformat("%s appears to have crashed or frozen the last time it ran.", mProductName.c_str()); - } - else - { - headerStr = llformat("%s appears to have crashed.", mProductName.c_str()); - } - ConvertLPCSTRToLPWSTR(headerStr.c_str(), header); - SetDlgItemText(gHwndReport, IDC_STATIC_HEADER, header); - ShowWindow(gHwndReport, SW_SHOW ); - - MSG msg; - memset(&msg, 0, sizeof(msg)); - while (!LLApp::isQuitting() && GetMessage(&msg, NULL, 0, 0)) - { - TranslateMessage(&msg); - DispatchMessage(&msg); - } - return true; // msg.wParam; - } - else - { - LL_WARNS() << "Unknown crash behavior " << mCrashBehavior << LL_ENDL; - return true; // 1; - } - return true; // 0; -} - -void LLCrashLoggerWindows::updateApplication(const std::string& message) -{ - LLCrashLogger::updateApplication(message); - if(!message.empty()) show_progress(message); - update_messages(); -} - -bool LLCrashLoggerWindows::cleanup() -{ - if(gSendLogs) - { - if(mSentCrashLogs) show_progress("Done"); - else show_progress("Could not connect to servers, logs not sent"); - sleep_and_pump_messages(3); - } - PostQuitMessage(0); - commonCleanup(); - mKeyMaster.releaseMaster(); - return true; -} - diff --git a/indra/win_crash_logger/llcrashloggerwindows.h b/indra/win_crash_logger/llcrashloggerwindows.h deleted file mode 100644 index f89b8708dc..0000000000 --- a/indra/win_crash_logger/llcrashloggerwindows.h +++ /dev/null @@ -1,86 +0,0 @@ -/** -* @file llcrashloggerwindows.h -* @brief Windows crash logger definition -* -* $LicenseInfo:firstyear=2003&license=viewerlgpl$ -* Second Life Viewer Source Code -* Copyright (C) 2010, Linden Research, Inc. -* -* This library is free software; you can redistribute it and/or -* modify it under the terms of the GNU Lesser General Public -* License as published by the Free Software Foundation; -* version 2.1 of the License only. -* -* This library is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -* Lesser General Public License for more details. -* -* You should have received a copy of the GNU Lesser General Public -* License along with this library; if not, write to the Free Software -* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -* -* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA -* $/LicenseInfo$ -*/ - -#ifndef LLCRASHLOGGERWINDOWS_H -#define LLCRASHLOGGERWINDOWS_H - -#include "llcrashlogger.h" -#include "windows.h" -#include "llstring.h" - -class LLSD; - -namespace google_breakpad { - class CrashGenerationServer; - class ClientInfo; -} - -class LLCrashLoggerWindows : public LLCrashLogger -{ -public: - LLCrashLoggerWindows(void); - ~LLCrashLoggerWindows(void); - static LLCrashLoggerWindows* sInstance; - - virtual bool init(); - virtual bool frame(); - virtual void updateApplication(const std::string& message = LLStringUtil::null); - virtual bool cleanup(); - virtual void gatherPlatformSpecificFiles(); - void setHandle(HINSTANCE hInst) { mhInst = hInst; } - int clients_connected() const { - return mClientsConnected; - } - bool getMessageWithTimeout(MSG *msg, UINT to); - - // Starts the processing loop. This function does not return unless the - // user is logging off or the user closes the crash service window. The - // return value is a good number to pass in ExitProcess(). - int processingLoop(); -private: - void ProcessDlgItemText(HWND hWnd, int nIDDlgItem); - void ProcessCaption(HWND hWnd); - bool initCrashServer(); - google_breakpad::CrashGenerationServer* mCrashHandler; - static void OnClientConnected(void* context, - const google_breakpad::ClientInfo* client_info); - - static void OnClientDumpRequest( - void* context, - const google_breakpad::ClientInfo* client_info, - const std::wstring* file_path); - - static void OnClientExited(void* context, - const google_breakpad::ClientInfo* client_info); - int mClientsConnected; - int mPID; - std::string mProcName; - - HINSTANCE mhInst; - -}; - -#endif diff --git a/indra/win_crash_logger/resource.h b/indra/win_crash_logger/resource.h deleted file mode 100644 index 37a387275e..0000000000 --- a/indra/win_crash_logger/resource.h +++ /dev/null @@ -1,63 +0,0 @@ -/** -* @file resource.h -* @brief Windows crash logger windows resources -* -* $LicenseInfo:firstyear=2003&license=viewerlgpl$ -* Second Life Viewer Source Code -* Copyright (C) 2010, Linden Research, Inc. -* -* This library is free software; you can redistribute it and/or -* modify it under the terms of the GNU Lesser General Public -* License as published by the Free Software Foundation; -* version 2.1 of the License only. -* -* This library is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -* Lesser General Public License for more details. -* -* You should have received a copy of the GNU Lesser General Public -* License along with this library; if not, write to the Free Software -* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -* -* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA -* $/LicenseInfo$ -*/ - -//{{NO_DEPENDENCIES}} -// Microsoft Visual C++ generated include file. -// Used by win_crash_logger.rc -// -#define IDC_MYICON 2 -#define IDD_REPORT 9 -#define IDD_WIN_CRASH_LOGGER_DIALOG 102 -#define IDD_ABOUTBOX 103 -#define IDS_APP_TITLE 103 -#define IDM_ABOUT 104 -#define IDM_EXIT 105 -#define IDS_HELLO 106 -#define IDI_WIN_CRASH_LOGGER 107 -#define IDI_SMALL 108 -#define IDC_WIN_CRASH_LOGGER 109 -#define IDR_MAINFRAME 128 -#define IDD_PROGRESS 129 -#define IDD_PREVREPORTBOX 130 -#define IDC_EDIT1 1000 -#define IDC_LOG 1004 -#define IDC_CHECK_AUTO 1006 -#define IDC_STATIC_HEADER 1007 -#define IDC_STATIC_WHATINFO 1008 -#define IDC_STATIC_MOTIVATION 1009 -#define IDC_STATIC_MSG 1010 -#define IDC_STATIC -1 - -// Next default values for new objects -// -#ifdef APSTUDIO_INVOKED -#ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 131 -#define _APS_NEXT_COMMAND_VALUE 32771 -#define _APS_NEXT_CONTROL_VALUE 1011 -#define _APS_NEXT_SYMED_VALUE 110 -#endif -#endif diff --git a/indra/win_crash_logger/win_crash_logger.cpp b/indra/win_crash_logger/win_crash_logger.cpp deleted file mode 100644 index 58746eba02..0000000000 --- a/indra/win_crash_logger/win_crash_logger.cpp +++ /dev/null @@ -1,70 +0,0 @@ -/** - * @file win_crash_logger.cpp - * @brief Windows crash logger implementation - * - * $LicenseInfo:firstyear=2003&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#include "linden_common.h" -#include "stdafx.h" -#include -#include "llcrashloggerwindows.h" - -#ifdef _UNICODE -int APIENTRY wWinMain(HINSTANCE hInstance, - HINSTANCE hPrevInstance, - LPWSTR lpCmdLine, - int nCmdShow) -#else -int APIENTRY WinMain(HINSTANCE hInstance, - HINSTANCE hPrevInstance, - LPSTR lpCmdLine, - int nCmdShow) -#endif //_UNICODE -{ - LL_INFOS() << "Starting crash reporter with args" << &lpCmdLine << LL_ENDL; - LLCrashLoggerWindows app; - app.setHandle(hInstance); -#ifdef _UNICODE - app.parseCommandOptions(__argc, __wargv); -#else - app.parseCommandOptions(__argc, __argv); -#endif //_UNICODE - - LLSD options = LLApp::instance()->getOptionData( - LLApp::PRIORITY_COMMAND_LINE); - if (!(options.has("pid") && options.has("dumpdir"))) - { - LL_WARNS() << "Insufficient parameters to crash report." << LL_ENDL; - } - if (! app.init()) - { - LL_WARNS() << "Unable to initialize application." << LL_ENDL; - return -1; - } - - app.processingLoop(); - app.frame(); - app.cleanup(); - LL_INFOS() << "Crash reporter finished normally." << LL_ENDL; - return 0; -} diff --git a/indra/win_crash_logger/win_crash_logger.h b/indra/win_crash_logger/win_crash_logger.h deleted file mode 100644 index 2cc2cf3dcf..0000000000 --- a/indra/win_crash_logger/win_crash_logger.h +++ /dev/null @@ -1,38 +0,0 @@ -/** - * @file win_crash_logger.h - * @brief Windows crash logger project includes - * - * $LicenseInfo:firstyear=2003&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - - -#if !defined(AFX_WIN_CRASH_LOGGER_H__79802F4B_7C37_4F63_A2BB_0768788C3A27__INCLUDED_) -#define AFX_WIN_CRASH_LOGGER_H__79802F4B_7C37_4F63_A2BB_0768788C3A27__INCLUDED_ - -#if _MSC_VER > 1000 -#pragma once -#endif // _MSC_VER > 1000 - -#include "resource.h" - - -#endif // !defined(AFX_WIN_CRASH_LOGGER_H__79802F4B_7C37_4F63_A2BB_0768788C3A27__INCLUDED_) diff --git a/indra/win_crash_logger/win_crash_logger.ico b/indra/win_crash_logger/win_crash_logger.ico deleted file mode 100644 index 386883523bcc032db77b69b047cbc5c15ae3b7fe..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1078 zcmeH_K@!3s3`IZHwe$$AoF2oYaWszOk{jR)NR>_(PRDWOZgV)&%Zp6VccBVa2?uQ&sh9LW;!?J w2dwKn!S@jnH5GJS10MR3&V{nkc?%F^XS#jrb=7ItXV>BJ*yg?&H~)SR4}%AClK=n! diff --git a/indra/win_crash_logger/win_crash_logger.rc b/indra/win_crash_logger/win_crash_logger.rc deleted file mode 100755 index 2819722f63..0000000000 --- a/indra/win_crash_logger/win_crash_logger.rc +++ /dev/null @@ -1,188 +0,0 @@ -// Microsoft Visual C++ generated resource script. -// -#include "resource.h" - -#define APSTUDIO_READONLY_SYMBOLS -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 2 resource. -// -#define APSTUDIO_HIDDEN_SYMBOLS -#include "windows.h" -#undef APSTUDIO_HIDDEN_SYMBOLS -#include "resource.h" - -///////////////////////////////////////////////////////////////////////////// -#undef APSTUDIO_READONLY_SYMBOLS - -///////////////////////////////////////////////////////////////////////////// -// English (U.S.) resources - -#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) -#ifdef _WIN32 -LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US -#pragma code_page(1252) -#endif //_WIN32 - -///////////////////////////////////////////////////////////////////////////// -// -// Icon -// - -// Icon with lowest ID value placed first to ensure application icon -// remains consistent on all systems. -IDI_WIN_CRASH_LOGGER ICON "ll_icon.ico" - -///////////////////////////////////////////////////////////////////////////// -// -// Menu -// - -IDC_WIN_CRASH_LOGGER MENU -BEGIN - POPUP "&File" - BEGIN - MENUITEM "E&xit", IDM_EXIT - END - POPUP "&Help" - BEGIN - MENUITEM "&About ...", IDM_ABOUT - END -END - - -///////////////////////////////////////////////////////////////////////////// -// -// Dialog -// - -IDD_PROGRESS DIALOGEX 100, 100, 234, 33 -STYLE DS_SETFONT | DS_SETFOREGROUND | WS_CAPTION | WS_SYSMENU -CAPTION "%s Crash Logger" -CLASS "WIN_CRASH_LOGGER" -FONT 8, "MS Sans Serif", 0, 0, 0x0 -BEGIN - LTEXT "Static",IDC_LOG,7,7,220,8 -END - -IDD_REPORT DIALOGEX 100, 100, 297, 125 -STYLE DS_SETFONT | DS_SETFOREGROUND | WS_CAPTION | WS_SYSMENU -CAPTION "%s Crash Logger" -CLASS "WIN_CRASH_LOGGER" -FONT 8, "MS Sans Serif", 0, 0, 0x0 -BEGIN - DEFPUSHBUTTON "Send",IDOK,198,104,45,15,WS_GROUP - PUSHBUTTON "Don't Send",IDCANCEL,247,104,45,15,WS_GROUP - LTEXT "%s appears to have crashed.",IDC_STATIC_HEADER,4,4,288,14 - LTEXT "This crash reporter collects information about your computer's hardware, operating system, and some %s logs, which are used for debugging purposes only.",IDC_STATIC_WHATINFO,4,23,288,19,NOT WS_GROUP - CONTROL "Remember this choice",IDC_CHECK_AUTO,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,4,106,89,13 - LTEXT "Sending crash reports is the best way to help us improve the quality of %s.",IDC_STATIC_MOTIVATION,4,43,288,8 - LTEXT "If you continue to experience this problem, please try:",IDC_STATIC,4,57,251,8 - LTEXT "- Contacting support by visiting http://www.secondlife.com/support",IDC_STATIC,4,67,231,8 -END - -IDD_PREVREPORTBOX DIALOGEX 100, 100, 232, 213 -STYLE DS_SETFONT | DS_SETFOREGROUND | WS_CAPTION | WS_SYSMENU -CAPTION "%s Crash Logger" -CLASS "WIN_CRASH_LOGGER" -FONT 8, "MS Sans Serif", 0, 0, 0x0 -BEGIN - DEFPUSHBUTTON "Send Report",IDOK,131,193,45,15,WS_GROUP - EDITTEXT IDC_EDIT1,3,100,223,89,ES_MULTILINE | ES_WANTRETURN | WS_VSCROLL - PUSHBUTTON "Don't Send",IDCANCEL,181,193,45,15,WS_GROUP - LTEXT "%s appears to have crashed or frozen the last time it ran.",IDC_STATIC_HEADER,4,4,214,8 - LTEXT "This crash reporter collects information about your computer's",IDC_STATIC,4,17,201,8 - LTEXT "hardware configuration, operating system, and some %s",IDC_STATIC_MSG,4,25,212,8 - LTEXT "logs, all of which are used for debugging purposes only.",IDC_STATIC,4,33,210,8 - LTEXT "In the space below, please briefly describe what you were doing",IDC_STATIC,3,48,208,8 - LTEXT "or trying to do just prior to the crash.",IDC_STATIC,3,56,204,8 - LTEXT "If you don't wish to send Linden Lab a crash report, press Don't Send.",IDC_STATIC,3,90,223,8 - LTEXT "This report is NOT read by customer support. If you have billing or",IDC_STATIC,3,68,208,8 - LTEXT "other questions, please go to: www.secondlife.com/support",IDC_STATIC,3,76,206,8 - CONTROL "Remember this choice",IDC_CHECK_AUTO,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,3,193,89,13 -END - - -#ifdef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// TEXTINCLUDE -// - -2 TEXTINCLUDE -BEGIN - "#define APSTUDIO_HIDDEN_SYMBOLS\r\n" - "#include ""windows.h""\r\n" - "#undef APSTUDIO_HIDDEN_SYMBOLS\r\n" - "#include ""resource.h""\r\n" - "\0" -END - -3 TEXTINCLUDE -BEGIN - "\r\n" - "\0" -END - -1 TEXTINCLUDE -BEGIN - "resource.h\0" -END - -#endif // APSTUDIO_INVOKED - - -///////////////////////////////////////////////////////////////////////////// -// -// DESIGNINFO -// - -#ifdef APSTUDIO_INVOKED -GUIDELINES DESIGNINFO -BEGIN - IDD_PROGRESS, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 227 - TOPMARGIN, 7 - BOTTOMMARGIN, 26 - END - - IDD_REPORT, DIALOG - BEGIN - RIGHTMARGIN, 292 - VERTGUIDE, 4 - BOTTOMMARGIN, 119 - HORZGUIDE, 4 - END -END -#endif // APSTUDIO_INVOKED - - -///////////////////////////////////////////////////////////////////////////// -// -// String Table -// - -STRINGTABLE -BEGIN - IDS_APP_TITLE "win_crash_logger" - IDS_HELLO "Hello World!" - IDC_WIN_CRASH_LOGGER "WIN_CRASH_LOGGER" -END - -#endif // English (U.S.) resources -///////////////////////////////////////////////////////////////////////////// - - - -#ifndef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 3 resource. -// - - -///////////////////////////////////////////////////////////////////////////// -#endif // not APSTUDIO_INVOKED - From 2febf90744624120b9d93708792ed5aaedb8ad14 Mon Sep 17 00:00:00 2001 From: Andrey Lihatskiy Date: Wed, 17 Mar 2021 08:53:20 +0200 Subject: [PATCH 095/443] SL-14541 follow-up xcode buildfix --- indra/cmake/Copy3rdPartyLibs.cmake | 1 - indra/llcommon/llapp.cpp | 4 ---- indra/llcorehttp/CMakeLists.txt | 1 - indra/newview/viewer_manifest.py | 1 - 4 files changed, 7 deletions(-) diff --git a/indra/cmake/Copy3rdPartyLibs.cmake b/indra/cmake/Copy3rdPartyLibs.cmake index 8efad33f71..742acabe5f 100644 --- a/indra/cmake/Copy3rdPartyLibs.cmake +++ b/indra/cmake/Copy3rdPartyLibs.cmake @@ -157,7 +157,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/llcommon/llapp.cpp b/indra/llcommon/llapp.cpp index c9e4cf2ab3..f66a6fb4dc 100644 --- a/indra/llcommon/llapp.cpp +++ b/indra/llcommon/llapp.cpp @@ -437,10 +437,6 @@ void LLApp::setupErrorHandling(bool second_instance) } #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)) { diff --git a/indra/llcorehttp/CMakeLists.txt b/indra/llcorehttp/CMakeLists.txt index 11b2e3e929..96a1057a63 100644 --- a/indra/llcorehttp/CMakeLists.txt +++ b/indra/llcorehttp/CMakeLists.txt @@ -176,7 +176,6 @@ if (DARWIN) set(copy_dylibs libapr-1.0.dylib libaprutil-1.0.dylib - libexception_handler.dylib libnghttp2*.dylib ${EXPAT_COPY} ) diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py index af7e799269..5a39616d55 100755 --- a/indra/newview/viewer_manifest.py +++ b/indra/newview/viewer_manifest.py @@ -1024,7 +1024,6 @@ class DarwinManifest(ViewerManifest): "libapr-1.0.dylib", "libaprutil-1.0.dylib", "libexpat.1.dylib", - "libexception_handler.dylib", "libGLOD.dylib", # libnghttp2.dylib is a symlink to # libnghttp2.major.dylib, which is a symlink to From 0feb3b4eb439c80d926bfd6fefc1cc9953eb6f89 Mon Sep 17 00:00:00 2001 From: Nicky Date: Wed, 17 Mar 2021 19:20:56 +0100 Subject: [PATCH 096/443] Linux; Remove breakpad artifacts. --- indra/llcommon/llapp.cpp | 58 +--------------------------------------- 1 file changed, 1 insertion(+), 57 deletions(-) diff --git a/indra/llcommon/llapp.cpp b/indra/llcommon/llapp.cpp index a08ff2ce22..9025015048 100644 --- a/indra/llcommon/llapp.cpp +++ b/indra/llcommon/llapp.cpp @@ -69,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, @@ -438,17 +434,7 @@ void LLApp::setupErrorHandling(bool second_instance) } #endif // ! LL_RELEASE_FOR_DOWNLOAD -#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_DARWIN #endif // ! LL_WINDOWS startErrorThread(); @@ -898,48 +884,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) From d039580d0736004af642f4620b5f40e1f762a24a Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Mon, 22 Mar 2021 23:45:25 +0200 Subject: [PATCH 097/443] SL-14993 Crash accessing mInvBindMatrix --- indra/llprimitive/llmodel.cpp | 30 +++++++++++++++++----------- indra/newview/llskinningutil.cpp | 34 +++----------------------------- indra/newview/llskinningutil.h | 1 - 3 files changed, 22 insertions(+), 43 deletions(-) diff --git a/indra/llprimitive/llmodel.cpp b/indra/llprimitive/llmodel.cpp index a2d9b4cd9b..702a1b5238 100644 --- a/indra/llprimitive/llmodel.cpp +++ b/indra/llprimitive/llmodel.cpp @@ -434,7 +434,7 @@ void LLModel::generateNormals(F32 angle_cutoff) if (vol_face.mNumIndices > 65535) { - LL_WARNS() << "Too many vertices for normal generation to work." << LL_ENDL; + LL_WARNS("MESHSKININFO") << "Too many vertices for normal generation to work." << LL_ENDL; continue; } @@ -1100,7 +1100,7 @@ bool LLModel::loadModel(std::istream& is) { if (!LLSDSerialize::fromBinary(header, is, 1024*1024*1024)) { - LL_WARNS() << "Mesh header parse error. Not a valid mesh asset!" << LL_ENDL; + LL_WARNS("MESHSKININFO") << "Mesh header parse error. Not a valid mesh asset!" << LL_ENDL; return false; } } @@ -1132,7 +1132,7 @@ bool LLModel::loadModel(std::istream& is) if (header[lod_name[lod]]["offset"].asInteger() == -1 || header[lod_name[lod]]["size"].asInteger() == 0 ) { //cannot load requested LOD - LL_WARNS() << "LoD data is invalid!" << LL_ENDL; + LL_WARNS("MESHSKININFO") << "LoD data is invalid!" << LL_ENDL; return false; } @@ -1195,7 +1195,7 @@ bool LLModel::loadModel(std::istream& is) } else { - LL_WARNS() << "unpackVolumeFaces failed!" << LL_ENDL; + LL_WARNS("MESHSKININFO") << "unpackVolumeFaces failed!" << LL_ENDL; } return false; @@ -1223,7 +1223,7 @@ bool LLModel::isMaterialListSubset( LLModel* ref ) if (!foundRef) { - LL_INFOS() << "Could not find material " << mMaterialList[src] << " in reference model " << ref->mLabel << LL_ENDL; + LL_INFOS("MESHSKININFO") << "Could not find material " << mMaterialList[src] << " in reference model " << ref->mLabel << LL_ENDL; return false; } } @@ -1259,7 +1259,7 @@ bool LLModel::matchMaterialOrder(LLModel* ref, int& refFaceCnt, int& modelFaceCn bool isASubset = isMaterialListSubset( ref ); if ( !isASubset ) { - LL_INFOS()<<"Material of model is not a subset of reference."<= face.mNumVertices) { - LL_WARNS() << "Face has invalid index." << LL_ENDL; + LL_WARNS("MESHSKININFO") << "Face has invalid index." << LL_ENDL; return false; } } if (face.mNumIndices % 3 != 0 || face.mNumIndices == 0) { - LL_WARNS() << "Face has invalid number of indices." << LL_ENDL; + LL_WARNS("MESHSKININFO") << "Face has invalid number of indices." << LL_ENDL; return false; } @@ -1879,7 +1887,7 @@ bool validate_model(const LLModel* mdl) { if (mdl->getNumVolumeFaces() == 0) { - LL_WARNS() << "Model has no faces!" << LL_ENDL; + LL_WARNS("MESHSKININFO") << "Model has no faces!" << LL_ENDL; return false; } @@ -1887,13 +1895,13 @@ bool validate_model(const LLModel* mdl) { if (mdl->getVolumeFace(i).mNumVertices == 0) { - LL_WARNS() << "Face has no vertices." << LL_ENDL; + LL_WARNS("MESHSKININFO") << "Face has no vertices." << LL_ENDL; return false; } if (mdl->getVolumeFace(i).mNumIndices == 0) { - LL_WARNS() << "Face has no indices." << LL_ENDL; + LL_WARNS("MESHSKININFO") << "Face has no indices." << LL_ENDL; return false; } diff --git a/indra/newview/llskinningutil.cpp b/indra/newview/llskinningutil.cpp index 1fb63c7444..f325315933 100644 --- a/indra/newview/llskinningutil.cpp +++ b/indra/newview/llskinningutil.cpp @@ -309,7 +309,8 @@ void LLSkinningUtil::updateRiggingInfo(const LLMeshSkinInfo* skin, LLVOAvatar *a if (vol_face.mJointRiggingInfoTab.needsUpdate()) { S32 num_verts = vol_face.mNumVertices; - if (num_verts>0 && vol_face.mWeights && (skin->mJointNames.size()>0)) + S32 num_joints = skin->mJointNames.size(); + if (num_verts > 0 && vol_face.mWeights && num_joints > 0) { initJointNums(const_cast(skin), avatar); if (vol_face.mJointRiggingInfoTab.size()==0) @@ -343,7 +344,7 @@ void LLSkinningUtil::updateRiggingInfo(const LLMeshSkinInfo* skin, LLVOAvatar *a for (U32 k=0; k<4; ++k) { S32 joint_index = idx[k]; - if (wght[k] > 0.0f) + if (wght[k] > 0.0f && num_joints > joint_index) { S32 joint_num = skin->mJointNums[joint_index]; if (joint_num >= 0 && joint_num < LL_CHARACTER_MAX_ANIMATED_JOINTS) @@ -394,35 +395,6 @@ void LLSkinningUtil::updateRiggingInfo(const LLMeshSkinInfo* skin, LLVOAvatar *a } } -void LLSkinningUtil::updateRiggingInfo_(LLMeshSkinInfo* skin, LLVOAvatar *avatar, S32 num_verts, LLVector4a* weights, LLVector4a* positions, U8* joint_indices, LLJointRiggingInfoTab &rig_info_tab) -{ - LL_RECORD_BLOCK_TIME(FTM_FACE_RIGGING_INFO); - for (S32 i=0; i < num_verts; i++) - { - LLVector4a& pos = positions[i]; - LLVector4a& wght = weights[i]; - for (U32 k=0; k<4; ++k) - { - S32 joint_num = skin->mJointNums[joint_indices[k]]; - llassert(joint_num >= 0 && joint_num < LL_CHARACTER_MAX_ANIMATED_JOINTS); - { - rig_info_tab[joint_num].setIsRiggedTo(true); - LLMatrix4a bind_shape; - bind_shape.loadu(skin->mBindShapeMatrix); - LLMatrix4a inv_bind; - inv_bind.loadu(skin->mInvBindMatrix[joint_indices[k]]); - LLMatrix4a mat; - matMul(bind_shape, inv_bind, mat); - LLVector4a pos_joint_space; - mat.affineTransform(pos, pos_joint_space); - pos_joint_space.mul(wght[k]); - LLVector4a *extents = rig_info_tab[joint_num].getRiggedExtents(); - update_min_max(extents[0], extents[1], pos_joint_space); - } - } - } -} - // This is used for extracting rotation from a bind shape matrix that // already has scales baked in LLQuaternion LLSkinningUtil::getUnscaledQuaternion(const LLMatrix4& mat4) diff --git a/indra/newview/llskinningutil.h b/indra/newview/llskinningutil.h index 549aa6a29f..efe7c85997 100644 --- a/indra/newview/llskinningutil.h +++ b/indra/newview/llskinningutil.h @@ -67,7 +67,6 @@ namespace LLSkinningUtil void initJointNums(LLMeshSkinInfo* skin, LLVOAvatar *avatar); void updateRiggingInfo(const LLMeshSkinInfo* skin, LLVOAvatar *avatar, LLVolumeFace& vol_face); - void updateRiggingInfo_(LLMeshSkinInfo* skin, LLVOAvatar *avatar, S32 num_verts, LLVector4a* weights, LLVector4a* positions, U8* joint_indices, LLJointRiggingInfoTab &rig_info_tab); LLQuaternion getUnscaledQuaternion(const LLMatrix4& mat4); }; From 9f95e619c9802bd405db43afa3fbf6b5ad82799d Mon Sep 17 00:00:00 2001 From: Callum Prentice Date: Fri, 26 Mar 2021 11:47:41 -0700 Subject: [PATCH 098/443] Add some logging for QA purposes (based on INFO/Mesh tag) to display when the mesh header and the mesh body is retrieved from the simulator or the local cache. --- indra/newview/llmeshrepository.cpp | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp index c2404a7e67..a93b3b4bfd 100644 --- a/indra/newview/llmeshrepository.cpp +++ b/indra/newview/llmeshrepository.cpp @@ -1647,6 +1647,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_INFOS(LOG_MESH) << "Mesh/Cache: Mesh header for ID " << mid << " - was retrieved from the cache." << LL_ENDL; + // Found mesh in cache return true; } @@ -1658,8 +1662,13 @@ bool LLMeshRepoThread::fetchMeshHeader(const LLVolumeParams& mesh_params, bool c std::string http_url; constructUrl(mesh_params.getSculptID(), &http_url); + if (!http_url.empty()) { + std::string mid; + mesh_params.getSculptID().toString(mid); + LL_INFOS(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 @@ -1740,6 +1749,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_INFOS(LOG_MESH) << "Mesh/Cache: Mesh body for ID " << mid << " - was retrieved from the cache." << LL_ENDL; + return true; } } @@ -1750,9 +1764,13 @@ bool LLMeshRepoThread::fetchMeshLOD(const LLVolumeParams& mesh_params, S32 lod, //reading from cache failed for whatever reason, fetch from sim std::string http_url; constructUrl(mesh_id, &http_url); - + if (!http_url.empty()) { + std::string mid; + mesh_id.toString(mid); + LL_INFOS(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)); LLCore::HttpHandle handle = getByteRange(http_url, offset, size, handler); if (LLCORE_HTTP_HANDLE_INVALID == handle) From dca449f65c82343ccc0a67719011d95e1f78bdc4 Mon Sep 17 00:00:00 2001 From: Ansariel Date: Fri, 2 Apr 2021 22:52:26 +0200 Subject: [PATCH 099/443] Re-apply after DRTVWR-514 changes --- indra/newview/lltoolpie.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/indra/newview/lltoolpie.cpp b/indra/newview/lltoolpie.cpp index 03cd0439b0..232decef68 100644 --- a/indra/newview/lltoolpie.cpp +++ b/indra/newview/lltoolpie.cpp @@ -746,12 +746,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); // deault 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 From bf4256fff0dc13dcb83c0fb1ff22cbd9618575fc Mon Sep 17 00:00:00 2001 From: Mnikolenko Productengine Date: Mon, 5 Apr 2021 15:35:19 +0300 Subject: [PATCH 100/443] SL-15070 FIXED Moving the cache does not remove the "cache" folder from the old location --- indra/newview/llappviewer.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 934a3313be..76c38ea024 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -4158,6 +4158,7 @@ bool LLAppViewer::initCache() LL_INFOS("AppCache") << "Cache location changed, cache needs purging" << LL_ENDL; gDirUtilp->setCacheDir(gSavedSettings.getString("CacheLocation")); purgeCache(); // purge old cache + gDirUtilp->deleteDirAndContents(gDirUtilp->getExpandedFilename(LL_PATH_CACHE, cache_dir_name)); gSavedSettings.setString("CacheLocation", new_cache_location); gSavedSettings.setString("CacheLocationTopFolder", gDirUtilp->getBaseFileName(new_cache_location)); } From 5ab76453bb53424bbbc77a0d0b818ba05bceb92d Mon Sep 17 00:00:00 2001 From: Ansariel Date: Mon, 5 Apr 2021 20:52:49 +0200 Subject: [PATCH 101/443] Fix merge errors --- indra/newview/lltoolpie.cpp | 59 ++----------------------------------- 1 file changed, 3 insertions(+), 56 deletions(-) diff --git a/indra/newview/lltoolpie.cpp b/indra/newview/lltoolpie.cpp index 5b6c540666..3628946260 100644 --- a/indra/newview/lltoolpie.cpp +++ b/indra/newview/lltoolpie.cpp @@ -658,9 +658,10 @@ 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; - 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))) { LLVector3d pos = mHoverPick.mPosGlobal; pos.mdV[VZ] += gAgentAvatarp->getPelvisToFoot(); @@ -878,60 +879,6 @@ BOOL LLToolPie::handleDoubleClick(S32 x, S32 y, MASK mask) } mDoubleClickTimer.stop(); - if (gSavedSettings.getBOOL("DoubleClickAutoPilot")) - { - // We may be doing double click to walk, but we don't want to use a target on - // a transparent object because the user thought they were clicking on - // whatever they were seeing through it, so recompute what was clicked on - // ignoring transparent objects - LLPickInfo savedPick = mPick; - mPick = gViewerWindow->pickImmediate(savedPick.mMousePt.mX, savedPick.mMousePt.mY, - FALSE /* ignore transparent */, - FALSE /* ignore rigged */, - FALSE /* ignore particles */); - - if(mPick.mPickType == LLPickInfo::PICK_OBJECT) - { - if (mPick.getObject() && mPick.getObject()->isHUDAttachment()) - { - mPick = savedPick; - return FALSE; - } - } - - if ((mPick.mPickType == LLPickInfo::PICK_LAND && !mPick.mPosGlobal.isExactlyZero()) || - (mPick.mObjectID.notNull() && !mPick.mPosGlobal.isExactlyZero())) - { - walkToClickedLocation(); - return TRUE; - } - else - { - // restore the original pick for any other purpose - mPick = savedPick; - } - } - else if (gSavedSettings.getBOOL("DoubleClickTeleport")) - { - LLViewerObject* objp = mPick.getObject(); - LLViewerObject* parentp = objp ? objp->getRootEdit() : NULL; - - bool is_in_world = mPick.mObjectID.notNull() && objp && !objp->isHUDAttachment(); - bool is_land = mPick.mPickType == LLPickInfo::PICK_LAND; - bool pos_non_zero = !mPick.mPosGlobal.isExactlyZero(); - bool has_touch_handler = (objp && objp->flagHandleTouch()) || (parentp && parentp->flagHandleTouch()); - U8 click_action = final_click_action(objp); // deault action: 0 - touch - bool has_click_action = (click_action || has_touch_handler) && click_action != CLICK_ACTION_DISABLED; - - if (pos_non_zero && (is_land || (is_in_world && !has_click_action))) - { - LLVector3d pos = mPick.mPosGlobal; - pos.mdV[VZ] += gAgentAvatarp->getPelvisToFoot(); - gAgent.teleportViaLocationLookAt(pos); - return TRUE; - } - } - return FALSE; } From 455db074b0bd286031f075f251abe7caa5a2c76e Mon Sep 17 00:00:00 2001 From: Mnikolenko Productengine Date: Tue, 6 Apr 2021 18:24:21 +0300 Subject: [PATCH 102/443] SL-14960 Add checkbox to turn off collision sound. --- indra/llprimitive/llmaterialtable.cpp | 17 +++++++++++++++++ indra/llprimitive/llmaterialtable.h | 2 ++ indra/newview/app_settings/settings.xml | 11 +++++++++++ indra/newview/llviewermessage.cpp | 6 ++++++ .../default/xui/en/panel_preferences_move.xml | 9 +++++++++ 5 files changed, 45 insertions(+) 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/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index d4ef9cd974..0236720c20 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -3748,6 +3748,17 @@ Value 1 + EnableCollisionSounds + + Comment + Play sounds on collision + Persist + 1 + Type + Boolean + Value + 0 + EnableMouselook Comment diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp index 458fc3b13d..126d146ac6 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" @@ -3857,6 +3858,11 @@ void process_sound_trigger(LLMessageSystem *msg, void **) return; } + if (LLMaterialTable::basic.isCollisionSound(sound_id) && !gSavedSettings.getBOOL("EnableCollisionSounds")) + { + return; + } + gAudiop->triggerSound(sound_id, owner_id, gain, LLAudioEngine::AUDIO_TYPE_SFX, pos_global); } diff --git a/indra/newview/skins/default/xui/en/panel_preferences_move.xml b/indra/newview/skins/default/xui/en/panel_preferences_move.xml index 8794e3bf95..864223e616 100644 --- a/indra/newview/skins/default/xui/en/panel_preferences_move.xml +++ b/indra/newview/skins/default/xui/en/panel_preferences_move.xml @@ -259,6 +259,15 @@ + + + Back + + + HUDs displayed: + + + 7 + + + If there are any you don't need, detaching them may improve graphics speed. + + + Note: Using a HUD's minimize button does not save memory. + + + + + + + + + Back + + + Avatars within draw distance: + + + 42 (very high) + + + Some avatars nearby are slow to display. Choosing complexity limit may help graphics speed. + + + + + + 0 + + + + + + + + You can also right-click on an avatar to control display. + + + + + + + diff --git a/indra/newview/skins/default/xui/en/panel_performance_preferences.xml b/indra/newview/skins/default/xui/en/panel_performance_preferences.xml new file mode 100644 index 0000000000..81605b35a2 --- /dev/null +++ b/indra/newview/skins/default/xui/en/panel_performance_preferences.xml @@ -0,0 +1,257 @@ + + + + + Back + + + This location is very complex + + + While you are here, you may want to reduce graphics quality or draw distance. + + + + Graphics quality + + + Fastest + + + + + Best quality + + + Enhancements + + + + + + + Draw distance + + + Faster + + + + m + + + Farther + + + Regions are 256 m x 256 m. + + + To zoom out and see long distances, increase the draw distance. + + + If you are socializing in a small area, decrease the draw distance. + + + + + Back + + + Avatar attachment scripts: + + + 12 + + + These attachments contain scripts (embedded apps) that use memory. + + + If there are any you don't need, detaching them may improve graphics speed. + + diff --git a/indra/newview/skins/default/xui/en/panel_performance_troubleshooting.xml b/indra/newview/skins/default/xui/en/panel_performance_troubleshooting.xml new file mode 100644 index 0000000000..d942580880 --- /dev/null +++ b/indra/newview/skins/default/xui/en/panel_performance_troubleshooting.xml @@ -0,0 +1,190 @@ + + + + + Back + + + Fixes for common problems + + + Some problems result from the complexity of the location where you are. All you can do is leave. + + + Rubberbanding + + + When you walk, your avatar may be pulled backward again and again. + + + Fix: XXXXXXX + + + Texture thrashing + + + On objects near you, you may see their surfaces get blurry, then sharp, then blurry again. + + + Fix: XXXXXXX + + + Avatars are not moving smoothly + + + Lorem ipsum dolor sit amet. + + + Fix: XXXXXXX + + + Will a better graphics card or new computer help? + + + Lorem ipsum dolor sit amet. + + + Fix: XXXXXXX + + From d0f2a2c2008006b57f181e8dfa5e20940687a941 Mon Sep 17 00:00:00 2001 From: Callum Prentice Date: Fri, 11 Jun 2021 11:01:07 -0700 Subject: [PATCH 155/443] Fix for SL-15389 -- Pull in the patch to add the Akamai cert fix specified in SL-15370 --- indra/newview/llsechandler_basic.cpp | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/indra/newview/llsechandler_basic.cpp b/indra/newview/llsechandler_basic.cpp index 737ef30ada..19db020a31 100644 --- a/indra/newview/llsechandler_basic.cpp +++ b/indra/newview/llsechandler_basic.cpp @@ -915,11 +915,19 @@ void _validateCert(int validation_policy, } if (validation_policy & VALIDATION_POLICY_SSL_KU) { + // This stanza of code was changed 2021-06-09 as per details in SL-15370. + // Brief summary: a renewed certificate from Akamai only contains the + // 'Digital Signature' field and not the 'Key Encipherment' one. This code + // used to look for both and throw an exception at startup (ignored) and + // (for example) when buying L$ in the Viewer (fails with a UI message + // and an entry in the Viewer log). This modified code removes the second + // check for the 'Key Encipherment' field. If Akamai can provide a + // replacement certificate that has both fields, then this modified code + // will not be required. if (current_cert_info.has(CERT_KEY_USAGE) && current_cert_info[CERT_KEY_USAGE].isArray() && - (!(_LLSDArrayIncludesValue(current_cert_info[CERT_KEY_USAGE], - LLSD((std::string)CERT_KU_DIGITAL_SIGNATURE))) || !(_LLSDArrayIncludesValue(current_cert_info[CERT_KEY_USAGE], - LLSD((std::string)CERT_KU_KEY_ENCIPHERMENT))))) + LLSD((std::string)CERT_KU_DIGITAL_SIGNATURE))) + ) { LLTHROW(LLCertKeyUsageValidationException(current_cert_info)); } From 564a7acb321c54ad5f9fc6f5242efbe4c7638dbc Mon Sep 17 00:00:00 2001 From: Ansariel Date: Fri, 11 Jun 2021 22:50:39 +0200 Subject: [PATCH 156/443] Change all remaining boost::filesystem methods to their non-throwing overloads --- indra/llfilesystem/lldiskcache.cpp | 35 ++++++++++++++++++++---------- 1 file changed, 24 insertions(+), 11 deletions(-) diff --git a/indra/llfilesystem/lldiskcache.cpp b/indra/llfilesystem/lldiskcache.cpp index f4d20d0e61..dd8916dccb 100644 --- a/indra/llfilesystem/lldiskcache.cpp +++ b/indra/llfilesystem/lldiskcache.cpp @@ -87,6 +87,7 @@ void LLDiskCache::purge() LL_INFOS() << "Total dir size before purge is " << dirFileSize(mCacheDir) << LL_ENDL; } + boost::system::error_code ec; auto start_time = std::chrono::high_resolution_clock::now(); typedef std::pair> file_info_t; @@ -97,17 +98,25 @@ void LLDiskCache::purge() #else std::string cache_path(mCacheDir); #endif - if (boost::filesystem::is_directory(cache_path)) + if (boost::filesystem::is_directory(cache_path, ec) && !ec.failed()) { for (auto& entry : boost::make_iterator_range(boost::filesystem::directory_iterator(cache_path), {})) { - if (boost::filesystem::is_regular_file(entry)) + if (boost::filesystem::is_regular_file(entry, ec) && !ec.failed()) { if (entry.path().string().find(mCacheFilenamePrefix) != std::string::npos) { - uintmax_t file_size = boost::filesystem::file_size(entry); + uintmax_t file_size = boost::filesystem::file_size(entry, ec); + if (ec.failed()) + { + continue; + } const std::string file_path = entry.path().string(); - const std::time_t file_time = boost::filesystem::last_write_time(entry); + const std::time_t file_time = boost::filesystem::last_write_time(entry, ec); + if (ec.failed()) + { + continue; + } file_info.push_back(file_info_t(file_time, { file_size, file_path })); } @@ -131,7 +140,6 @@ void LLDiskCache::purge() if (file_size_total > mMaxSizeBytes) { action = "DELETE:"; - boost::system::error_code ec; boost::filesystem::remove(entry.second.second, ec); if (ec.failed()) { @@ -321,20 +329,20 @@ void LLDiskCache::clearCache() * the component files but it's called infrequently so it's * likely just fine */ + boost::system::error_code ec; #if LL_WINDOWS std::wstring cache_path(utf8str_to_utf16str(mCacheDir)); #else std::string cache_path(mCacheDir); #endif - if (boost::filesystem::is_directory(cache_path)) + if (boost::filesystem::is_directory(cache_path, ec) && !ec.failed()) { for (auto& entry : boost::make_iterator_range(boost::filesystem::directory_iterator(cache_path), {})) { - if (boost::filesystem::is_regular_file(entry)) + if (boost::filesystem::is_regular_file(entry, ec) && !ec.failed()) { if (entry.path().string().find(mCacheFilenamePrefix) != std::string::npos) { - boost::system::error_code ec; boost::filesystem::remove(entry, ec); if (ec.failed()) { @@ -359,20 +367,25 @@ uintmax_t LLDiskCache::dirFileSize(const std::string dir) * so if performance is ever an issue, optimizing this or removing it altogether, * is an easy win. */ + boost::system::error_code ec; #if LL_WINDOWS std::wstring dir_path(utf8str_to_utf16str(dir)); #else std::string dir_path(dir); #endif - if (boost::filesystem::is_directory(dir_path)) + if (boost::filesystem::is_directory(dir_path, ec) && !ec.failed()) { for (auto& entry : boost::make_iterator_range(boost::filesystem::directory_iterator(dir_path), {})) { - if (boost::filesystem::is_regular_file(entry)) + if (boost::filesystem::is_regular_file(entry, ec) && !ec.failed()) { if (entry.path().string().find(mCacheFilenamePrefix) != std::string::npos) { - total_file_size += boost::filesystem::file_size(entry); + uintmax_t file_size = boost::filesystem::file_size(entry, ec); + if (!ec.failed()) + { + total_file_size += file_size; + } } } } From fedae88be7b7174956f549194b13883ff2cb4161 Mon Sep 17 00:00:00 2001 From: Ansariel Date: Fri, 11 Jun 2021 22:59:55 +0200 Subject: [PATCH 157/443] boost::filesystem::directory_iterator uses throw-behavior by default as well --- indra/llfilesystem/lldiskcache.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/indra/llfilesystem/lldiskcache.cpp b/indra/llfilesystem/lldiskcache.cpp index dd8916dccb..ee43a599f7 100644 --- a/indra/llfilesystem/lldiskcache.cpp +++ b/indra/llfilesystem/lldiskcache.cpp @@ -100,7 +100,7 @@ void LLDiskCache::purge() #endif if (boost::filesystem::is_directory(cache_path, ec) && !ec.failed()) { - for (auto& entry : boost::make_iterator_range(boost::filesystem::directory_iterator(cache_path), {})) + for (auto& entry : boost::make_iterator_range(boost::filesystem::directory_iterator(cache_path, ec), {})) { if (boost::filesystem::is_regular_file(entry, ec) && !ec.failed()) { @@ -337,7 +337,7 @@ void LLDiskCache::clearCache() #endif if (boost::filesystem::is_directory(cache_path, ec) && !ec.failed()) { - for (auto& entry : boost::make_iterator_range(boost::filesystem::directory_iterator(cache_path), {})) + for (auto& entry : boost::make_iterator_range(boost::filesystem::directory_iterator(cache_path, ec), {})) { if (boost::filesystem::is_regular_file(entry, ec) && !ec.failed()) { @@ -375,7 +375,7 @@ uintmax_t LLDiskCache::dirFileSize(const std::string dir) #endif if (boost::filesystem::is_directory(dir_path, ec) && !ec.failed()) { - for (auto& entry : boost::make_iterator_range(boost::filesystem::directory_iterator(dir_path), {})) + for (auto& entry : boost::make_iterator_range(boost::filesystem::directory_iterator(dir_path, ec), {})) { if (boost::filesystem::is_regular_file(entry, ec) && !ec.failed()) { From 6baaef4ee20b62b310ea738e416feeb417ed1792 Mon Sep 17 00:00:00 2001 From: Callum Prentice Date: Mon, 14 Jun 2021 11:10:22 -0700 Subject: [PATCH 158/443] Add in the JIRA (SL-15398) describing the contribution from FS:Ansariel to the contributions.txt file --- doc/contributions.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/contributions.txt b/doc/contributions.txt index 276d37836d..a29d4e6137 100755 --- a/doc/contributions.txt +++ b/doc/contributions.txt @@ -233,6 +233,7 @@ Ansariel Hiller SL-15200 SL-15226 SL-15227 + SL-15398 Aralara Rajal Arare Chantilly CHUIBUG-191 From 5b92d266df00c8d8b8a6353061b4a9672bfa97f5 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Mon, 14 Jun 2021 21:19:55 +0300 Subject: [PATCH 159/443] SL-15383 Crash at SearchableControl's setHighlighted --- indra/newview/llfloaterpreference.cpp | 43 ++++++++++++++++++++++----- indra/newview/llfloaterpreference.h | 2 ++ 2 files changed, 38 insertions(+), 7 deletions(-) diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp index 15ceb4067c..7676487587 100644 --- a/indra/newview/llfloaterpreference.cpp +++ b/indra/newview/llfloaterpreference.cpp @@ -263,7 +263,8 @@ LLFloaterPreference::LLFloaterPreference(const LLSD& key) mGotPersonalInfo(false), mOriginalIMViaEmail(false), mLanguageChanged(false), - mAvatarDataInitialized(false) + mAvatarDataInitialized(false), + mSearchDataDirty(true) { LLConversationLog::instance().addObserver(this); @@ -2150,6 +2151,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())); @@ -2906,10 +2912,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); @@ -2940,8 +2955,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(); } } @@ -3559,6 +3581,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 ) @@ -3656,4 +3684,5 @@ void LLFloaterPreference::collectSearchableItems() collectChildren( this, ll::prefs::PanelDataPtr(), pRootTabcontainer ); } + mSearchDataDirty = false; } diff --git a/indra/newview/llfloaterpreference.h b/indra/newview/llfloaterpreference.h index 1268935712..e9e19e9acb 100644 --- a/indra/newview/llfloaterpreference.h +++ b/indra/newview/llfloaterpreference.h @@ -108,6 +108,7 @@ public: void getControlNames(std::vector& names); // updates click/double-click action controls depending on values from settings.xml void updateClickActionViews(); + void updateSearchableItems(); protected: void onBtnOK(const LLSD& userdata); @@ -220,6 +221,7 @@ private: LLSearchEditor *mFilterEdit; std::unique_ptr< ll::prefs::SearchData > mSearchData; + bool mSearchDataDirty; void onUpdateFilterTerm( bool force = false ); void collectSearchableItems(); From 0914f5c48f777705bdc57188e7372707f7977e5a Mon Sep 17 00:00:00 2001 From: Mnikolenko Productengine Date: Tue, 15 Jun 2021 19:25:08 +0300 Subject: [PATCH 160/443] SL-15297 WIP Implement performance floater #2 --- indra/newview/CMakeLists.txt | 2 + indra/newview/llfloaterperformance.cpp | 36 +- indra/newview/llfloaterperformance.h | 5 + indra/newview/llfloaterpreference.cpp | 409 +-------------- indra/newview/llfloaterpreference.h | 31 +- .../llfloaterpreferencesgraphicsadvanced.cpp | 466 ++++++++++++++++++ .../llfloaterpreferencesgraphicsadvanced.h | 63 +++ indra/newview/llviewerfloaterreg.cpp | 1 + .../xui/en/panel_performance_nearby.xml | 3 - 9 files changed, 575 insertions(+), 441 deletions(-) create mode 100644 indra/newview/llfloaterpreferencesgraphicsadvanced.cpp create mode 100644 indra/newview/llfloaterpreferencesgraphicsadvanced.h diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index 1ec1e2cc24..888796015b 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -290,6 +290,7 @@ set(viewer_SOURCE_FILES llfloaterperms.cpp llfloaterpostprocess.cpp llfloaterpreference.cpp + llfloaterpreferencesgraphicsadvanced.cpp llfloaterpreferenceviewadvanced.cpp llfloaterpreviewtrash.cpp llfloaterproperties.cpp @@ -929,6 +930,7 @@ set(viewer_HEADER_FILES llfloaterperms.h llfloaterpostprocess.h llfloaterpreference.h + llfloaterpreferencesgraphicsadvanced.h llfloaterpreferenceviewadvanced.h llfloaterpreviewtrash.h llfloaterproperties.h diff --git a/indra/newview/llfloaterperformance.cpp b/indra/newview/llfloaterperformance.cpp index 8024d1539c..a44c3a262d 100644 --- a/indra/newview/llfloaterperformance.cpp +++ b/indra/newview/llfloaterperformance.cpp @@ -27,11 +27,15 @@ #include "llfloaterperformance.h" #include "llappearancemgr.h" +#include "llavataractions.h" #include "llavatarrendernotifier.h" #include "llfeaturemanager.h" #include "llfloaterreg.h" #include "llnamelistctrl.h" +#include "llfloaterpreference.h" // LLAvatarComplexityControls +#include "llsliderctrl.h" #include "lltextbox.h" +#include "lltrans.h" #include "llvoavatar.h" @@ -43,6 +47,7 @@ LLFloaterPerformance::LLFloaterPerformance(const LLSD& key) LLFloaterPerformance::~LLFloaterPerformance() { + mComplexityChangedSignal.disconnect(); } BOOL LLFloaterPerformance::postBuild() @@ -79,7 +84,11 @@ BOOL LLFloaterPerformance::postBuild() mNearbyPanel->getChild("exceptions_btn")->setCommitCallback(boost::bind(&LLFloaterPerformance::onClickExceptions, this)); mNearbyList = mNearbyPanel->getChild("nearby_list"); - + + updateComplexityText(); + mComplexityChangedSignal = gSavedSettings.getControl("IndirectMaxComplexity")->getCommitSignal()->connect(boost::bind(&LLFloaterPerformance::updateComplexityText, this)); + mNearbyPanel->getChild("IndirectMaxComplexity")->setCommitCallback(boost::bind(&LLFloaterPerformance::updateMaxComplexity, this)); + return TRUE; } @@ -151,6 +160,7 @@ void LLFloaterPerformance::populateHUDList() mHUDList->addElement(item); } + mHUDList->sortByColumnIndex(1, FALSE); mHUDsPanel->getChild("huds_value")->setValue(std::to_string(complexity_list.size())); } @@ -185,10 +195,19 @@ void LLFloaterPerformance::populateNearbyList() row[2]["value"] = avatar->getFullname(); row[2]["font"]["name"] = "SANSSERIF"; - mNearbyList->addElement(item); + LLScrollListItem* av_item = mNearbyList->addElement(item); + if(av_item && LLAvatarActions::isFriend(avatar->getID())) + { + LLScrollListText* name_text = dynamic_cast(av_item->getColumn(2)); + if (name_text) + { + name_text->setColor(LLUIColorTable::instance().getColor("ConversationFriendColor")); + } + } } char_iter++; } + mNearbyList->sortByColumnIndex(1, FALSE); } @@ -213,4 +232,17 @@ void LLFloaterPerformance::onClickExceptions() LLFloaterReg::showInstance("avatar_render_settings"); } +void LLFloaterPerformance::updateMaxComplexity() +{ + LLAvatarComplexityControls::updateMax( + mNearbyPanel->getChild("IndirectMaxComplexity"), + mNearbyPanel->getChild("IndirectMaxComplexityText")); +} + +void LLFloaterPerformance::updateComplexityText() +{ + LLAvatarComplexityControls::setText(gSavedSettings.getU32("RenderAvatarMaxComplexity"), + mNearbyPanel->getChild("IndirectMaxComplexityText", true)); +} + // EOF diff --git a/indra/newview/llfloaterperformance.h b/indra/newview/llfloaterperformance.h index a70a328d3a..0cba07f21e 100644 --- a/indra/newview/llfloaterperformance.h +++ b/indra/newview/llfloaterperformance.h @@ -52,6 +52,9 @@ private: void onClickRecommended(); void onClickExceptions(); + void updateMaxComplexity(); + void updateComplexityText(); + LLPanel* mMainPanel; LLPanel* mTroubleshootingPanel; LLPanel* mNearbyPanel; @@ -60,6 +63,8 @@ private: LLPanel* mPreferencesPanel; LLNameListCtrl* mHUDList; LLNameListCtrl* mNearbyList; + + boost::signals2::connection mComplexityChangedSignal; }; #endif // LL_LLFLOATERPERFORMANCE_H diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp index 6bf2136f60..1ab6621c4c 100644 --- a/indra/newview/llfloaterpreference.cpp +++ b/indra/newview/llfloaterpreference.cpp @@ -50,6 +50,7 @@ #include "llfloaterreg.h" #include "llfloaterabout.h" #include "llfavoritesbar.h" +#include "llfloaterpreferencesgraphicsadvanced.h" #include "llfloatersidepanelcontainer.h" #include "llfloaterimsession.h" #include "llkeyboard.h" @@ -74,7 +75,6 @@ #include "llviewereventrecorder.h" #include "llviewermessage.h" #include "llviewerwindow.h" -#include "llviewershadermgr.h" #include "llviewerthrottle.h" #include "llvoavatarself.h" #include "llvotree.h" @@ -98,11 +98,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" @@ -115,8 +113,6 @@ #include "llpresetsmanager.h" #include "llviewercontrol.h" #include "llpresetsmanager.h" -#include "llfeaturemanager.h" -#include "llviewertexturelist.h" #include "llsearchableui.h" @@ -751,33 +747,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(); @@ -1216,124 +1185,6 @@ void LLFloaterPreference::refreshEnabledState() getChildView("block_list")->setEnabled(LLLoginInstance::getInstance()->authSuccess()); } -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); - } - - // 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"); - 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() { @@ -1376,118 +1227,6 @@ void LLAvatarComplexityControls::setIndirectMaxArc() gSavedSettings.setU32("IndirectMaxComplexity", indirect_max_arc); } -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(); @@ -1503,32 +1242,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(); @@ -1742,63 +1455,6 @@ void LLFloaterPreference::refreshUI() refresh(); } -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) { // Called when the IndirectMaxComplexity control changes @@ -1891,22 +1547,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"); @@ -3310,18 +2950,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) @@ -3331,41 +2959,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() { } diff --git a/indra/newview/llfloaterpreference.h b/indra/newview/llfloaterpreference.h index 1268935712..f86104ed99 100644 --- a/indra/newview/llfloaterpreference.h +++ b/indra/newview/llfloaterpreference.h @@ -109,9 +109,10 @@ public: // updates click/double-click action controls depending on values from settings.xml void updateClickActionViews(); + void onBtnOK(const LLSD& userdata); + void onBtnCancel(const LLSD& userdata); + protected: - void onBtnOK(const LLSD& userdata); - void onBtnCancel(const LLSD& userdata); void onClickClearCache(); // Clear viewer texture cache, vfs, and VO cache on next startup void onClickBrowserClearCache(); // Clear web history and caches as well as viewer caches above @@ -347,32 +348,6 @@ 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: diff --git a/indra/newview/llfloaterpreferencesgraphicsadvanced.cpp b/indra/newview/llfloaterpreferencesgraphicsadvanced.cpp new file mode 100644 index 0000000000..404cdf5280 --- /dev/null +++ b/indra/newview/llfloaterpreferencesgraphicsadvanced.cpp @@ -0,0 +1,466 @@ +/** + * @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" + + +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() +{ +} + +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(); +} + +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")); + + LLFloaterPreference* floater_preferences = LLFloaterReg::findTypedInstance("preferences"); + if (floater_preferences) + { + LLAvatarComplexityControls::updateMax( + floater_preferences->getChild("IndirectMaxComplexity"), + floater_preferences->getChild("IndirectMaxComplexityText")); + } +} + +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); + } + + // 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"); + 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..3e9046eba9 --- /dev/null +++ b/indra/newview/llfloaterpreferencesgraphicsadvanced.h @@ -0,0 +1,63 @@ +/** + * @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 setMaxComplexityText(U32 value, LLTextBox* text_box); + 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); +}; + +#endif //LLFLOATERPREFERENCEGRAPHICSADVANCED_H + diff --git a/indra/newview/llviewerfloaterreg.cpp b/indra/newview/llviewerfloaterreg.cpp index eabdb67188..731a7e8ace 100644 --- a/indra/newview/llviewerfloaterreg.cpp +++ b/indra/newview/llviewerfloaterreg.cpp @@ -106,6 +106,7 @@ #include "llfloaterperms.h" #include "llfloaterpostprocess.h" #include "llfloaterpreference.h" +#include "llfloaterpreferencesgraphicsadvanced.h" #include "llfloaterpreferenceviewadvanced.h" #include "llfloaterpreviewtrash.h" #include "llfloaterproperties.h" diff --git a/indra/newview/skins/default/xui/en/panel_performance_nearby.xml b/indra/newview/skins/default/xui/en/panel_performance_nearby.xml index ade5f99451..d71b5334cd 100644 --- a/indra/newview/skins/default/xui/en/panel_performance_nearby.xml +++ b/indra/newview/skins/default/xui/en/panel_performance_nearby.xml @@ -83,9 +83,6 @@ show_text="false" top_pad="10" width="300"> - Date: Tue, 15 Jun 2021 22:15:41 +0300 Subject: [PATCH 161/443] SL-15403 Crash at LLFloaterTools's setStatusText On shutdown some floaters reset tools using LLToolMgr::setCurrentToolset and it updates LLFloaterTools, which might be dead by that point --- indra/newview/llmaniprotate.cpp | 5 ++++- indra/newview/llmanipscale.cpp | 5 ++++- indra/newview/llmaniptranslate.cpp | 5 ++++- 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/indra/newview/llmaniprotate.cpp b/indra/newview/llmaniprotate.cpp index c3e39429a2..7c942e8b53 100644 --- a/indra/newview/llmaniprotate.cpp +++ b/indra/newview/llmaniprotate.cpp @@ -105,7 +105,10 @@ void LLManipRotate::handleSelect() { // *FIX: put this in mouseDown? LLSelectMgr::getInstance()->saveSelectedObjectTransform(SELECT_ACTION_TYPE_PICK); - gFloaterTools->setStatusText("rotate"); + if (gFloaterTools) + { + gFloaterTools->setStatusText("rotate"); + } LLManip::handleSelect(); } diff --git a/indra/newview/llmanipscale.cpp b/indra/newview/llmanipscale.cpp index 9a8222d941..e74fd1241b 100644 --- a/indra/newview/llmanipscale.cpp +++ b/indra/newview/llmanipscale.cpp @@ -170,7 +170,10 @@ void LLManipScale::handleSelect() LLBBox bbox = LLSelectMgr::getInstance()->getBBoxOfSelection(); updateSnapGuides(bbox); LLSelectMgr::getInstance()->saveSelectedObjectTransform(SELECT_ACTION_TYPE_PICK); - gFloaterTools->setStatusText("scale"); + if (gFloaterTools) + { + gFloaterTools->setStatusText("scale"); + } LLManip::handleSelect(); } diff --git a/indra/newview/llmaniptranslate.cpp b/indra/newview/llmaniptranslate.cpp index 9248c160c6..8736d3b51f 100644 --- a/indra/newview/llmaniptranslate.cpp +++ b/indra/newview/llmaniptranslate.cpp @@ -287,7 +287,10 @@ LLManipTranslate::~LLManipTranslate() void LLManipTranslate::handleSelect() { LLSelectMgr::getInstance()->saveSelectedObjectTransform(SELECT_ACTION_TYPE_PICK); - gFloaterTools->setStatusText("move"); + if (gFloaterTools) + { + gFloaterTools->setStatusText("move"); + } LLManip::handleSelect(); } From ded1f85b2811a51c61b140be6862ba479c02b5a8 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Tue, 15 Jun 2021 22:43:28 +0300 Subject: [PATCH 162/443] SL-15404 Crash at setSeedCapability Viewer tried to set capability when quiting. --- indra/newview/llworld.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/indra/newview/llworld.cpp b/indra/newview/llworld.cpp index a1a1db35d6..fb3fc55a94 100644 --- a/indra/newview/llworld.cpp +++ b/indra/newview/llworld.cpp @@ -1194,6 +1194,11 @@ public: virtual void post(ResponsePtr response, const LLSD& context, const LLSD& input) const { + if (LLApp::isExiting()) + { + return; + } + if (!input["body"].has("agent-id") || !input["body"].has("sim-ip-and-port") || !input["body"].has("seed-capability")) From bc609f964b13141301aca9d29b9ceb5f9a541bf9 Mon Sep 17 00:00:00 2001 From: Mnikolenko Productengine Date: Thu, 17 Jun 2021 20:37:06 +0300 Subject: [PATCH 163/443] SL-15297 WIP Implement performance floater - updated UI --- indra/newview/llavatarrendernotifier.cpp | 16 +- indra/newview/llavatarrendernotifier.h | 26 + indra/newview/llfloaterperformance.cpp | 135 +++- indra/newview/llfloaterperformance.h | 11 +- indra/newview/llvoavatar.cpp | 33 +- indra/newview/llvoavatar.h | 3 +- .../default/textures/icons/green_dot.png | Bin 18614 -> 0 bytes .../skins/default/textures/textures.xml | 2 - .../default/xui/en/floater_performance.xml | 754 +++++++++--------- ...s.xml => panel_performance_complexity.xml} | 46 +- .../default/xui/en/panel_performance_huds.xml | 20 +- .../xui/en/panel_performance_nearby.xml | 25 +- .../xui/en/panel_performance_preferences.xml | 4 +- .../en/panel_performance_troubleshooting.xml | 4 +- 14 files changed, 609 insertions(+), 470 deletions(-) delete mode 100644 indra/newview/skins/default/textures/icons/green_dot.png rename indra/newview/skins/default/xui/en/{panel_performance_scripts.xml => panel_performance_complexity.xml} (62%) diff --git a/indra/newview/llavatarrendernotifier.cpp b/indra/newview/llavatarrendernotifier.cpp index 4fd57c7341..8b09f7903d 100644 --- a/indra/newview/llavatarrendernotifier.cpp +++ b/indra/newview/llavatarrendernotifier.cpp @@ -235,6 +235,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. @@ -282,7 +288,8 @@ static const char* e_hud_messages[] = }; LLHUDRenderNotifier::LLHUDRenderNotifier() : -mReportedHUDWarning(WARN_NONE) +mReportedHUDWarning(WARN_NONE), +mHUDsCount(0) { } @@ -299,7 +306,14 @@ void LLHUDRenderNotifier::updateNotificationHUD(hud_complexity_list_t complexity } 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 3fd7a32d84..37130bfcf6 100644 --- a/indra/newview/llavatarrendernotifier.h +++ b/indra/newview/llavatarrendernotifier.h @@ -63,6 +63,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 +96,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 +131,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 @@ -122,6 +146,7 @@ public: bool isNotificationVisible(); hud_complexity_list_t getHUDComplexityList() { return mHUDComplexityList; } + S32 getHUDsCount() { return mHUDsCount; } private: enum EWarnLevel @@ -144,6 +169,7 @@ private: LLHUDComplexity mLatestHUDComplexity; LLFrameTimer mHUDPopUpDelayTimer; hud_complexity_list_t mHUDComplexityList; + S32 mHUDsCount; }; #endif /* ! defined(LL_llavatarrendernotifier_H) */ diff --git a/indra/newview/llfloaterperformance.cpp b/indra/newview/llfloaterperformance.cpp index a44c3a262d..c96d3dac5e 100644 --- a/indra/newview/llfloaterperformance.cpp +++ b/indra/newview/llfloaterperformance.cpp @@ -37,17 +37,22 @@ #include "lltextbox.h" #include "lltrans.h" #include "llvoavatar.h" +#include "llvoavatarself.h" + +const F32 REFRESH_INTERVAL = 1.0f; +const S32 COMPLEXITY_THRESHOLD_1 = 100000; LLFloaterPerformance::LLFloaterPerformance(const LLSD& key) - : LLFloater(key) +: LLFloater(key), + mUpdateTimer(new LLTimer()) { - } LLFloaterPerformance::~LLFloaterPerformance() { mComplexityChangedSignal.disconnect(); + delete mUpdateTimer; } BOOL LLFloaterPerformance::postBuild() @@ -55,32 +60,34 @@ BOOL LLFloaterPerformance::postBuild() mMainPanel = getChild("panel_performance_main"); mTroubleshootingPanel = getChild("panel_performance_troubleshooting"); mNearbyPanel = getChild("panel_performance_nearby"); - mScriptsPanel = getChild("panel_performance_scripts"); - mPreferencesPanel = getChild("panel_performance_preferences"); + mComplexityPanel = getChild("panel_performance_complexity"); + mSettingsPanel = getChild("panel_performance_preferences"); mHUDsPanel = getChild("panel_performance_huds"); getChild("troubleshooting_subpanel")->setMouseDownCallback(boost::bind(&LLFloaterPerformance::showSelectedPanel, this, mTroubleshootingPanel)); getChild("nearby_subpanel")->setMouseDownCallback(boost::bind(&LLFloaterPerformance::showSelectedPanel, this, mNearbyPanel)); - getChild("scripts_subpanel")->setMouseDownCallback(boost::bind(&LLFloaterPerformance::showSelectedPanel, this, mScriptsPanel)); - getChild("preferences_subpanel")->setMouseDownCallback(boost::bind(&LLFloaterPerformance::showSelectedPanel, this, mPreferencesPanel)); + getChild("complexity_subpanel")->setMouseDownCallback(boost::bind(&LLFloaterPerformance::showSelectedPanel, this, mComplexityPanel)); + getChild("settings_subpanel")->setMouseDownCallback(boost::bind(&LLFloaterPerformance::showSelectedPanel, this, mSettingsPanel)); getChild("huds_subpanel")->setMouseDownCallback(boost::bind(&LLFloaterPerformance::showSelectedPanel, this, mHUDsPanel)); initBackBtn(mTroubleshootingPanel); initBackBtn(mNearbyPanel); - initBackBtn(mScriptsPanel); - initBackBtn(mPreferencesPanel); + initBackBtn(mComplexityPanel); + initBackBtn(mSettingsPanel); initBackBtn(mHUDsPanel); - - mHUDsPanel->getChild("refresh_list_btn")->setCommitCallback(boost::bind(&LLFloaterPerformance::populateHUDList, this)); - mHUDList = mHUDsPanel->getChild("hud_list"); mHUDList->setNameListType(LLNameListCtrl::SPECIAL); mHUDList->setHoverIconName("StopReload_Off"); mHUDList->setIconClickedCallback(boost::bind(&LLFloaterPerformance::detachItem, this, _1)); - mPreferencesPanel->getChild("advanced_btn")->setCommitCallback(boost::bind(&LLFloaterPerformance::onClickAdvanced, this)); - mPreferencesPanel->getChild("defaults_btn")->setCommitCallback(boost::bind(&LLFloaterPerformance::onClickRecommended, this)); + mObjectList = mComplexityPanel->getChild("obj_list"); + mObjectList->setNameListType(LLNameListCtrl::SPECIAL); + mObjectList->setHoverIconName("StopReload_Off"); + mObjectList->setIconClickedCallback(boost::bind(&LLFloaterPerformance::detachItem, this, _1)); + + mSettingsPanel->getChild("advanced_btn")->setCommitCallback(boost::bind(&LLFloaterPerformance::onClickAdvanced, this)); + mSettingsPanel->getChild("defaults_btn")->setCommitCallback(boost::bind(&LLFloaterPerformance::onClickRecommended, this)); mNearbyPanel->getChild("exceptions_btn")->setCommitCallback(boost::bind(&LLFloaterPerformance::onClickExceptions, this)); mNearbyList = mNearbyPanel->getChild("nearby_list"); @@ -89,6 +96,8 @@ BOOL LLFloaterPerformance::postBuild() mComplexityChangedSignal = gSavedSettings.getControl("IndirectMaxComplexity")->getCommitSignal()->connect(boost::bind(&LLFloaterPerformance::updateComplexityText, this)); mNearbyPanel->getChild("IndirectMaxComplexity")->setCommitCallback(boost::bind(&LLFloaterPerformance::updateMaxComplexity, this)); + LLAvatarComplexityControls::setIndirectMaxArc(); + return TRUE; } @@ -107,13 +116,43 @@ void LLFloaterPerformance::showSelectedPanel(LLPanel* selected_panel) } } +void LLFloaterPerformance::draw() +{ + if (mUpdateTimer->hasExpired()) + { + getChild("fps_value")->setValue((S32)llround(LLTrace::get_frame_recording().getPeriodMeanPerSec(LLStatViewer::FPS))); + if (mMainPanel->getVisible()) + { + mMainPanel->getChild("huds_value")->setValue(LLHUDRenderNotifier::getInstance()->getHUDsCount()); + mMainPanel->getChild("complexity_value")->setValue((S32)gAgentAvatarp->getVisualComplexity()); + updateNearbyComplexityDesc(); + } + else if (mHUDsPanel->getVisible()) + { + populateHUDList(); + } + else if (mNearbyPanel->getVisible()) + { + populateNearbyList(); + updateNearbyComplexityDesc(); + } + else if (mComplexityPanel->getVisible()) + { + populateObjectList(); + } + + mUpdateTimer->setTimerExpirySec(REFRESH_INTERVAL); + } + LLFloater::draw(); +} + void LLFloaterPerformance::showMainPanel() { mTroubleshootingPanel->setVisible(FALSE); mNearbyPanel->setVisible(FALSE); - mScriptsPanel->setVisible(FALSE); + mComplexityPanel->setVisible(FALSE); mHUDsPanel->setVisible(FALSE); - mPreferencesPanel->setVisible(FALSE); + mSettingsPanel->setVisible(FALSE); mMainPanel->setVisible(TRUE); } @@ -165,16 +204,55 @@ void LLFloaterPerformance::populateHUDList() mHUDsPanel->getChild("huds_value")->setValue(std::to_string(complexity_list.size())); } +void LLFloaterPerformance::populateObjectList() +{ + mObjectList->clearRows(); + mObjectList->updateColumns(true); + + object_complexity_list_t complexity_list = LLAvatarRenderNotifier::getInstance()->getObjectComplexityList(); + + object_complexity_list_t::iterator iter = complexity_list.begin(); + object_complexity_list_t::iterator end = complexity_list.end(); + + for (; iter != end; ++iter) + { + LLObjectComplexity object_complexity = *iter; + + LLSD item; + item["special_id"] = object_complexity.objectId; + item["target"] = LLNameListCtrl::SPECIAL; + LLSD& row = item["columns"]; + row[0]["column"] = "complex_visual"; + row[0]["type"] = "text"; + row[0]["value"] = "*"; + + row[1]["column"] = "complex_value"; + row[1]["type"] = "text"; + row[1]["value"] = std::to_string(object_complexity.objectCost); + row[1]["font"]["name"] = "SANSSERIF"; + + row[2]["column"] = "name"; + row[2]["type"] = "text"; + row[2]["value"] = object_complexity.objectName; + row[2]["font"]["name"] = "SANSSERIF"; + + mObjectList->addElement(item); + } + mObjectList->sortByColumnIndex(1, FALSE); +} + void LLFloaterPerformance::populateNearbyList() { mNearbyList->clearRows(); mNearbyList->updateColumns(true); + S32 avatars = 0; + 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 (avatar && !avatar->isDead() && !avatar->isControlAvatar() && !avatar->isSelf()) { avatar->calculateUpdateRenderComplexity(); @@ -204,17 +282,38 @@ void LLFloaterPerformance::populateNearbyList() name_text->setColor(LLUIColorTable::instance().getColor("ConversationFriendColor")); } } + avatars++; } char_iter++; } - mNearbyList->sortByColumnIndex(1, FALSE); + mNearbyList->sortByColumnIndex(1, FALSE); +} +void LLFloaterPerformance::updateNearbyComplexityDesc() +{ + S32 max_complexity = 0; + 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() && !avatar->isSelf()) + { + max_complexity = llmax(max_complexity, (S32)avatar->getVisualComplexity()); + } + char_iter++; + } + std::string desc = getString(max_complexity > COMPLEXITY_THRESHOLD_1 ? "very_high" : "medium"); + + if (mMainPanel->getVisible()) + { + mMainPanel->getChild("avatars_nearby_value")->setValue(desc); + } + mNearbyPanel->getChild("av_nearby_value")->setValue(desc); } void LLFloaterPerformance::detachItem(const LLUUID& item_id) { LLAppearanceMgr::instance().removeItemFromAvatar(item_id); - mHUDList->removeNameItem(item_id); } void LLFloaterPerformance::onClickRecommended() diff --git a/indra/newview/llfloaterperformance.h b/indra/newview/llfloaterperformance.h index 0cba07f21e..1facfe9225 100644 --- a/indra/newview/llfloaterperformance.h +++ b/indra/newview/llfloaterperformance.h @@ -37,6 +37,7 @@ public: virtual ~LLFloaterPerformance(); /*virtual*/ BOOL postBuild(); + /*virtual*/ void draw(); void showSelectedPanel(LLPanel* selected_panel); void showMainPanel(); @@ -46,6 +47,7 @@ public: private: void initBackBtn(LLPanel* panel); void populateHUDList(); + void populateObjectList(); void populateNearbyList(); void onClickAdvanced(); @@ -55,15 +57,20 @@ private: void updateMaxComplexity(); void updateComplexityText(); + void updateNearbyComplexityDesc(); + LLPanel* mMainPanel; LLPanel* mTroubleshootingPanel; LLPanel* mNearbyPanel; - LLPanel* mScriptsPanel; + LLPanel* mComplexityPanel; LLPanel* mHUDsPanel; - LLPanel* mPreferencesPanel; + LLPanel* mSettingsPanel; LLNameListCtrl* mHUDList; + LLNameListCtrl* mObjectList; LLNameListCtrl* mNearbyList; + LLTimer* mUpdateTimer; + boost::signals2::connection mComplexityChangedSignal; }; diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp index f69b9b3861..ab7e5f7f8a 100644 --- a/indra/newview/llvoavatar.cpp +++ b/indra/newview/llvoavatar.cpp @@ -10533,7 +10533,8 @@ void LLVOAvatar::accountRenderComplexityForObject( const F32 max_attachment_complexity, LLVOVolume::texture_cost_t& textures, U32& cost, - hud_complexity_list_t& hud_complexity_list) + hud_complexity_list_t& hud_complexity_list, + object_complexity_list_t& object_complexity_list) { if (attached_object && !attached_object->isHUDAttachment()) { @@ -10552,12 +10553,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(); @@ -10590,6 +10591,15 @@ void LLVOAvatar::accountRenderComplexityForObject( << LL_ENDL; // 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); + } } } } @@ -10676,6 +10686,7 @@ 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; for (U8 baked_index = 0; baked_index < BAKED_NUM_INDICES; baked_index++) { @@ -10706,7 +10717,7 @@ void LLVOAvatar::calculateUpdateRenderComplexity() if (volp && !volp->isAttachment()) { accountRenderComplexityForObject(volp, max_attachment_complexity, - textures, cost, hud_complexity_list); + textures, cost, hud_complexity_list, object_complexity_list); } } @@ -10722,7 +10733,7 @@ void LLVOAvatar::calculateUpdateRenderComplexity() { const LLViewerObject* attached_object = attachment_iter->get(); accountRenderComplexityForObject(attached_object, max_attachment_complexity, - textures, cost, hud_complexity_list); + textures, cost, hud_complexity_list, object_complexity_list); } } @@ -10782,13 +10793,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); } diff --git a/indra/newview/llvoavatar.h b/indra/newview/llvoavatar.h index 74ef589ca4..f83f9d4eaf 100644 --- a/indra/newview/llvoavatar.h +++ b/indra/newview/llvoavatar.h @@ -299,7 +299,8 @@ public: const F32 max_attachment_complexity, LLVOVolume::texture_cost_t& textures, U32& cost, - hud_complexity_list_t& hud_complexity_list); + hud_complexity_list_t& hud_complexity_list, + object_complexity_list_t& object_complexity_list); void calculateUpdateRenderComplexity(); static const U32 VISUAL_COMPLEXITY_UNKNOWN; void updateVisualComplexity(); diff --git a/indra/newview/skins/default/textures/icons/green_dot.png b/indra/newview/skins/default/textures/icons/green_dot.png deleted file mode 100644 index 02c07810c2a850129e7afae4a88c0b7160380ceb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 18614 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 - - diff --git a/indra/newview/skins/default/xui/en/floater_performance.xml b/indra/newview/skins/default/xui/en/floater_performance.xml index 42269ba34a..09af364266 100644 --- a/indra/newview/skins/default/xui/en/floater_performance.xml +++ b/indra/newview/skins/default/xui/en/floater_performance.xml @@ -1,409 +1,387 @@ + + + + + 75 + + + FPS -- 60 or more for the best experience + + + + - + - Current FPS - - + + Quick settings for common situations + + + Choose settings for parties, exploration, photography, and more. + + + + - 75.2 - - - - - - - - Client: - - - Network: - - - Server: - - - Normal - - - Normal - - - Normal - - - + + Individual settings + + + More control over quality, visibility distance, and enhancements. + + + + - General troubleshooting - - + + Nearby avatar complexity is + + + very high + + + Choose which avatars are not displayed in detail, to increase FPS. + + + + - Choose among common problems and see what you can do. - - + top_pad="20"> + + Your avatar complexity is + + + 275 + + + Reduce the complexity of your avatar if you aren't satisfied with current FPS. + + + + + + Your current HUDs: + + + 7 + + + Removing HUDs you are not using can improve speed. + + + + + + General troubleshooting + + + Choose among common problems and see what you can do. + + + - - - Avatars nearby: - - - 42 (very high) - - - Click to review avatars and choose a complexity limit. - - - - - - This location is - - - very complex - - - Try changing graphics quality or draw distance. - - - - - - Your avatar: - - - 12 scripts - - - Removing high-impact attachments may improve graphics speed. - - - - - - Your HUDs: - - - 7 - - - Removing HUDs you are not using can improve graphics speed. - - - - + top="55" /> + top="55" /> + top="55" /> + top="55" /> + top="55" /> diff --git a/indra/newview/skins/default/xui/en/panel_performance_scripts.xml b/indra/newview/skins/default/xui/en/panel_performance_complexity.xml similarity index 62% rename from indra/newview/skins/default/xui/en/panel_performance_scripts.xml rename to indra/newview/skins/default/xui/en/panel_performance_complexity.xml index e6dc4a217d..8d4512c4f7 100644 --- a/indra/newview/skins/default/xui/en/panel_performance_scripts.xml +++ b/indra/newview/skins/default/xui/en/panel_performance_complexity.xml @@ -4,7 +4,7 @@ follows="left|top" height="490" width="580" - name="panel_performance_scripts" + name="panel_performance_complexity" layout="topleft" left="0" top="0"> @@ -15,7 +15,7 @@ mouse_opaque="true" follows="left|top" name="back_btn" - top="10" + top="7" image_selected="Arrow_Left_Off" image_pressed="Arrow_Left_Off" image_unselected="Arrow_Left_Off" @@ -27,7 +27,7 @@ height="20" layout="topleft" left_pad="3" - top="13" + top="10" name="back_lbl" width="40"> Back @@ -35,25 +35,14 @@ - Avatar attachment scripts: - - - 12 + My avatar complexity - These attachments contain scripts (embedded apps) that use memory. + Complex attachments require more time and memory to display. - If there are any you don't need, detaching them may improve graphics speed. + While you are in this location, removing the most complex ones may increase speed. + + + + + diff --git a/indra/newview/skins/default/xui/en/panel_performance_huds.xml b/indra/newview/skins/default/xui/en/panel_performance_huds.xml index c881fadbe8..96bdf2412f 100644 --- a/indra/newview/skins/default/xui/en/panel_performance_huds.xml +++ b/indra/newview/skins/default/xui/en/panel_performance_huds.xml @@ -15,7 +15,7 @@ mouse_opaque="true" follows="left|top" name="back_btn" - top="10" + top="7" image_selected="Arrow_Left_Off" image_pressed="Arrow_Left_Off" image_unselected="Arrow_Left_Off" @@ -27,7 +27,7 @@ height="20" layout="topleft" left_pad="3" - top="13" + top="10" name="back_lbl" width="40"> Back @@ -35,14 +35,14 @@ - HUDs displayed: + width="135"> + Your current HUDs: - If there are any you don't need, detaching them may improve graphics speed. + Detaching HUDs you aren't using us always a good idea, but especially in a complex location. - - + + Back + + + Quick settings + + + Note: Quick settings will reset all manual changes you have made. + + + + + Tuned for many avatars in a room. + + + Nearby avatar complexity is high. + + + [secondlife:/// Choose avatars to show and hide] + + + + + Fewer avatars, higher visibility distance. + + + + + Good for zooming your camera far out and viewing large land areas. + + + + + Maximum quality, minimum visibility distance. + + + + For more control, try + + + [secondlife:/// Idividual Settings] + + + From f33605f8b113f1fed84564c7618630acd5c9427a Mon Sep 17 00:00:00 2001 From: Mnikolenko Productengine Date: Thu, 24 Jun 2021 16:17:04 +0300 Subject: [PATCH 165/443] SL-15297 WIP Implement performance floater - implement complexity bars --- indra/llui/llscrolllistcell.cpp | 73 +++++++++++ indra/llui/llscrolllistcell.h | 21 ++++ indra/newview/llfloaterperformance.cpp | 118 ++++++++++++++---- indra/newview/llfloaterperformance.h | 4 + .../default/xui/en/floater_performance.xml | 3 + 5 files changed, 195 insertions(+), 24 deletions(-) diff --git a/indra/llui/llscrolllistcell.cpp b/indra/llui/llscrolllistcell.cpp index 13839da400..50f0f5f820 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() == "image") + { + cell = new LLScrollListBar(cell_p); + } else // default is "text" { cell = new LLScrollListText(cell_p); @@ -165,6 +169,75 @@ 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_line_2d(left, mBottom, getWidth() - mRightPad, mBottom, mColor); + gl_line_2d(left, mBottom - 1, getWidth() - mRightPad, mBottom - 1, mColor); +} + // // LLScrollListText // diff --git a/indra/llui/llscrolllistcell.h b/indra/llui/llscrolllistcell.h index 19576fb247..26a272b270 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; @@ -192,6 +193,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/newview/llfloaterperformance.cpp b/indra/newview/llfloaterperformance.cpp index 424ca04b1f..beeebcb202 100644 --- a/indra/newview/llfloaterperformance.cpp +++ b/indra/newview/llfloaterperformance.cpp @@ -26,13 +26,15 @@ #include "llviewerprecompiledheaders.h" #include "llfloaterperformance.h" +#include "llagent.h" +#include "llagentcamera.h" #include "llappearancemgr.h" #include "llavataractions.h" #include "llavatarrendernotifier.h" #include "llfeaturemanager.h" +#include "llfloaterpreference.h" // LLAvatarComplexityControls #include "llfloaterreg.h" #include "llnamelistctrl.h" -#include "llfloaterpreference.h" // LLAvatarComplexityControls #include "llsliderctrl.h" #include "lltextbox.h" #include "lltrans.h" @@ -40,12 +42,16 @@ #include "llvoavatarself.h" const F32 REFRESH_INTERVAL = 1.0f; -const S32 COMPLEXITY_THRESHOLD_1 = 100000; - +const S32 COMPLEXITY_THRESHOLD_HIGH = 100000; +const S32 COMPLEXITY_THRESHOLD_MEDIUM = 30000; +const S32 BAR_LEFT_PAD = 2; +const S32 BAR_RIGHT_PAD = 5; +const S32 BAR_BOTTOM_PAD = 9; LLFloaterPerformance::LLFloaterPerformance(const LLSD& key) : LLFloater(key), - mUpdateTimer(new LLTimer()) + mUpdateTimer(new LLTimer()), + mNearbyMaxComplexity(0) { } @@ -120,6 +126,10 @@ void LLFloaterPerformance::showSelectedPanel(LLPanel* selected_panel) { populateNearbyList(); } + else if (mComplexityPanel == selected_panel) + { + populateObjectList(); + } } void LLFloaterPerformance::draw() @@ -179,6 +189,7 @@ void LLFloaterPerformance::initBackBtn(LLPanel* panel) void LLFloaterPerformance::populateHUDList() { + S32 prev_pos = mHUDList->getScrollPos(); mHUDList->clearRows(); mHUDList->updateColumns(true); @@ -186,8 +197,14 @@ void LLFloaterPerformance::populateHUDList() 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); + } + + for (iter = complexity_list.begin(); iter != end; ++iter) { LLHUDComplexity hud_object_complexity = *iter; @@ -196,8 +213,12 @@ void LLFloaterPerformance::populateHUDList() item["target"] = LLNameListCtrl::SPECIAL; LLSD& row = item["columns"]; row[0]["column"] = "complex_visual"; - row[0]["type"] = "text"; - row[0]["value"] = "*"; + row[0]["type"] = "image"; + LLSD& value = row[0]["value"]; + value["ratio"] = (F32)hud_object_complexity.objectsCost / max_complexity; + value["bottom"] = BAR_BOTTOM_PAD; + value["left_pad"] = BAR_LEFT_PAD; + value["right_pad"] = BAR_RIGHT_PAD; row[1]["column"] = "complex_value"; row[1]["type"] = "text"; @@ -212,12 +233,14 @@ void LLFloaterPerformance::populateHUDList() mHUDList->addElement(item); } mHUDList->sortByColumnIndex(1, FALSE); + mHUDList->setScrollPos(prev_pos); mHUDsPanel->getChild("huds_value")->setValue(std::to_string(complexity_list.size())); } void LLFloaterPerformance::populateObjectList() { + S32 prev_pos = mObjectList->getScrollPos(); mObjectList->clearRows(); mObjectList->updateColumns(true); @@ -226,7 +249,13 @@ void LLFloaterPerformance::populateObjectList() object_complexity_list_t::iterator iter = complexity_list.begin(); object_complexity_list_t::iterator end = complexity_list.end(); + U32 max_complexity = 0; for (; iter != end; ++iter) + { + max_complexity = llmax(max_complexity, (*iter).objectCost); + } + + for (iter = complexity_list.begin(); iter != end; ++iter) { LLObjectComplexity object_complexity = *iter; @@ -235,8 +264,12 @@ void LLFloaterPerformance::populateObjectList() item["target"] = LLNameListCtrl::SPECIAL; LLSD& row = item["columns"]; row[0]["column"] = "complex_visual"; - row[0]["type"] = "text"; - row[0]["value"] = "*"; + row[0]["type"] = "image"; + LLSD& value = row[0]["value"]; + value["ratio"] = (F32)object_complexity.objectCost / max_complexity; + value["bottom"] = BAR_BOTTOM_PAD; + value["left_pad"] = BAR_LEFT_PAD; + value["right_pad"] = BAR_RIGHT_PAD; row[1]["column"] = "complex_value"; row[1]["type"] = "text"; @@ -251,30 +284,35 @@ void LLFloaterPerformance::populateObjectList() mObjectList->addElement(item); } mObjectList->sortByColumnIndex(1, FALSE); + mObjectList->setScrollPos(prev_pos); } void LLFloaterPerformance::populateNearbyList() { + S32 prev_pos = mNearbyList->getScrollPos(); mNearbyList->clearRows(); mNearbyList->updateColumns(true); - S32 avatars = 0; static LLCachedControl max_render_cost(gSavedSettings, "RenderAvatarMaxComplexity", 0); + std::vector valid_nearby_avs; + getNearbyAvatars(valid_nearby_avs); - std::vector::iterator char_iter = LLCharacter::sInstances.begin(); - while (char_iter != LLCharacter::sInstances.end()) + std::vector::iterator char_iter = valid_nearby_avs.begin(); + while (char_iter != valid_nearby_avs.end()) { LLVOAvatar* avatar = dynamic_cast(*char_iter); - if (avatar && !avatar->isDead() && !avatar->isControlAvatar() && !avatar->isSelf()) + if (avatar) { - avatar->calculateUpdateRenderComplexity(); - LLSD item; item["id"] = avatar->getID(); LLSD& row = item["columns"]; row[0]["column"] = "complex_visual"; - row[0]["type"] = "text"; - row[0]["value"] = "*"; + row[0]["type"] = "image"; + LLSD& value = row[0]["value"]; + value["ratio"] = (F32)avatar->getVisualComplexity() / mNearbyMaxComplexity; + value["bottom"] = BAR_BOTTOM_PAD; + value["left_pad"] = BAR_LEFT_PAD; + value["right_pad"] = BAR_RIGHT_PAD; row[1]["column"] = "complex_value"; row[1]["type"] = "text"; @@ -296,6 +334,11 @@ void LLFloaterPerformance::populateNearbyList() if (avatar->getVisualComplexity() > max_render_cost) { color = "LabelDisabledColor"; + LLScrollListBar* bar = dynamic_cast(av_item->getColumn(0)); + if (bar) + { + bar->setColor(LLUIColorTable::instance().getColor(color)); + } } else if (LLAvatarActions::isFriend(avatar->getID())) { @@ -304,28 +347,55 @@ void LLFloaterPerformance::populateNearbyList() name_text->setColor(LLUIColorTable::instance().getColor(color)); } } - avatars++; } char_iter++; } - mNearbyList->sortByColumnIndex(1, FALSE); + mNearbyList->sortByColumnIndex(1, FALSE); + mNearbyList->setScrollPos(prev_pos); } -void LLFloaterPerformance::updateNearbyComplexityDesc() +void LLFloaterPerformance::getNearbyAvatars(std::vector &valid_nearby_avs) { - static LLCachedControl max_render_cost(gSavedSettings, "RenderAvatarMaxComplexity", 0); - S32 max_complexity = 0; + static LLCachedControl render_far_clip(gSavedSettings, "RenderFarClip", 64); + 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() && !avatar->isSelf()) { - max_complexity = llmax(max_complexity, (S32)avatar->getVisualComplexity()); + 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++; } - std::string desc = getString(max_complexity > llmin((S32)max_render_cost, COMPLEXITY_THRESHOLD_1) ? "very_high" : "medium"); +} + +void LLFloaterPerformance::updateNearbyComplexityDesc() +{ + std::string desc = getString("low"); + + static LLCachedControl max_render_cost(gSavedSettings, "RenderAvatarMaxComplexity", 0); + if (mMainPanel->getVisible()) + { + std::vector valid_nearby_avs; + getNearbyAvatars(valid_nearby_avs); + } + if (mNearbyMaxComplexity > COMPLEXITY_THRESHOLD_HIGH) + { + desc = getString("very_high"); + } + else if (mNearbyMaxComplexity > COMPLEXITY_THRESHOLD_MEDIUM) + { + desc = getString("medium"); + } if (mMainPanel->getVisible()) { diff --git a/indra/newview/llfloaterperformance.h b/indra/newview/llfloaterperformance.h index 7aec7c3f6c..ea15873b95 100644 --- a/indra/newview/llfloaterperformance.h +++ b/indra/newview/llfloaterperformance.h @@ -28,6 +28,7 @@ #include "llfloater.h" +class LLCharacter; class LLNameListCtrl; class LLFloaterPerformance : public LLFloater @@ -57,6 +58,7 @@ private: void updateMaxComplexity(); void updateComplexityText(); + void getNearbyAvatars(std::vector &valid_nearby_avs); void updateNearbyComplexityDesc(); LLPanel* mMainPanel; @@ -72,6 +74,8 @@ private: LLTimer* mUpdateTimer; + S32 mNearbyMaxComplexity; + boost::signals2::connection mComplexityChangedSignal; }; diff --git a/indra/newview/skins/default/xui/en/floater_performance.xml b/indra/newview/skins/default/xui/en/floater_performance.xml index e415ac5be0..4cd3c7a603 100644 --- a/indra/newview/skins/default/xui/en/floater_performance.xml +++ b/indra/newview/skins/default/xui/en/floater_performance.xml @@ -12,6 +12,9 @@ + Date: Fri, 25 Jun 2021 20:05:07 +0300 Subject: [PATCH 166/443] SL-15297 WIP restore selection after updating the list & don't show avatars in the list as disabled when complexity is not limited --- indra/llui/llscrolllistcell.cpp | 2 +- indra/newview/llfloaterperformance.cpp | 14 +++++++--- indra/newview/llnamelistctrl.cpp | 28 +++++++++++++++++++ indra/newview/llnamelistctrl.h | 3 ++ indra/newview/skins/default/colors.xml | 5 +--- .../xui/en/floater_add_payment_method.xml | 2 +- .../default/xui/en/floater_performance.xml | 12 ++++---- 7 files changed, 50 insertions(+), 16 deletions(-) diff --git a/indra/llui/llscrolllistcell.cpp b/indra/llui/llscrolllistcell.cpp index 50f0f5f820..c5f53823f3 100644 --- a/indra/llui/llscrolllistcell.cpp +++ b/indra/llui/llscrolllistcell.cpp @@ -54,7 +54,7 @@ LLScrollListCell* LLScrollListCell::create(const LLScrollListCell::Params& cell_ { cell = new LLScrollListIconText(cell_p); } - else if (cell_p.type() == "image") + else if (cell_p.type() == "bar") { cell = new LLScrollListBar(cell_p); } diff --git a/indra/newview/llfloaterperformance.cpp b/indra/newview/llfloaterperformance.cpp index beeebcb202..b8adf7fedc 100644 --- a/indra/newview/llfloaterperformance.cpp +++ b/indra/newview/llfloaterperformance.cpp @@ -190,6 +190,7 @@ void LLFloaterPerformance::initBackBtn(LLPanel* panel) void LLFloaterPerformance::populateHUDList() { S32 prev_pos = mHUDList->getScrollPos(); + LLUUID prev_selected_id = mHUDList->getSelectedSpecialId(); mHUDList->clearRows(); mHUDList->updateColumns(true); @@ -213,7 +214,7 @@ void LLFloaterPerformance::populateHUDList() item["target"] = LLNameListCtrl::SPECIAL; LLSD& row = item["columns"]; row[0]["column"] = "complex_visual"; - row[0]["type"] = "image"; + row[0]["type"] = "bar"; LLSD& value = row[0]["value"]; value["ratio"] = (F32)hud_object_complexity.objectsCost / max_complexity; value["bottom"] = BAR_BOTTOM_PAD; @@ -234,6 +235,7 @@ void LLFloaterPerformance::populateHUDList() } mHUDList->sortByColumnIndex(1, FALSE); mHUDList->setScrollPos(prev_pos); + mHUDList->selectItemBySpecialId(prev_selected_id); mHUDsPanel->getChild("huds_value")->setValue(std::to_string(complexity_list.size())); } @@ -241,6 +243,7 @@ void LLFloaterPerformance::populateHUDList() void LLFloaterPerformance::populateObjectList() { S32 prev_pos = mObjectList->getScrollPos(); + LLUUID prev_selected_id = mObjectList->getSelectedSpecialId(); mObjectList->clearRows(); mObjectList->updateColumns(true); @@ -264,7 +267,7 @@ void LLFloaterPerformance::populateObjectList() item["target"] = LLNameListCtrl::SPECIAL; LLSD& row = item["columns"]; row[0]["column"] = "complex_visual"; - row[0]["type"] = "image"; + row[0]["type"] = "bar"; LLSD& value = row[0]["value"]; value["ratio"] = (F32)object_complexity.objectCost / max_complexity; value["bottom"] = BAR_BOTTOM_PAD; @@ -285,11 +288,13 @@ void LLFloaterPerformance::populateObjectList() } mObjectList->sortByColumnIndex(1, FALSE); mObjectList->setScrollPos(prev_pos); + mObjectList->selectItemBySpecialId(prev_selected_id); } void LLFloaterPerformance::populateNearbyList() { S32 prev_pos = mNearbyList->getScrollPos(); + LLUUID prev_selected_id = mNearbyList->getStringUUIDSelectedItem(); mNearbyList->clearRows(); mNearbyList->updateColumns(true); @@ -307,7 +312,7 @@ void LLFloaterPerformance::populateNearbyList() item["id"] = avatar->getID(); LLSD& row = item["columns"]; row[0]["column"] = "complex_visual"; - row[0]["type"] = "image"; + row[0]["type"] = "bar"; LLSD& value = row[0]["value"]; value["ratio"] = (F32)avatar->getVisualComplexity() / mNearbyMaxComplexity; value["bottom"] = BAR_BOTTOM_PAD; @@ -331,7 +336,7 @@ void LLFloaterPerformance::populateNearbyList() if (name_text) { std::string color = "white"; - if (avatar->getVisualComplexity() > max_render_cost) + if ((max_render_cost != 0) && (avatar->getVisualComplexity() > max_render_cost)) { color = "LabelDisabledColor"; LLScrollListBar* bar = dynamic_cast(av_item->getColumn(0)); @@ -352,6 +357,7 @@ void LLFloaterPerformance::populateNearbyList() } mNearbyList->sortByColumnIndex(1, FALSE); mNearbyList->setScrollPos(prev_pos); + mNearbyList->selectByID(prev_selected_id); } void LLFloaterPerformance::getNearbyAvatars(std::vector &valid_nearby_avs) diff --git a/indra/newview/llnamelistctrl.cpp b/indra/newview/llnamelistctrl.cpp index e1bf9b1a17..92805e03f0 100644 --- a/indra/newview/llnamelistctrl.cpp +++ b/indra/newview/llnamelistctrl.cpp @@ -464,6 +464,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 1a31b1cc10..d7e991c94d 100644 --- a/indra/newview/llnamelistctrl.h +++ b/indra/newview/llnamelistctrl.h @@ -162,6 +162,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, diff --git a/indra/newview/skins/default/colors.xml b/indra/newview/skins/default/colors.xml index 9fcb6edca4..e8d3c12d39 100644 --- a/indra/newview/skins/default/colors.xml +++ b/indra/newview/skins/default/colors.xml @@ -967,10 +967,7 @@ name="OutfitGalleryItemUnselected" value="0.4 0.4 0.4 1" /> - Date: Fri, 25 Jun 2021 22:13:56 +0300 Subject: [PATCH 167/443] SL-15458 Avatars who are moderators appear twice in popped-out IM session floater --- indra/newview/llfloaterimsessiontab.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/indra/newview/llfloaterimsessiontab.cpp b/indra/newview/llfloaterimsessiontab.cpp index 7541bb5efe..441979389e 100644 --- a/indra/newview/llfloaterimsessiontab.cpp +++ b/indra/newview/llfloaterimsessiontab.cpp @@ -518,9 +518,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 { From 54ffa6a23d093af8932f8978d3c1a420153f7997 Mon Sep 17 00:00:00 2001 From: Mnikolenko Productengine Date: Tue, 29 Jun 2021 18:34:18 +0300 Subject: [PATCH 168/443] SL-15297 WIP update Individual settings panel & correctly show avatar state in the list --- indra/newview/llfloaterperformance.cpp | 8 +- .../xui/en/panel_performance_preferences.xml | 144 +++++++++++++++--- 2 files changed, 131 insertions(+), 21 deletions(-) diff --git a/indra/newview/llfloaterperformance.cpp b/indra/newview/llfloaterperformance.cpp index b8adf7fedc..16afeb6e52 100644 --- a/indra/newview/llfloaterperformance.cpp +++ b/indra/newview/llfloaterperformance.cpp @@ -306,7 +306,7 @@ void LLFloaterPerformance::populateNearbyList() while (char_iter != valid_nearby_avs.end()) { LLVOAvatar* avatar = dynamic_cast(*char_iter); - if (avatar) + if (avatar && (LLVOAvatar::AOA_INVISIBLE != avatar->getOverallAppearance())) { LLSD item; item["id"] = avatar->getID(); @@ -336,7 +336,7 @@ void LLFloaterPerformance::populateNearbyList() if (name_text) { std::string color = "white"; - if ((max_render_cost != 0) && (avatar->getVisualComplexity() > max_render_cost)) + if (LLVOAvatar::AOA_JELLYDOLL == avatar->getOverallAppearance()) { color = "LabelDisabledColor"; LLScrollListBar* bar = dynamic_cast(av_item->getColumn(0)); @@ -345,9 +345,9 @@ void LLFloaterPerformance::populateNearbyList() bar->setColor(LLUIColorTable::instance().getColor(color)); } } - else if (LLAvatarActions::isFriend(avatar->getID())) + else if (LLVOAvatar::AOA_NORMAL == avatar->getOverallAppearance()) { - color = "ConversationFriendColor"; + color = LLAvatarActions::isFriend(avatar->getID()) ? "ConversationFriendColor" : "white"; } name_text->setColor(LLUIColorTable::instance().getColor(color)); } diff --git a/indra/newview/skins/default/xui/en/panel_performance_preferences.xml b/indra/newview/skins/default/xui/en/panel_performance_preferences.xml index ec1b624f13..b5cc2a29ed 100644 --- a/indra/newview/skins/default/xui/en/panel_performance_preferences.xml +++ b/indra/newview/skins/default/xui/en/panel_performance_preferences.xml @@ -2,7 +2,7 @@ Graphics quality @@ -74,21 +74,60 @@ shortcuts width="40"> Fastest - - + + + + + + + + + + + 1 + + + 2 + + + 3 + + + 4 + + + 5 + + + 6 + + + 7 + From f9a6e31c763a32215819291bd21e792e03fb95dc Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Tue, 29 Jun 2021 16:51:28 -0400 Subject: [PATCH 169/443] SL-15500: A couple further tweaks to satisfy commit policy checker. --- indra/edit-me-to-trigger-new-build.txt | 2 +- indra/newview/llfloatercreatelandmark.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) 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/newview/llfloatercreatelandmark.cpp b/indra/newview/llfloatercreatelandmark.cpp index eb93a6a75a..6b1d9306fb 100644 --- a/indra/newview/llfloatercreatelandmark.cpp +++ b/indra/newview/llfloatercreatelandmark.cpp @@ -320,4 +320,4 @@ void LLFloaterCreateLandmark::setItem(const uuid_set_t& items) } } } -} \ No newline at end of file +} From ab185263fa43141ff325edb8dace25f99e685c3d Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Tue, 29 Jun 2021 17:45:13 -0400 Subject: [PATCH 170/443] SL-15500: Install git-hooks (and requirements) and run policy check on the entire current (branch of the) viewer repo before starting any build. --- BuildParams | 2 +- build.sh | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/BuildParams b/BuildParams index c5f96d5ee3..27ae40767a 100755 --- 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/build.sh b/build.sh index 3b0cf97731..e059af4ded 100755 --- a/build.sh +++ b/build.sh @@ -280,6 +280,12 @@ python_cmd "$helpers/codeticket.py" addinput "Viewer Channel" "${viewer_channel} initialize_version # provided by buildscripts build.sh; sets version id +# install the git-hooks dependencies +pip_install -r "$git_hooks_checkout/requirements.txt" +# validate the branch we're about to build +python_cmd "$git_hooks_checkout/coding_policy_git.py" --all_files || \ + fatal "coding policy check failed" + # Now run the build succeeded=true last_built_variant= From 0276a325695f513df045ca5ffd97df478b23a95d Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Tue, 29 Jun 2021 18:04:03 -0400 Subject: [PATCH 171/443] SL-15500: Use plain pip install, not pip_install shell function. pip_install doesn't know about the '-r requirements.txt' feature. --- build.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/build.sh b/build.sh index e059af4ded..24090dd747 100755 --- a/build.sh +++ b/build.sh @@ -281,7 +281,8 @@ python_cmd "$helpers/codeticket.py" addinput "Viewer Channel" "${viewer_channel} initialize_version # provided by buildscripts build.sh; sets version id # install the git-hooks dependencies -pip_install -r "$git_hooks_checkout/requirements.txt" +pip install -r "$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" From d2de2f9d252be32b262b929fe7565729417d789b Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Wed, 30 Jun 2021 08:11:30 -0400 Subject: [PATCH 172/443] SL-15500: Always have to work around Windows path incompatibilities. --- build.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.sh b/build.sh index 24090dd747..64aa402fae 100755 --- a/build.sh +++ b/build.sh @@ -281,7 +281,7 @@ python_cmd "$helpers/codeticket.py" addinput "Viewer Channel" "${viewer_channel} initialize_version # provided by buildscripts build.sh; sets version id # install the git-hooks dependencies -pip install -r "$git_hooks_checkout/requirements.txt" || \ +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 || \ From 6460b7ac419021ca998c5f849ad382423599fc58 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Wed, 30 Jun 2021 09:48:02 -0400 Subject: [PATCH 173/443] SL-15500: Only run coding_policy_git.py on Mac since it fails on Windows due to some problem in the underlying library. Also wrap the coding policy checks in a TC log subsection. --- build.sh | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/build.sh b/build.sh index 64aa402fae..961d1df30d 100755 --- a/build.sh +++ b/build.sh @@ -280,12 +280,21 @@ python_cmd "$helpers/codeticket.py" addinput "Viewer Channel" "${viewer_channel} initialize_version # provided by buildscripts build.sh; sets version id -# 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" +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 From b15f30a9ce6f7ac7057a9daf7a4072426baf25d9 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Wed, 30 Jun 2021 17:34:30 +0300 Subject: [PATCH 174/443] SL-15501 Viewer crash with unprotected use of std::vector::front() --- indra/newview/llappearancemgr.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/indra/newview/llappearancemgr.cpp b/indra/newview/llappearancemgr.cpp index 31b5cf9aaa..fd712ea5d0 100644 --- a/indra/newview/llappearancemgr.cpp +++ b/indra/newview/llappearancemgr.cpp @@ -4267,6 +4267,17 @@ public: } virtual void done() { + if (mComplete.size() <= 0) + { + // Ex: timeout + LL_WARNS() << "Failed to load data. Removing observer " << LL_ENDL; + gInventory.removeObserver(this); + doOnIdleOneTime(mCallable); + + delete this; + return; + } + // What we do here is get the complete information on the // items in the requested category, and set up an observer // that will wait for that to happen. From 7a6b5a598487c6162c56246561bae205824c892b Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Thu, 1 Jul 2021 23:02:08 +0300 Subject: [PATCH 175/443] SL-15383 Fix combobox's search highlights --- indra/llui/llcombobox.cpp | 37 +++++++++++++++++++++++++++++++++++++ indra/llui/llcombobox.h | 7 ++++++- 2 files changed, 43 insertions(+), 1 deletion(-) diff --git a/indra/llui/llcombobox.cpp b/indra/llui/llcombobox.cpp index 52dc908655..bcc653a602 100644 --- a/indra/llui/llcombobox.cpp +++ b/indra/llui/llcombobox.cpp @@ -1037,6 +1037,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 4af3313162..e17d6cdfb4 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 @@ -100,6 +102,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(); From 66793abc716d86660e2fa4c7731e235881525c69 Mon Sep 17 00:00:00 2001 From: Mnikolenko Productengine Date: Fri, 2 Jul 2021 16:11:39 +0300 Subject: [PATCH 176/443] SL-14075 allow exporting multiple textures with the same name --- indra/newview/llinventorybridge.cpp | 2 +- indra/newview/llinventorybridge.h | 3 +++ indra/newview/llinventoryfunctions.cpp | 11 ++++++++++- indra/newview/llpreviewtexture.cpp | 4 ++-- indra/newview/llpreviewtexture.h | 2 +- 5 files changed, 17 insertions(+), 5 deletions(-) diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp index 9b5be70d86..86ee7e7a82 100644 --- a/indra/newview/llinventorybridge.cpp +++ b/indra/newview/llinventorybridge.cpp @@ -5497,7 +5497,7 @@ void LLTextureBridge::performAction(LLInventoryModel* model, std::string action) LLPreviewTexture* preview_texture = LLFloaterReg::getTypedInstance("preview_texture", mUUID); if (preview_texture) { - preview_texture->saveMultipleToFile(); + preview_texture->saveMultipleToFile(mFileName); } } else diff --git a/indra/newview/llinventorybridge.h b/indra/newview/llinventorybridge.h index 9af8664388..7db9c640f2 100644 --- a/indra/newview/llinventorybridge.h +++ b/indra/newview/llinventorybridge.h @@ -403,6 +403,9 @@ public: virtual void buildContextMenu(LLMenuGL& menu, U32 flags); virtual void performAction(LLInventoryModel* model, std::string action); bool canSaveTexture(void); + void setFileName(std::string& file_name) { mFileName = file_name; } +protected: + std::string mFileName; }; class LLSoundBridge : public LLItemBridge diff --git a/indra/newview/llinventoryfunctions.cpp b/indra/newview/llinventoryfunctions.cpp index 5049174a8b..9cc67766ca 100644 --- a/indra/newview/llinventoryfunctions.cpp +++ b/indra/newview/llinventoryfunctions.cpp @@ -2558,13 +2558,22 @@ void LLInventoryAction::saveMultipleTextures(const std::vector& fil 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; - LLInvFVBridge* bridge = (LLInvFVBridge*)folder_item->getViewModelItem(); + 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"); } diff --git a/indra/newview/llpreviewtexture.cpp b/indra/newview/llpreviewtexture.cpp index 53869606bb..cd7b93aba7 100644 --- a/indra/newview/llpreviewtexture.cpp +++ b/indra/newview/llpreviewtexture.cpp @@ -319,10 +319,10 @@ void LLPreviewTexture::saveTextureToFile(const std::vector& filenam } -void LLPreviewTexture::saveMultipleToFile() +void LLPreviewTexture::saveMultipleToFile(const std::string& file_name) { std::string texture_location(gSavedSettings.getString("TextureSaveLocation")); - std::string texture_name = getItem()->getName(); + std::string texture_name = file_name.empty() ? getItem()->getName() : file_name; std::string filepath; S32 i = 0; diff --git a/indra/newview/llpreviewtexture.h b/indra/newview/llpreviewtexture.h index cc6c7854b6..9b6a843875 100644 --- a/indra/newview/llpreviewtexture.h +++ b/indra/newview/llpreviewtexture.h @@ -63,7 +63,7 @@ public: void openToSave(); void saveTextureToFile(const std::vector& filenames); - void saveMultipleToFile(); + void saveMultipleToFile(const std::string& file_name = ""); static void onSaveAsBtn(void* data); From 7a468f62730029be9a47a2079fa267788d7a339e Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Fri, 2 Jul 2021 23:39:18 +0300 Subject: [PATCH 177/443] SL-15528 Crash at reblendSettings looks like blenders weren't inited yet. --- indra/newview/llfloatereditextdaycycle.cpp | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/indra/newview/llfloatereditextdaycycle.cpp b/indra/newview/llfloatereditextdaycycle.cpp index 0501c287ad..281d4f68f5 100644 --- a/indra/newview/llfloatereditextdaycycle.cpp +++ b/indra/newview/llfloatereditextdaycycle.cpp @@ -1457,14 +1457,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) From d53055406ea82f57edc7d5f59ed73ca1cda90621 Mon Sep 17 00:00:00 2001 From: Andrey Lihatskiy Date: Mon, 12 Jul 2021 20:32:48 +0300 Subject: [PATCH 178/443] DRTVWR-521 xcode buildfix --- indra/llplugin/llpluginprocessparent.cpp | 6 +++--- indra/newview/llinventorybridge.h | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/indra/llplugin/llpluginprocessparent.cpp b/indra/llplugin/llpluginprocessparent.cpp index 7d18bae947..e5b4dec1bd 100644 --- a/indra/llplugin/llpluginprocessparent.cpp +++ b/indra/llplugin/llpluginprocessparent.cpp @@ -154,9 +154,9 @@ void LLPluginProcessParent::shutdown() { EState state = (*it).second->mState; if (state != STATE_CLEANUP - || state != STATE_EXITING - || state != STATE_DONE - || state != STATE_ERROR) + && state != STATE_EXITING + && state != STATE_DONE + && state != STATE_ERROR) { (*it).second->setState(STATE_GOODBYE); } diff --git a/indra/newview/llinventorybridge.h b/indra/newview/llinventorybridge.h index 7db9c640f2..5d938bbc70 100644 --- a/indra/newview/llinventorybridge.h +++ b/indra/newview/llinventorybridge.h @@ -403,7 +403,7 @@ public: virtual void buildContextMenu(LLMenuGL& menu, U32 flags); virtual void performAction(LLInventoryModel* model, std::string action); bool canSaveTexture(void); - void setFileName(std::string& file_name) { mFileName = file_name; } + void setFileName(std::string file_name) { mFileName = file_name; } protected: std::string mFileName; }; From e0eb9b96f7137e1d4ad4f8b7224cb8b6145ad77c Mon Sep 17 00:00:00 2001 From: "Brad Payne (Vir Linden)" Date: Tue, 13 Jul 2021 14:55:11 +0100 Subject: [PATCH 179/443] SL-15572 - Possible fix for codeticket upload issue --- build.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/build.sh b/build.sh index 3b0cf97731..89e4492671 100755 --- a/build.sh +++ b/build.sh @@ -449,6 +449,7 @@ then # Upload additional packages. for package_id in $additional_packages do + sleep 240 package=$(installer_$arch "$package_id") if [ x"$package" != x ] then From 3d57b7946a1b432710b2909c8ece16e62e356148 Mon Sep 17 00:00:00 2001 From: "Brad Payne (Vir Linden)" Date: Tue, 13 Jul 2021 16:19:35 +0100 Subject: [PATCH 180/443] SL-15572 - more sleeps in build.sh --- build.sh | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/build.sh b/build.sh index 89e4492671..491fdd6b94 100755 --- a/build.sh +++ b/build.sh @@ -449,10 +449,11 @@ then # Upload additional packages. for package_id in $additional_packages do - sleep 240 package=$(installer_$arch "$package_id") if [ x"$package" != x ] then + echo "sleeping 240" + sleep 240 python_cmd "$helpers/codeticket.py" addoutput "Installer $package_id" "$package" \ || fatal "Upload of installer $package_id failed" else @@ -466,6 +467,8 @@ then if [ "${RELEASE_CRASH_REPORTING:-}" != "OFF" ] then # Upload crash reporter file + echo "sleeping 240" + sleep 240 python_cmd "$helpers/codeticket.py" addoutput "Symbolfile" "$VIEWER_SYMBOL_FILE" \ || fatal "Upload of symbolfile failed" fi @@ -474,6 +477,8 @@ then # *TODO: Make this an upload-extension if [ -r "$build_dir/llphysicsextensions_package" ] then + echo "sleeping 240" + sleep 240 llphysicsextensions_package=$(cat $build_dir/llphysicsextensions_package) python_cmd "$helpers/codeticket.py" addoutput "Physics Extensions Package" "$llphysicsextensions_package" --private \ || fatal "Upload of physics extensions package failed" From 502afc5ed2cd883afb5e921cf33c8dff24d1336f Mon Sep 17 00:00:00 2001 From: "Brad Payne (Vir Linden)" Date: Tue, 13 Jul 2021 18:20:56 +0100 Subject: [PATCH 181/443] SL-15572 - shorter sleeps in build.sh --- build.sh | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/build.sh b/build.sh index 491fdd6b94..f7e90b8582 100755 --- a/build.sh +++ b/build.sh @@ -452,8 +452,8 @@ then package=$(installer_$arch "$package_id") if [ x"$package" != x ] then - echo "sleeping 240" - sleep 240 + echo "sleeping 30" + sleep 30 python_cmd "$helpers/codeticket.py" addoutput "Installer $package_id" "$package" \ || fatal "Upload of installer $package_id failed" else @@ -467,8 +467,8 @@ then if [ "${RELEASE_CRASH_REPORTING:-}" != "OFF" ] then # Upload crash reporter file - echo "sleeping 240" - sleep 240 + echo "sleeping 30" + sleep 30 python_cmd "$helpers/codeticket.py" addoutput "Symbolfile" "$VIEWER_SYMBOL_FILE" \ || fatal "Upload of symbolfile failed" fi @@ -477,8 +477,8 @@ then # *TODO: Make this an upload-extension if [ -r "$build_dir/llphysicsextensions_package" ] then - echo "sleeping 240" - sleep 240 + echo "sleeping 30" + sleep 30 llphysicsextensions_package=$(cat $build_dir/llphysicsextensions_package) python_cmd "$helpers/codeticket.py" addoutput "Physics Extensions Package" "$llphysicsextensions_package" --private \ || fatal "Upload of physics extensions package failed" From 4d15f18d924b403fd40ae737b9478aadc345a56a Mon Sep 17 00:00:00 2001 From: "Brad Payne (Vir Linden)" Date: Tue, 13 Jul 2021 21:40:00 +0100 Subject: [PATCH 182/443] SL-15572 - retry logic for codeticket.py commands --- build.sh | 37 +++++++++++++++++++++++++++---------- 1 file changed, 27 insertions(+), 10 deletions(-) diff --git a/build.sh b/build.sh index f7e90b8582..72fa5fc31e 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 @@ -443,7 +466,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" # Upload additional packages. @@ -452,9 +475,7 @@ then package=$(installer_$arch "$package_id") if [ x"$package" != x ] then - echo "sleeping 30" - sleep 30 - 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" else record_failure "Failed to find additional package for '$package_id'." @@ -467,9 +488,7 @@ then if [ "${RELEASE_CRASH_REPORTING:-}" != "OFF" ] then # Upload crash reporter file - echo "sleeping 30" - sleep 30 - 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" fi @@ -477,10 +496,8 @@ then # *TODO: Make this an upload-extension if [ -r "$build_dir/llphysicsextensions_package" ] then - echo "sleeping 30" - sleep 30 llphysicsextensions_package=$(cat $build_dir/llphysicsextensions_package) - 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 From 77aac9579170369a11f0884e16bd730f8cbb8bdb Mon Sep 17 00:00:00 2001 From: Mnikolenko Productengine Date: Wed, 14 Jul 2021 14:49:43 +0300 Subject: [PATCH 183/443] SL-15297 performance floater ui update --- .../newview/llfloateravatarrendersettings.cpp | 37 +-- indra/newview/llfloateravatarrendersettings.h | 4 - indra/newview/llfloaterperformance.cpp | 178 ++++++++++---- indra/newview/llfloaterperformance.h | 12 +- .../xui/en/floater_avatar_render_settings.xml | 66 +++--- .../default/xui/en/floater_performance.xml | 221 ++++------------- .../xui/en/menu_avatar_rendering_settings.xml | 25 +- .../en/menu_avatar_rendering_settings_add.xml | 4 +- .../xui/en/panel_performance_complexity.xml | 6 +- .../default/xui/en/panel_performance_huds.xml | 17 +- .../xui/en/panel_performance_nearby.xml | 18 +- .../xui/en/panel_performance_preferences.xml | 188 ++++++++++----- .../xui/en/panel_performance_presets.xml | 223 ------------------ .../en/panel_performance_troubleshooting.xml | 190 --------------- 14 files changed, 375 insertions(+), 814 deletions(-) delete mode 100644 indra/newview/skins/default/xui/en/panel_performance_presets.xml delete mode 100644 indra/newview/skins/default/xui/en/panel_performance_troubleshooting.xml diff --git a/indra/newview/llfloateravatarrendersettings.cpp b/indra/newview/llfloateravatarrendersettings.cpp index b8f854feb3..7d098e6c88 100644 --- a/indra/newview/llfloateravatarrendersettings.cpp +++ b/indra/newview/llfloateravatarrendersettings.cpp @@ -89,7 +89,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; } @@ -133,37 +132,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); @@ -214,6 +189,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 00ee074f17..2e0a844afd 100644 --- a/indra/newview/llfloateravatarrendersettings.h +++ b/indra/newview/llfloateravatarrendersettings.h @@ -48,7 +48,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); @@ -59,15 +58,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/llfloaterperformance.cpp b/indra/newview/llfloaterperformance.cpp index 16afeb6e52..a2fb8c130d 100644 --- a/indra/newview/llfloaterperformance.cpp +++ b/indra/newview/llfloaterperformance.cpp @@ -31,6 +31,7 @@ #include "llappearancemgr.h" #include "llavataractions.h" #include "llavatarrendernotifier.h" +#include "llcheckboxctrl.h" #include "llfeaturemanager.h" #include "llfloaterpreference.h" // LLAvatarComplexityControls #include "llfloaterreg.h" @@ -38,52 +39,69 @@ #include "llsliderctrl.h" #include "lltextbox.h" #include "lltrans.h" +#include "llviewerobjectlist.h" #include "llvoavatar.h" #include "llvoavatarself.h" +#include "pipeline.h" const F32 REFRESH_INTERVAL = 1.0f; -const S32 COMPLEXITY_THRESHOLD_HIGH = 100000; -const S32 COMPLEXITY_THRESHOLD_MEDIUM = 30000; const S32 BAR_LEFT_PAD = 2; const S32 BAR_RIGHT_PAD = 5; const S32 BAR_BOTTOM_PAD = 9; +class LLExceptionsContextMenu : public LLListContextMenu +{ +public: + LLExceptionsContextMenu(LLFloaterPerformance* floater_settings) + : mFloaterPerformance(floater_settings) + {} +protected: + LLContextMenu* createMenu() + { + LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar; + LLUICtrl::EnableCallbackRegistry::ScopedRegistrar enable_registrar; + registrar.add("Settings.SetRendering", boost::bind(&LLFloaterPerformance::onCustomAction, mFloaterPerformance, _2, mUUIDs.front())); + enable_registrar.add("Settings.IsSelected", boost::bind(&LLFloaterPerformance::isActionChecked, mFloaterPerformance, _2, mUUIDs.front())); + LLContextMenu* menu = createFromFile("menu_avatar_rendering_settings.xml"); + + return menu; + } + + LLFloaterPerformance* mFloaterPerformance; +}; + LLFloaterPerformance::LLFloaterPerformance(const LLSD& key) : LLFloater(key), mUpdateTimer(new LLTimer()), mNearbyMaxComplexity(0) { + mContextMenu = new LLExceptionsContextMenu(this); } LLFloaterPerformance::~LLFloaterPerformance() { mComplexityChangedSignal.disconnect(); + delete mContextMenu; delete mUpdateTimer; } BOOL LLFloaterPerformance::postBuild() { mMainPanel = getChild("panel_performance_main"); - mTroubleshootingPanel = getChild("panel_performance_troubleshooting"); mNearbyPanel = getChild("panel_performance_nearby"); mComplexityPanel = getChild("panel_performance_complexity"); mSettingsPanel = getChild("panel_performance_preferences"); mHUDsPanel = getChild("panel_performance_huds"); - mPresetsPanel = getChild("panel_performance_presets"); - getChild("troubleshooting_subpanel")->setMouseDownCallback(boost::bind(&LLFloaterPerformance::showSelectedPanel, this, mTroubleshootingPanel)); getChild("nearby_subpanel")->setMouseDownCallback(boost::bind(&LLFloaterPerformance::showSelectedPanel, this, mNearbyPanel)); getChild("complexity_subpanel")->setMouseDownCallback(boost::bind(&LLFloaterPerformance::showSelectedPanel, this, mComplexityPanel)); getChild("settings_subpanel")->setMouseDownCallback(boost::bind(&LLFloaterPerformance::showSelectedPanel, this, mSettingsPanel)); getChild("huds_subpanel")->setMouseDownCallback(boost::bind(&LLFloaterPerformance::showSelectedPanel, this, mHUDsPanel)); - getChild("presets_subpanel")->setMouseDownCallback(boost::bind(&LLFloaterPerformance::showSelectedPanel, this, mPresetsPanel)); - initBackBtn(mTroubleshootingPanel); initBackBtn(mNearbyPanel); initBackBtn(mComplexityPanel); initBackBtn(mSettingsPanel); initBackBtn(mHUDsPanel); - initBackBtn(mPresetsPanel); mHUDList = mHUDsPanel->getChild("hud_list"); mHUDList->setNameListType(LLNameListCtrl::SPECIAL); @@ -96,12 +114,12 @@ BOOL LLFloaterPerformance::postBuild() mObjectList->setIconClickedCallback(boost::bind(&LLFloaterPerformance::detachItem, this, _1)); mSettingsPanel->getChild("advanced_btn")->setCommitCallback(boost::bind(&LLFloaterPerformance::onClickAdvanced, this)); + mSettingsPanel->getChild("hide_avatars")->setCommitCallback(boost::bind(&LLFloaterPerformance::onClickHideAvatars, this)); + mSettingsPanel->getChild("hide_avatars")->set(!LLPipeline::hasRenderTypeControl(LLPipeline::RENDER_TYPE_AVATAR)); mNearbyPanel->getChild("exceptions_btn")->setCommitCallback(boost::bind(&LLFloaterPerformance::onClickExceptions, this)); mNearbyList = mNearbyPanel->getChild("nearby_list"); - - mPresetsPanel->getChild("avatars_nearby_link")->setURLClickedCallback(boost::bind(&LLFloaterPerformance::showSelectedPanel, this, mNearbyPanel)); - mPresetsPanel->getChild("settings_link")->setURLClickedCallback(boost::bind(&LLFloaterPerformance::showSelectedPanel, this, mSettingsPanel)); + mNearbyList->setRightMouseDownCallback(boost::bind(&LLFloaterPerformance::onAvatarListRightClick, this, _1, _2, _3)); updateComplexityText(); mComplexityChangedSignal = gSavedSettings.getControl("IndirectMaxComplexity")->getCommitSignal()->connect(boost::bind(&LLFloaterPerformance::updateComplexityText, this)); @@ -134,28 +152,27 @@ void LLFloaterPerformance::showSelectedPanel(LLPanel* selected_panel) void LLFloaterPerformance::draw() { + const S32 NUM_PERIODS = 50; + if (mUpdateTimer->hasExpired()) { - getChild("fps_value")->setValue((S32)llround(LLTrace::get_frame_recording().getPeriodMeanPerSec(LLStatViewer::FPS))); - if (mMainPanel->getVisible()) - { - mMainPanel->getChild("huds_value")->setValue(LLHUDRenderNotifier::getInstance()->getHUDsCount()); - mMainPanel->getChild("complexity_value")->setValue((S32)gAgentAvatarp->getVisualComplexity()); - updateNearbyComplexityDesc(); - } - else if (mHUDsPanel->getVisible()) + getChild("fps_value")->setValue((S32)llround(LLTrace::get_frame_recording().getPeriodMeanPerSec(LLStatViewer::FPS, NUM_PERIODS))); + if (mHUDsPanel->getVisible()) { populateHUDList(); } else if (mNearbyPanel->getVisible()) { populateNearbyList(); - updateNearbyComplexityDesc(); } else if (mComplexityPanel->getVisible()) { populateObjectList(); } + else if (mSettingsPanel->getVisible()) + { + mSettingsPanel->getChild("hide_avatars")->set(!LLPipeline::hasRenderTypeControl(LLPipeline::RENDER_TYPE_AVATAR)); + } mUpdateTimer->setTimerExpirySec(REFRESH_INTERVAL); } @@ -170,12 +187,10 @@ void LLFloaterPerformance::showMainPanel() void LLFloaterPerformance::hidePanels() { - mTroubleshootingPanel->setVisible(FALSE); mNearbyPanel->setVisible(FALSE); mComplexityPanel->setVisible(FALSE); mHUDsPanel->setVisible(FALSE); mSettingsPanel->setVisible(FALSE); - mPresetsPanel->setVisible(FALSE); } void LLFloaterPerformance::initBackBtn(LLPanel* panel) @@ -236,8 +251,6 @@ void LLFloaterPerformance::populateHUDList() mHUDList->sortByColumnIndex(1, FALSE); mHUDList->setScrollPos(prev_pos); mHUDList->selectItemBySpecialId(prev_selected_id); - - mHUDsPanel->getChild("huds_value")->setValue(std::to_string(complexity_list.size())); } void LLFloaterPerformance::populateObjectList() @@ -384,32 +397,6 @@ void LLFloaterPerformance::getNearbyAvatars(std::vector &valid_nea } } -void LLFloaterPerformance::updateNearbyComplexityDesc() -{ - std::string desc = getString("low"); - - static LLCachedControl max_render_cost(gSavedSettings, "RenderAvatarMaxComplexity", 0); - if (mMainPanel->getVisible()) - { - std::vector valid_nearby_avs; - getNearbyAvatars(valid_nearby_avs); - } - if (mNearbyMaxComplexity > COMPLEXITY_THRESHOLD_HIGH) - { - desc = getString("very_high"); - } - else if (mNearbyMaxComplexity > COMPLEXITY_THRESHOLD_MEDIUM) - { - desc = getString("medium"); - } - - if (mMainPanel->getVisible()) - { - mMainPanel->getChild("avatars_nearby_value")->setValue(desc); - } - mNearbyPanel->getChild("av_nearby_value")->setValue(desc); -} - void LLFloaterPerformance::detachItem(const LLUUID& item_id) { LLAppearanceMgr::instance().removeItemFromAvatar(item_id); @@ -425,6 +412,11 @@ void LLFloaterPerformance::onClickAdvanced() LLFloaterReg::showInstance("prefs_graphics_advanced"); } +void LLFloaterPerformance::onClickHideAvatars() +{ + LLPipeline::toggleRenderTypeControl(LLPipeline::RENDER_TYPE_AVATAR); +} + void LLFloaterPerformance::onClickExceptions() { LLFloaterReg::showInstance("avatar_render_settings"); @@ -443,4 +435,90 @@ void LLFloaterPerformance::updateComplexityText() mNearbyPanel->getChild("IndirectMaxComplexityText", 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 LLFloaterPerformance::onCustomAction(const LLSD& userdata, const LLUUID& av_id) +{ + const std::string command_name = userdata.asString(); + + S32 new_setting = 0; + if ("default" == command_name) + { + new_setting = S32(LLVOAvatar::AV_RENDER_NORMALLY); + } + else if ("never" == command_name) + { + new_setting = S32(LLVOAvatar::AV_DO_NOT_RENDER); + } + else if ("always" == command_name) + { + new_setting = S32(LLVOAvatar::AV_ALWAYS_RENDER); + } + + LLVOAvatar *avatarp = find_avatar(av_id); + if (avatarp) + { + avatarp->setVisualMuteSettings(LLVOAvatar::VisualMuteSettings(new_setting)); + } + else + { + LLRenderMuteList::getInstance()->saveVisualMuteSetting(av_id, new_setting); + } +} + + +bool LLFloaterPerformance::isActionChecked(const LLSD& userdata, const LLUUID& av_id) +{ + const std::string command_name = userdata.asString(); + + S32 visual_setting = LLRenderMuteList::getInstance()->getSavedVisualMuteSetting(av_id); + if ("default" == command_name) + { + 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)); + } + else if ("always" == command_name) + { + return (visual_setting == S32(LLVOAvatar::AV_ALWAYS_RENDER)); + } + return false; +} + +void LLFloaterPerformance::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()) + { + selected_uuids.push_back(list->getCurrentID()); + mContextMenu->show(ctrl, selected_uuids, x, y); + } +} + // EOF diff --git a/indra/newview/llfloaterperformance.h b/indra/newview/llfloaterperformance.h index ea15873b95..58f9447d4c 100644 --- a/indra/newview/llfloaterperformance.h +++ b/indra/newview/llfloaterperformance.h @@ -27,6 +27,7 @@ #define LL_LLFLOATERPERFORMANCE_H #include "llfloater.h" +#include "lllistcontextmenu.h" class LLCharacter; class LLNameListCtrl; @@ -46,6 +47,11 @@ public: 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); + private: void initBackBtn(LLPanel* panel); void populateHUDList(); @@ -53,25 +59,25 @@ private: void populateNearbyList(); void onClickAdvanced(); + void onClickHideAvatars(); void onClickExceptions(); void updateMaxComplexity(); void updateComplexityText(); void getNearbyAvatars(std::vector &valid_nearby_avs); - void updateNearbyComplexityDesc(); LLPanel* mMainPanel; - LLPanel* mTroubleshootingPanel; LLPanel* mNearbyPanel; LLPanel* mComplexityPanel; LLPanel* mHUDsPanel; LLPanel* mSettingsPanel; - LLPanel* mPresetsPanel; LLNameListCtrl* mHUDList; LLNameListCtrl* mObjectList; LLNameListCtrl* mNearbyList; + LLListContextMenu* mContextMenu; + LLTimer* mUpdateTimer; S32 mNearbyMaxComplexity; diff --git a/indra/newview/skins/default/xui/en/floater_avatar_render_settings.xml b/indra/newview/skins/default/xui/en/floater_avatar_render_settings.xml index e088d4d2a1..d222dca98b 100644 --- a/indra/newview/skins/default/xui/en/floater_avatar_render_settings.xml +++ b/indra/newview/skins/default/xui/en/floater_avatar_render_settings.xml @@ -10,7 +10,7 @@ save_rect="true" single_instance="true" reuse_instance="true" - title="AVATAR RENDER SETTINGS" + title="AVATAR DISPLAY EXCEPTIONS" width="300"> - - + top="0"> + relative_width="0.65" /> - + relative_width="0.35" /> + + + diff --git a/indra/newview/skins/default/xui/en/floater_performance.xml b/indra/newview/skins/default/xui/en/floater_performance.xml index 039421d589..210b2f8792 100644 --- a/indra/newview/skins/default/xui/en/floater_performance.xml +++ b/indra/newview/skins/default/xui/en/floater_performance.xml @@ -1,20 +1,11 @@ - - - - FPS -- 60 or more for the best experience - + frames per second + + + Allow 5-10 seconds for + + + changes to take full effect. + + top="60"> - - Quick settings for common situations - - - Choose settings for parties, exploration, photography, and more. - - - - + left="10" + top="5"> - Individual settings + Graphics settings - More control over quality, visibility distance, and enhancements. + Choose settings for distance, water, lighting and more. - Nearby avatar complexity is - - - very high + Avatars nearby - Choose which avatars are not displayed in detail, to increase FPS. + Manage which nearby avatars are fully displayed. - Your avatar complexity is - - - 275 + Your avatar complexity Reduce the complexity of your avatar if you aren't satisfied with current FPS. @@ -278,7 +222,7 @@ mouse_opaque="true" name="icon_arrow4" follows="right|top" - top="24" + top="29" right="-20"/> - Your current HUDs: - - - 7 + Your active HUDs Removing HUDs you are not using can improve speed. @@ -335,72 +268,10 @@ mouse_opaque="true" name="icon_arrow4" follows="right|top" - top="24" - right="-20"/> - - - - General troubleshooting - - - Choose among common problems and see what you can do. - - - - - - - - - + - - + + + + + + + diff --git a/indra/newview/skins/default/xui/en/menu_avatar_rendering_settings_add.xml b/indra/newview/skins/default/xui/en/menu_avatar_rendering_settings_add.xml index c64b24ed70..6e09eb5981 100644 --- a/indra/newview/skins/default/xui/en/menu_avatar_rendering_settings_add.xml +++ b/indra/newview/skins/default/xui/en/menu_avatar_rendering_settings_add.xml @@ -4,13 +4,13 @@ left="0" bottom="0" visible="false" mouse_opaque="false"> diff --git a/indra/newview/skins/default/xui/en/panel_performance_complexity.xml b/indra/newview/skins/default/xui/en/panel_performance_complexity.xml index 8d4512c4f7..b2f65f9488 100644 --- a/indra/newview/skins/default/xui/en/panel_performance_complexity.xml +++ b/indra/newview/skins/default/xui/en/panel_performance_complexity.xml @@ -42,7 +42,7 @@ top_pad="10" name="attachments_title" width="195"> - My avatar complexity + Your avatar complexity - Complex attachments require more time and memory to display. + If your avatar is very complex, some other people may not see you in full detail and - While you are in this location, removing the most complex ones may increase speed. + your own graphics speed may be reduced. - Your current HUDs: - - - 7 + Your active HUDs - Detaching HUDs you aren't using us always a good idea, but especially in a complex location. + Detaching HUDs you aren't using saves memory and can make Second Life run faster. - Note: Using a HUD's minimize button does not save memory. + Note: Using a HUD's minimize button does not detach it. - Nearby avatar complexity is - - - very high + Avatars nearby - Some avatars nearby are slow to display. Choosing a complexity limit may help graphics speed. + Avatars more complex than your chosen limit will be shown in silhouette. - Individual settings + Graphics settings - Graphics quality -shortcuts + Shortcuts - To zoom out and see long distances, increase the distance. - - - If you are indoors, decrease the distance to improve speed. + To see more land when you zoom out, increase the distance. - Enhancements + Environment - + + + Shadows: + + + + + + + + + Water + + + Reducing or turning off water effects can greatly improve frame rate. + - - Shadows: - - + + Photography + + - - - - + left="160" + name="photo_desc" + width="350"> + Maximum detail is good for photos, but can slow frame rate. + + - [secondlife:/// What do these settings mean?] + top_delta="3" + left_pad="10" + name="photo_desc" + width="180"> + (Enter value between 0.0 and 4.0) + + diff --git a/indra/newview/skins/default/xui/en/panel_performance_presets.xml b/indra/newview/skins/default/xui/en/panel_performance_presets.xml deleted file mode 100644 index 51516020a2..0000000000 --- a/indra/newview/skins/default/xui/en/panel_performance_presets.xml +++ /dev/null @@ -1,223 +0,0 @@ - - - - - Back - - - Quick settings - - - Note: Quick settings will reset all manual changes you have made. - - - - - Tuned for many avatars in a room. - - - Nearby avatar complexity is high. - - - [secondlife:/// Choose avatars to show and hide] - - - - - Fewer avatars, higher visibility distance. - - - - - Good for zooming your camera far out and viewing large land areas. - - - - - Maximum quality, minimum visibility distance. - - - - For more control, try - - - [secondlife:/// Idividual Settings] - - - diff --git a/indra/newview/skins/default/xui/en/panel_performance_troubleshooting.xml b/indra/newview/skins/default/xui/en/panel_performance_troubleshooting.xml deleted file mode 100644 index 0a14eeb1c0..0000000000 --- a/indra/newview/skins/default/xui/en/panel_performance_troubleshooting.xml +++ /dev/null @@ -1,190 +0,0 @@ - - - - - Back - - - Fixes for common problems - - - Some problems result from the complexity of the location where you are. All you can do is leave. - - - Rubberbanding - - - When you walk, your avatar may be pulled backward again and again. - - - Fix: XXXXXXX - - - Texture thrashing - - - On objects near you, you may see their surfaces get blurry, then sharp, then blurry again. - - - Fix: XXXXXXX - - - Avatars are not moving smoothly - - - Lorem ipsum dolor sit amet. - - - Fix: XXXXXXX - - - Will a better graphics card or new computer help? - - - Lorem ipsum dolor sit amet. - - - Fix: XXXXXXX - - From b58fb175829423412fd7ecab8b3f49ee474f92cc Mon Sep 17 00:00:00 2001 From: Andrey Lihatskiy Date: Wed, 14 Jul 2021 23:35:45 +0300 Subject: [PATCH 184/443] SL-15585 Improved notarization error handling --- indra/newview/installers/darwin/apple-notarize.sh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/indra/newview/installers/darwin/apple-notarize.sh b/indra/newview/installers/darwin/apple-notarize.sh index b953af81af..be0f8a5717 100755 --- a/indra/newview/installers/darwin/apple-notarize.sh +++ b/indra/newview/installers/darwin/apple-notarize.sh @@ -36,8 +36,12 @@ if [ -f "$CONFIG_FILE" ]; then 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 + elif + echo "Notarization error: couldn't get request UUID" + exit 1 fi fi fi From 11635dc5b80b9e65dd53cf9a66f3861c90818d0a Mon Sep 17 00:00:00 2001 From: Andrey Lihatskiy Date: Thu, 15 Jul 2021 00:58:07 +0300 Subject: [PATCH 185/443] SL-15585 typo fix --- indra/newview/installers/darwin/apple-notarize.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/indra/newview/installers/darwin/apple-notarize.sh b/indra/newview/installers/darwin/apple-notarize.sh index be0f8a5717..2b3cce6078 100755 --- a/indra/newview/installers/darwin/apple-notarize.sh +++ b/indra/newview/installers/darwin/apple-notarize.sh @@ -39,7 +39,7 @@ if [ -f "$CONFIG_FILE" ]; then echo "Notarization error: failed to process the app file" exit 1 fi - elif + else echo "Notarization error: couldn't get request UUID" exit 1 fi From 09f53a672bc42bed83bf43632013969000065c25 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Thu, 15 Jul 2021 18:37:02 +0300 Subject: [PATCH 186/443] SL-443 keybindings: Do not error on unknown function It is likely be from newer viewer / Preparations for SL-443 deloyment. --- indra/newview/llviewerinput.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/indra/newview/llviewerinput.cpp b/indra/newview/llviewerinput.cpp index c0eaa88f54..f269be035e 100644 --- a/indra/newview/llviewerinput.cpp +++ b/indra/newview/llviewerinput.cpp @@ -1070,7 +1070,7 @@ BOOL LLViewerInput::bindKey(const S32 mode, const KEY key, const MASK mask, cons if (!function) { - LL_ERRS() << "Can't bind key to function " << function_name << ", no function with this name found" << LL_ENDL; + LL_WARNS() << "Can't bind key to function " << function_name << ", no function with this name found" << LL_ENDL; return FALSE; } @@ -1112,7 +1112,7 @@ BOOL LLViewerInput::bindMouse(const S32 mode, const EMouseClickType mouse, const if (!function) { - LL_ERRS() << "Can't bind key to function " << function_name << ", no function with this name found" << LL_ENDL; + LL_WARNS() << "Can't bind mouse key to function " << function_name << ", no function with this name found" << LL_ENDL; return FALSE; } From 3bdabd80de15d7dcadb460d8fa37af6674692ebd Mon Sep 17 00:00:00 2001 From: Andrey Lihatskiy Date: Thu, 15 Jul 2021 19:33:42 +0300 Subject: [PATCH 187/443] DRTVWR-521 improvement --- indra/newview/llinventorybridge.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/indra/newview/llinventorybridge.h b/indra/newview/llinventorybridge.h index 5d938bbc70..c21bfbd02d 100644 --- a/indra/newview/llinventorybridge.h +++ b/indra/newview/llinventorybridge.h @@ -403,7 +403,7 @@ public: virtual void buildContextMenu(LLMenuGL& menu, U32 flags); virtual void performAction(LLInventoryModel* model, std::string action); bool canSaveTexture(void); - void setFileName(std::string file_name) { mFileName = file_name; } + void setFileName(const std::string& file_name) { mFileName = file_name; } protected: std::string mFileName; }; From 84ae60a3b34d92930a74e9207bf39e6335e307a0 Mon Sep 17 00:00:00 2001 From: Mnikolenko Productengine Date: Fri, 16 Jul 2021 16:32:12 +0300 Subject: [PATCH 188/443] SL-15581 Add the function to get median FPS --- indra/llcommon/lltracerecording.h | 25 +++++++++++++++++++++++++ indra/newview/llfloaterperformance.cpp | 2 +- 2 files changed, 26 insertions(+), 1 deletion(-) 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/newview/llfloaterperformance.cpp b/indra/newview/llfloaterperformance.cpp index a2fb8c130d..879a8f8718 100644 --- a/indra/newview/llfloaterperformance.cpp +++ b/indra/newview/llfloaterperformance.cpp @@ -156,7 +156,7 @@ void LLFloaterPerformance::draw() if (mUpdateTimer->hasExpired()) { - getChild("fps_value")->setValue((S32)llround(LLTrace::get_frame_recording().getPeriodMeanPerSec(LLStatViewer::FPS, NUM_PERIODS))); + getChild("fps_value")->setValue((S32)llround(LLTrace::get_frame_recording().getPeriodMedianPerSec(LLStatViewer::FPS, NUM_PERIODS))); if (mHUDsPanel->getVisible()) { populateHUDList(); From 2d855a9fd7ea0ef32f8d9de81b2532b3771142e4 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Fri, 16 Jul 2021 22:45:41 +0300 Subject: [PATCH 189/443] SL-15594 Reimplement previous voice keybind behavior Also fixed dupplicate checks --- indra/newview/llviewerinput.cpp | 159 +++++++++++++++++++++++++------ indra/newview/llviewerinput.h | 11 +++ indra/newview/llviewerwindow.cpp | 12 ++- 3 files changed, 150 insertions(+), 32 deletions(-) diff --git a/indra/newview/llviewerinput.cpp b/indra/newview/llviewerinput.cpp index f269be035e..77b0c8e37b 100644 --- a/indra/newview/llviewerinput.cpp +++ b/indra/newview/llviewerinput.cpp @@ -60,8 +60,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); }; @@ -852,7 +865,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); @@ -903,8 +919,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() @@ -1034,6 +1050,29 @@ BOOL LLViewerInput::handleKeyUp(KEY translated_key, MASK translated_mask) return gViewerWindow->handleKeyUp(translated_key, translated_mask); } +bool LLViewerInput::handleGlobalBindsKeyDown(KEY key, MASK mask) +{ + S32 mode = getMode(); + return scanKey(mGlobalKeyBindings[mode], mGlobalKeyBindings[mode].size(), key, mask, TRUE, FALSE, FALSE, FALSE); +} + +bool LLViewerInput::handleGlobalBindsKeyUp(KEY key, MASK mask) +{ + 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) +{ + bool res = false; + if (down) + { + S32 mode = getMode(); + res = scanMouse(mGlobalMouseBindings[mode], mGlobalMouseBindings[mode].size(), clicktype, mask, MOUSE_STATE_DOWN); + } + return res; +} + BOOL LLViewerInput::bindKey(const S32 mode, const KEY key, const MASK mask, const std::string& function_name) { S32 index; @@ -1061,39 +1100,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_WARNS() << "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; } @@ -1104,38 +1168,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_WARNS() << "Can't bind mouse 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; } @@ -1162,6 +1251,8 @@ void LLViewerInput::resetBindings() { for (S32 i = 0; i < MODE_COUNT; i++) { + mGlobalKeyBindings[i].clear(); + mGlobalMouseBindings[i].clear(); mKeyBindings[i].clear(); mMouseBindings[i].clear(); } @@ -1536,5 +1627,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 281a209896..8401f8cd95 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; @@ -164,6 +171,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/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp index 21985d5a8a..b0462f8ba7 100644 --- a/indra/newview/llviewerwindow.cpp +++ b/indra/newview/llviewerwindow.cpp @@ -54,7 +54,6 @@ #include "llslurl.h" #include "llrender.h" -#include "llvoiceclient.h" // for push-to-talk button handling #include "stringize.h" // @@ -1057,6 +1056,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)) { @@ -1577,6 +1579,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(); @@ -1601,6 +1607,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) From 54171dbc9fe3fa42ebbf59a243b7381fdb3aa662 Mon Sep 17 00:00:00 2001 From: Andrey Lihatskiy Date: Mon, 19 Jul 2021 18:58:04 +0300 Subject: [PATCH 190/443] SL-15585 more logging for altool --- indra/newview/installers/darwin/apple-notarize.sh | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/indra/newview/installers/darwin/apple-notarize.sh b/indra/newview/installers/darwin/apple-notarize.sh index 2b3cce6078..ecf5bd158a 100755 --- a/indra/newview/installers/darwin/apple-notarize.sh +++ b/indra/newview/installers/darwin/apple-notarize.sh @@ -6,12 +6,12 @@ if [ -f "$CONFIG_FILE" ]; then zip_file=${app_file/app/zip} ditto -c -k --keepParent "$app_file" "$zip_file" if [ -f "$zip_file" ]; then - requestUUID=$(xcrun altool --notarize-app --primary-bundle-id "com.secondlife.viewer" \ - --username $USERNAME \ - --password $PASSWORD \ - --asc-provider $ASC_PROVIDER \ - --file "$zip_file" 2>&1 \ - | awk '/RequestUUID/ { print $NF; }') + 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" @@ -41,6 +41,7 @@ if [ -f "$CONFIG_FILE" ]; then fi else echo "Notarization error: couldn't get request UUID" + echo $res exit 1 fi fi From 928191f525cf8a02816718eefd9a65097d8ecb8b Mon Sep 17 00:00:00 2001 From: Mnikolenko Productengine Date: Mon, 19 Jul 2021 20:07:03 +0300 Subject: [PATCH 191/443] SL-15297 performance floater UI update #2 --- indra/llui/llscrolllistcell.cpp | 3 +- indra/llui/llscrolllistcell.h | 1 + indra/newview/llfloaterperformance.cpp | 89 ++++++++++++------- indra/newview/llfloaterpreference.cpp | 9 +- indra/newview/llfloaterpreference.h | 4 +- indra/newview/llnamelistctrl.cpp | 2 +- indra/newview/llviewermenu.cpp | 2 + .../default/xui/en/floater_performance.xml | 42 ++++----- .../default/xui/en/menu_attachment_other.xml | 28 +++--- .../default/xui/en/menu_avatar_other.xml | 64 ++++++------- .../skins/default/xui/en/menu_viewer.xml | 15 ++-- .../xui/en/panel_performance_complexity.xml | 20 ++++- .../default/xui/en/panel_performance_huds.xml | 4 +- .../xui/en/panel_performance_nearby.xml | 75 ++++++++++++++-- .../xui/en/panel_performance_preferences.xml | 47 ++++------ .../newview/skins/default/xui/en/strings.xml | 2 +- 16 files changed, 249 insertions(+), 158 deletions(-) diff --git a/indra/llui/llscrolllistcell.cpp b/indra/llui/llscrolllistcell.cpp index c5f53823f3..61470d1440 100644 --- a/indra/llui/llscrolllistcell.cpp +++ b/indra/llui/llscrolllistcell.cpp @@ -234,8 +234,7 @@ void LLScrollListBar::draw(const LLColor4& color, const LLColor4& highlight_colo S32 left = bar_width - bar_width * mRatio; left = llclamp(left, mLeftPad, getWidth() - mRightPad - 1); - gl_line_2d(left, mBottom, getWidth() - mRightPad, mBottom, mColor); - gl_line_2d(left, mBottom - 1, getWidth() - mRightPad, mBottom - 1, mColor); + gl_rect_2d(left, mBottom, getWidth() - mRightPad, mBottom - 1, mColor); } // diff --git a/indra/llui/llscrolllistcell.h b/indra/llui/llscrolllistcell.h index 26a272b270..9a659dfd0d 100644 --- a/indra/llui/llscrolllistcell.h +++ b/indra/llui/llscrolllistcell.h @@ -154,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; diff --git a/indra/newview/llfloaterperformance.cpp b/indra/newview/llfloaterperformance.cpp index 879a8f8718..d7c0527b5c 100644 --- a/indra/newview/llfloaterperformance.cpp +++ b/indra/newview/llfloaterperformance.cpp @@ -114,10 +114,10 @@ BOOL LLFloaterPerformance::postBuild() mObjectList->setIconClickedCallback(boost::bind(&LLFloaterPerformance::detachItem, this, _1)); mSettingsPanel->getChild("advanced_btn")->setCommitCallback(boost::bind(&LLFloaterPerformance::onClickAdvanced, this)); - mSettingsPanel->getChild("hide_avatars")->setCommitCallback(boost::bind(&LLFloaterPerformance::onClickHideAvatars, this)); - mSettingsPanel->getChild("hide_avatars")->set(!LLPipeline::hasRenderTypeControl(LLPipeline::RENDER_TYPE_AVATAR)); mNearbyPanel->getChild("exceptions_btn")->setCommitCallback(boost::bind(&LLFloaterPerformance::onClickExceptions, this)); + mNearbyPanel->getChild("hide_avatars")->setCommitCallback(boost::bind(&LLFloaterPerformance::onClickHideAvatars, this)); + mNearbyPanel->getChild("hide_avatars")->set(!LLPipeline::hasRenderTypeControl(LLPipeline::RENDER_TYPE_AVATAR)); mNearbyList = mNearbyPanel->getChild("nearby_list"); mNearbyList->setRightMouseDownCallback(boost::bind(&LLFloaterPerformance::onAvatarListRightClick, this, _1, _2, _3)); @@ -164,15 +164,12 @@ void LLFloaterPerformance::draw() else if (mNearbyPanel->getVisible()) { populateNearbyList(); + mNearbyPanel->getChild("hide_avatars")->set(!LLPipeline::hasRenderTypeControl(LLPipeline::RENDER_TYPE_AVATAR)); } else if (mComplexityPanel->getVisible()) { populateObjectList(); } - else if (mSettingsPanel->getVisible()) - { - mSettingsPanel->getChild("hide_avatars")->set(!LLPipeline::hasRenderTypeControl(LLPipeline::RENDER_TYPE_AVATAR)); - } mUpdateTimer->setTimerExpirySec(REFRESH_INTERVAL); } @@ -223,7 +220,7 @@ void LLFloaterPerformance::populateHUDList() for (iter = complexity_list.begin(); iter != end; ++iter) { LLHUDComplexity hud_object_complexity = *iter; - + S32 obj_cost_short = hud_object_complexity.objectsCost / 1000; LLSD item; item["special_id"] = hud_object_complexity.objectId; item["target"] = LLNameListCtrl::SPECIAL; @@ -231,14 +228,14 @@ void LLFloaterPerformance::populateHUDList() row[0]["column"] = "complex_visual"; row[0]["type"] = "bar"; LLSD& value = row[0]["value"]; - value["ratio"] = (F32)hud_object_complexity.objectsCost / max_complexity; + value["ratio"] = (F32)obj_cost_short / max_complexity * 1000; value["bottom"] = BAR_BOTTOM_PAD; value["left_pad"] = BAR_LEFT_PAD; value["right_pad"] = BAR_RIGHT_PAD; row[1]["column"] = "complex_value"; row[1]["type"] = "text"; - row[1]["value"] = std::to_string(hud_object_complexity.objectsCost); + row[1]["value"] = std::to_string(obj_cost_short); row[1]["font"]["name"] = "SANSSERIF"; row[2]["column"] = "name"; @@ -246,7 +243,15 @@ void LLFloaterPerformance::populateHUDList() row[2]["value"] = hud_object_complexity.objectName; row[2]["font"]["name"] = "SANSSERIF"; - mHUDList->addElement(item); + LLScrollListItem* obj = mHUDList->addElement(item); + if (obj) + { + LLScrollListText* value_text = dynamic_cast(obj->getColumn(1)); + if (value_text) + { + value_text->setAlignment(LLFontGL::HCENTER); + } + } } mHUDList->sortByColumnIndex(1, FALSE); mHUDList->setScrollPos(prev_pos); @@ -274,7 +279,7 @@ void LLFloaterPerformance::populateObjectList() for (iter = complexity_list.begin(); iter != end; ++iter) { LLObjectComplexity object_complexity = *iter; - + S32 obj_cost_short = object_complexity.objectCost / 1000; LLSD item; item["special_id"] = object_complexity.objectId; item["target"] = LLNameListCtrl::SPECIAL; @@ -282,14 +287,14 @@ void LLFloaterPerformance::populateObjectList() row[0]["column"] = "complex_visual"; row[0]["type"] = "bar"; LLSD& value = row[0]["value"]; - value["ratio"] = (F32)object_complexity.objectCost / max_complexity; + value["ratio"] = (F32)obj_cost_short / max_complexity * 1000; value["bottom"] = BAR_BOTTOM_PAD; value["left_pad"] = BAR_LEFT_PAD; value["right_pad"] = BAR_RIGHT_PAD; row[1]["column"] = "complex_value"; row[1]["type"] = "text"; - row[1]["value"] = std::to_string(object_complexity.objectCost); + row[1]["value"] = std::to_string(obj_cost_short); row[1]["font"]["name"] = "SANSSERIF"; row[2]["column"] = "name"; @@ -297,7 +302,15 @@ void LLFloaterPerformance::populateObjectList() row[2]["value"] = object_complexity.objectName; row[2]["font"]["name"] = "SANSSERIF"; - mObjectList->addElement(item); + LLScrollListItem* obj = mObjectList->addElement(item); + if (obj) + { + LLScrollListText* value_text = dynamic_cast(obj->getColumn(1)); + if (value_text) + { + value_text->setAlignment(LLFontGL::HCENTER); + } + } } mObjectList->sortByColumnIndex(1, FALSE); mObjectList->setScrollPos(prev_pos); @@ -321,20 +334,21 @@ void LLFloaterPerformance::populateNearbyList() LLVOAvatar* avatar = dynamic_cast(*char_iter); if (avatar && (LLVOAvatar::AOA_INVISIBLE != avatar->getOverallAppearance())) { + S32 complexity_short = avatar->getVisualComplexity() / 1000; LLSD item; item["id"] = avatar->getID(); LLSD& row = item["columns"]; row[0]["column"] = "complex_visual"; row[0]["type"] = "bar"; LLSD& value = row[0]["value"]; - value["ratio"] = (F32)avatar->getVisualComplexity() / mNearbyMaxComplexity; + value["ratio"] = (F32)complexity_short / mNearbyMaxComplexity * 1000; value["bottom"] = BAR_BOTTOM_PAD; value["left_pad"] = BAR_LEFT_PAD; value["right_pad"] = BAR_RIGHT_PAD; row[1]["column"] = "complex_value"; row[1]["type"] = "text"; - row[1]["value"] = std::to_string( avatar->getVisualComplexity()); + row[1]["value"] = std::to_string(complexity_short); row[1]["font"]["name"] = "SANSSERIF"; row[2]["column"] = "name"; @@ -345,24 +359,36 @@ void LLFloaterPerformance::populateNearbyList() LLScrollListItem* av_item = mNearbyList->addElement(item); if(av_item) { + LLScrollListText* value_text = dynamic_cast(av_item->getColumn(1)); + if (value_text) + { + value_text->setAlignment(LLFontGL::HCENTER); + } LLScrollListText* name_text = dynamic_cast(av_item->getColumn(2)); if (name_text) { - std::string color = "white"; - if (LLVOAvatar::AOA_JELLYDOLL == avatar->getOverallAppearance()) + if (avatar->isSelf()) { - color = "LabelDisabledColor"; - LLScrollListBar* bar = dynamic_cast(av_item->getColumn(0)); - if (bar) + name_text->setColor(LLUIColorTable::instance().getColor("DrYellow")); + } + else + { + std::string color = "white"; + if (LLVOAvatar::AOA_JELLYDOLL == avatar->getOverallAppearance()) { - bar->setColor(LLUIColorTable::instance().getColor(color)); + color = "LabelDisabledColor"; + LLScrollListBar* bar = dynamic_cast(av_item->getColumn(0)); + if (bar) + { + bar->setColor(LLUIColorTable::instance().getColor(color)); + } } + else if (LLVOAvatar::AOA_NORMAL == avatar->getOverallAppearance()) + { + color = LLAvatarActions::isFriend(avatar->getID()) ? "ConversationFriendColor" : "white"; + } + name_text->setColor(LLUIColorTable::instance().getColor(color)); } - else if (LLVOAvatar::AOA_NORMAL == avatar->getOverallAppearance()) - { - color = LLAvatarActions::isFriend(avatar->getID()) ? "ConversationFriendColor" : "white"; - } - name_text->setColor(LLUIColorTable::instance().getColor(color)); } } } @@ -376,12 +402,13 @@ void LLFloaterPerformance::populateNearbyList() void LLFloaterPerformance::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() && !avatar->isSelf()) + if (avatar && !avatar->isDead() && !avatar->isControlAvatar()) { if ((dist_vec_squared(avatar->getPositionGlobal(), gAgent.getPositionGlobal()) > radius) && (dist_vec_squared(avatar->getPositionGlobal(), gAgentCamera.getCameraPositionGlobal()) > radius)) @@ -426,13 +453,15 @@ void LLFloaterPerformance::updateMaxComplexity() { LLAvatarComplexityControls::updateMax( mNearbyPanel->getChild("IndirectMaxComplexity"), - mNearbyPanel->getChild("IndirectMaxComplexityText")); + mNearbyPanel->getChild("IndirectMaxComplexityText"), + true); } void LLFloaterPerformance::updateComplexityText() { LLAvatarComplexityControls::setText(gSavedSettings.getU32("RenderAvatarMaxComplexity"), - mNearbyPanel->getChild("IndirectMaxComplexityText", true)); + mNearbyPanel->getChild("IndirectMaxComplexityText", true), + true); } static LLVOAvatar* find_avatar(const LLUUID& id) diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp index 1ab6621c4c..a0a0b3c874 100644 --- a/indra/newview/llfloaterpreference.cpp +++ b/indra/newview/llfloaterpreference.cpp @@ -1455,7 +1455,7 @@ void LLFloaterPreference::refreshUI() refresh(); } -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 @@ -1477,10 +1477,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) { @@ -1488,7 +1488,8 @@ void LLAvatarComplexityControls::setText(U32 value, LLTextBox* text_box) } else { - text_box->setText(llformat("%d", value)); + std::string text_value = short_val ? llformat("%d", value / 1000) : llformat("%d", value); + text_box->setText(text_value); } } diff --git a/indra/newview/llfloaterpreference.h b/indra/newview/llfloaterpreference.h index f86104ed99..23d3f73d70 100644 --- a/indra/newview/llfloaterpreference.h +++ b/indra/newview/llfloaterpreference.h @@ -351,8 +351,8 @@ private: 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); static void setIndirectControls(); static void setIndirectMaxNonImpostors(); static void setIndirectMaxArc(); diff --git a/indra/newview/llnamelistctrl.cpp b/indra/newview/llnamelistctrl.cpp index 92805e03f0..c24c74393d 100644 --- a/indra/newview/llnamelistctrl.cpp +++ b/indra/newview/llnamelistctrl.cpp @@ -363,7 +363,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(); } diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index ad81cb07c1..fa2ada32b3 100644 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -3149,6 +3149,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; } diff --git a/indra/newview/skins/default/xui/en/floater_performance.xml b/indra/newview/skins/default/xui/en/floater_performance.xml index 210b2f8792..c47b8100c2 100644 --- a/indra/newview/skins/default/xui/en/floater_performance.xml +++ b/indra/newview/skins/default/xui/en/floater_performance.xml @@ -1,6 +1,6 @@ @@ -93,7 +93,7 @@ border="true" bevel_style="none" follows="left|top" - height="70" + height="50" width="560" name="settings_subpanel" layout="topleft" @@ -107,7 +107,7 @@ layout="topleft" left="10" name="settings_lbl" - top="12" + top="7" width="180"> Graphics settings @@ -119,7 +119,7 @@ layout="topleft" left="10" name="settings_desc" - top_pad="10" + top_pad="0" width="395"> Choose settings for distance, water, lighting and more. @@ -130,7 +130,7 @@ mouse_opaque="true" name="icon_arrow3" follows="right|top" - top="29" + top="19" right="-20"/> + top_pad="10"> Avatars nearby @@ -165,7 +165,7 @@ layout="topleft" left="10" name="avatars_nearby_desc" - top_pad="10" + top_pad="0" width="395"> Manage which nearby avatars are fully displayed. @@ -176,7 +176,7 @@ mouse_opaque="true" name="icon_arrow2" follows="right|top" - top="29" + top="19" right="-20"/> + top_pad="10"> Your avatar complexity @@ -211,7 +211,7 @@ layout="topleft" left="10" name="complexity_info" - top_pad="10" + top_pad="0" width="455"> Reduce the complexity of your avatar if you aren't satisfied with current FPS. @@ -222,7 +222,7 @@ mouse_opaque="true" name="icon_arrow4" follows="right|top" - top="29" + top="19" right="-20"/> + top_pad="10"> Your active HUDs @@ -257,7 +257,7 @@ layout="topleft" left="10" name="huds_desc" - top_pad="10" + top_pad="0" width="395"> Removing HUDs you are not using can improve speed. @@ -268,7 +268,7 @@ mouse_opaque="true" name="icon_arrow4" follows="right|top" - top="29" + top="19" right="-20"/> diff --git a/indra/newview/skins/default/xui/en/menu_attachment_other.xml b/indra/newview/skins/default/xui/en/menu_attachment_other.xml index 7ad692038e..22006c287f 100644 --- a/indra/newview/skins/default/xui/en/menu_attachment_other.xml +++ b/indra/newview/skins/default/xui/en/menu_attachment_other.xml @@ -131,22 +131,12 @@ - - - - + name="Render Avatar"> + label="Always full detail"> @@ -156,7 +146,7 @@ + label="Never full detail"> @@ -164,6 +154,16 @@ function="Avatar.SetImpostorMode" parameter="1" /> + + + + - - - - - - - - - - - - + name="Render Avatar"> + + + + + + + + + + + + - - -

- + + + + 360 Capture About land Outfits Complete avatars @@ -4154,6 +4156,8 @@ Try enclosing path to the editor with double quotes. Camera controls Voice settings + Capture a 360 panorama image Information about the land you're visiting Change your avatar Choose a complete avatar diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py index 41da8fa328..7e24c1f800 100755 --- a/indra/newview/viewer_manifest.py +++ b/indra/newview/viewer_manifest.py @@ -158,18 +158,12 @@ class ViewerManifest(LLManifest): self.path("*/xui/*/widgets/*.xml") self.path("*/*.xml") - # Local HTML files (e.g. loading screen) - # The claim is that we never use local html files any - # longer. But rather than commenting out this block, let's - # rename every html subdirectory as html.old. That way, if - # we're wrong, a user actually does have the relevant - # files; s/he just needs to rename every html.old - # directory back to html to recover them. - with self.prefix(src="*/html", dst="*/html.old"): - self.path("*.png") - self.path("*/*/*.html") - self.path("*/*/*.gif") - + # Update: 2017-11-01 CP Now we store app code in the html folder + # Initially the HTML/JS code to render equirectangular + # images for the 360 capture feature but more to follow. + with self.prefix(src="*/html", dst="*/html"): + self.path("*/*/*/*.js") + self.path("*/*/*.html") #build_data.json. Standard with exception handling is fine. If we can't open a new file for writing, we have worse problems #platform is computed above with other arg parsing From f78cb1c4ff7608a05976d6be7b568fbbbf36202b Mon Sep 17 00:00:00 2001 From: Callum Prentice Date: Fri, 20 Aug 2021 11:19:31 -0700 Subject: [PATCH 230/443] DRTVWR-534: collection of minor UI tweaks and fixes via XUI changes --- .../default/xui/en/floater_360capture.xml | 53 +++++++++++-------- .../skins/default/xui/en/menu_viewer.xml | 2 +- .../newview/skins/default/xui/en/strings.xml | 4 +- 3 files changed, 35 insertions(+), 24 deletions(-) diff --git a/indra/newview/skins/default/xui/en/floater_360capture.xml b/indra/newview/skins/default/xui/en/floater_360capture.xml index c2959b9853..f24639d81a 100644 --- a/indra/newview/skins/default/xui/en/floater_360capture.xml +++ b/indra/newview/skins/default/xui/en/floater_360capture.xml @@ -7,7 +7,7 @@ name="360capture" help_topic="360capture" save_rect="true" - title="360 Capture" + title="360 CAPTURE" width="800"> + name="ui_panel_left"> + - - - Target frame rate - - - Automatically tune display to give a smoother experience - - - - +top="115"> + top="115" /> + top="115" /> + top="115" /> + top="115" /> + diff --git a/indra/newview/skins/default/xui/en/menu_perf_avatar_rendering_settings.xml b/indra/newview/skins/default/xui/en/menu_perf_avatar_rendering_settings.xml new file mode 100644 index 0000000000..c60d72a587 --- /dev/null +++ b/indra/newview/skins/default/xui/en/menu_perf_avatar_rendering_settings.xml @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/indra/newview/skins/default/xui/en/panel_performance_complexity.xml b/indra/newview/skins/default/xui/en/panel_performance_complexity.xml index c7201d8385..5d1dc79386 100644 --- a/indra/newview/skins/default/xui/en/panel_performance_complexity.xml +++ b/indra/newview/skins/default/xui/en/panel_performance_complexity.xml @@ -42,67 +42,75 @@ top_pad="10" name="attachments_title" width="195"> - Your avatar complexity + Avatar complexity - Attachments make your avatar more complex. If your avatar is very complex, some other - - - people may not see you in full detail, and your graphics speed may be reduced. Removing - - - heavy attachments that you don’t need can help. - + follows="left|top" + font="SansSerifSmall" + text_color="White" + height="18" + layout="topleft" + top_pad="5" + left="20" + name="attachments_desc1" + width="580"> + Attachments make your avatar more complex and slower to render. + + +This screen allows you to view the attachments of your own avatar. + + +You may remove your own attachments quickly and easily by hitting the 'X'. + - - diff --git a/indra/newview/skins/default/xui/en/panel_performance_huds.xml b/indra/newview/skins/default/xui/en/panel_performance_huds.xml index 1ba3c85776..df8aa130d4 100644 --- a/indra/newview/skins/default/xui/en/panel_performance_huds.xml +++ b/indra/newview/skins/default/xui/en/panel_performance_huds.xml @@ -66,7 +66,7 @@ left="20" name="huds_desc2" width="540"> - Note: Using a HUD's minimize button does not detach it. + Note: Using a HUD's minimize button does not detach it. Use the X to remove it. 0 - - - - - + Reducing or turning off water effects can greatly improve frame rate. - - Date: Wed, 3 Nov 2021 19:35:30 +0000 Subject: [PATCH 317/443] Fix inherited bug in xml --- indra/newview/skins/default/xui/en/menu_attachment_other.xml | 1 - 1 file changed, 1 deletion(-) diff --git a/indra/newview/skins/default/xui/en/menu_attachment_other.xml b/indra/newview/skins/default/xui/en/menu_attachment_other.xml index 56ec6ad8d2..88a8ef12ce 100644 --- a/indra/newview/skins/default/xui/en/menu_attachment_other.xml +++ b/indra/newview/skins/default/xui/en/menu_attachment_other.xml @@ -206,7 +206,6 @@ function="Floater.ToggleOrBringToFront" parameter="avatar_render_settings" />
- Date: Wed, 3 Nov 2021 19:36:11 +0000 Subject: [PATCH 318/443] remove pointer no longer used for tracking attachments/huds --- indra/newview/llavatarrendernotifier.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/indra/newview/llavatarrendernotifier.h b/indra/newview/llavatarrendernotifier.h index e8077d55c0..658d696458 100644 --- a/indra/newview/llavatarrendernotifier.h +++ b/indra/newview/llavatarrendernotifier.h @@ -48,7 +48,6 @@ struct LLHUDComplexity objectName = ""; objectsCost = 0; objectsCount = 0; - objectPtr = nullptr; texturesCost = 0; texturesCount = 0; largeTexturesCount = 0; @@ -62,7 +61,6 @@ struct LLHUDComplexity U32 texturesCost; U32 texturesCount; U32 largeTexturesCount; - const LLViewerObject * objectPtr; F64Bytes texturesMemoryTotal; }; From 1fb8e1bc88ce65b5d58c61a0c4f80bb4ff33f186 Mon Sep 17 00:00:00 2001 From: Beq Date: Wed, 3 Nov 2021 19:37:17 +0000 Subject: [PATCH 319/443] add thread name (is this used though?) --- indra/llcorehttp/_thread.h | 5 +++++ 1 file changed, 5 insertions(+) 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(); From a37a36c40886ab8435da6c5b5dbe7bdb47803484 Mon Sep 17 00:00:00 2001 From: Andrey Lihatskiy Date: Thu, 4 Nov 2021 01:10:03 +0200 Subject: [PATCH 320/443] SL-16299 Updated dullahan to CT build 565428; entitlements cleanup --- autobuild.xml | 14 +++++++------- indra/newview/slplugin.entitlements | 4 ---- 2 files changed, 7 insertions(+), 11 deletions(-) diff --git a/autobuild.xml b/autobuild.xml index 59d65972f5..f43b277264 100644 --- a/autobuild.xml +++ b/autobuild.xml @@ -580,9 +580,9 @@ archive hash - 45dedb5b09995cd794304150e94fcf21 + 2653c3627fd8687ff9e003425fd14834 url - https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/87950/806969/dullahan-1.12.2.202109170444_91.1.21_g9dd45fe_chromium-91.0.4472.114-darwin64-563968.tar.bz2 + 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 @@ -592,9 +592,9 @@ archive hash - d0fd9d7086699da4bb5ccc935622a717 + b4003772562a5dd40bc112eec7cba5f5 url - https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/88276/809277/dullahan-1.12.2.202109230751_91.1.21_g9dd45fe_chromium-91.0.4472.114-windows-563968.tar.bz2 + 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 @@ -604,16 +604,16 @@ archive hash - 7e8c3ccd420ff5aef24ff72d609ba394 + d9030d7a7390b3bda7de2adcc27e535a url - https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/88275/809281/dullahan-1.12.2.202109230751_91.1.21_g9dd45fe_chromium-91.0.4472.114-windows64-563968.tar.bz2 + 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
version - 1.12.2.202109230751_91.1.21_g9dd45fe_chromium-91.0.4472.114 + 1.12.3.202111032221_91.1.21_g9dd45fe_chromium-91.0.4472.114 elfio diff --git a/indra/newview/slplugin.entitlements b/indra/newview/slplugin.entitlements index 1c2f2e5d2c..a72c6bc82c 100644 --- a/indra/newview/slplugin.entitlements +++ b/indra/newview/slplugin.entitlements @@ -10,10 +10,6 @@ com.apple.security.cs.disable-library-validation - com.apple.security.device.audio-input - - com.apple.security.device.camera - com.apple.security.cs.allow-dyld-environment-variables From b25a0055c271bc293935014170dd356a65761f4a Mon Sep 17 00:00:00 2001 From: Beq Date: Thu, 4 Nov 2021 01:54:30 +0000 Subject: [PATCH 321/443] fix sleep/limit detection --- indra/newview/fsperfstats.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/indra/newview/fsperfstats.cpp b/indra/newview/fsperfstats.cpp index a62559c335..aaab2770c5 100644 --- a/indra/newview/fsperfstats.cpp +++ b/indra/newview/fsperfstats.cpp @@ -101,6 +101,8 @@ namespace FSPerfStats 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) From f48cd18750dd9bc5b33c08f5eba6f6ed83c1d16a Mon Sep 17 00:00:00 2001 From: Beq Date: Thu, 4 Nov 2021 01:57:24 +0000 Subject: [PATCH 322/443] clean up performance display a little more --- indra/newview/fsfloaterperformance.cpp | 44 ++++++++++++++++++-------- indra/newview/fsfloaterperformance.h | 10 +++--- 2 files changed, 37 insertions(+), 17 deletions(-) diff --git a/indra/newview/fsfloaterperformance.cpp b/indra/newview/fsfloaterperformance.cpp index f21d9dfad1..4557891a55 100644 --- a/indra/newview/fsfloaterperformance.cpp +++ b/indra/newview/fsfloaterperformance.cpp @@ -24,7 +24,7 @@ */ #include "llviewerprecompiledheaders.h" -#include "llfloaterperformance.h" +#include "fsfloaterperformance.h" #include "llagent.h" #include "llagentcamera.h" @@ -229,8 +229,8 @@ void LLFloaterPerformance::draw() 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 NOT subtract the avatar time accumulated here as it was removed form the avatar time above - auto tot_idle_time_raw = FSPerfStats::StatsRecorder::getSceneStat(FSPerfStats::StatType_t::RENDER_IDLE); + // "idle" time. This is the time spent in the idle poll section of the main loop, we DO remove the avatar idel 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 @@ -459,10 +459,10 @@ void LLFloaterPerformance::populateObjectList() mObjectList->clearRows(); mObjectList->updateColumns(true); - object_complexity_list_t complexity_list = LLAvatarRenderNotifier::getInstance()->getObjectComplexityList(); + object_complexity_list_t attachment_list = LLAvatarRenderNotifier::getInstance()->getObjectComplexityList(); - object_complexity_list_t::iterator iter = complexity_list.begin(); - object_complexity_list_t::iterator end = complexity_list.end(); + object_complexity_list_t::iterator iter = attachment_list.begin(); + object_complexity_list_t::iterator end = attachment_list.end(); U32 max_complexity = 0; @@ -471,17 +471,20 @@ void LLFloaterPerformance::populateObjectList() 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 = complexity_list.begin(); iter != end; ++iter) + for (iter = attachment_list.begin(); iter != end; ++iter) { - LLObjectComplexity object_complexity = *iter; - S32 obj_cost_short = llmax((S32)object_complexity.objectCost / 1000, 1); + LLObjectComplexity attachment_complexity = *iter; + S32 obj_cost_short = llmax((S32)attachment_complexity.objectCost / 1000, 1); - auto& attID{object_complexity.objectId}; - auto& attName{object_complexity.objectName}; + 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; @@ -522,11 +525,19 @@ void LLFloaterPerformance::populateObjectList() } } } + + 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 LLFloaterPerformance::populateNearbyList() @@ -555,10 +566,11 @@ void LLFloaterPerformance::populateNearbyList() 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()); + // 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()) { @@ -682,6 +694,12 @@ void LLFloaterPerformance::populateNearbyList() 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 LLFloaterPerformance::getNearbyAvatars(std::vector &valid_nearby_avs) diff --git a/indra/newview/fsfloaterperformance.h b/indra/newview/fsfloaterperformance.h index 1fdbe4686f..46f0dae430 100644 --- a/indra/newview/fsfloaterperformance.h +++ b/indra/newview/fsfloaterperformance.h @@ -1,6 +1,8 @@ /** - * @file llfloaterperformance.h + * @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. @@ -23,8 +25,8 @@ * $/LicenseInfo$ */ -#ifndef LL_LLFLOATERPERFORMANCE_H -#define LL_LLFLOATERPERFORMANCE_H +#ifndef FS_FLOATERPERFORMANCE_H +#define FS_FSFLOATERPERFORMANCE_H #include "llfloater.h" #include "lllistcontextmenu.h" @@ -94,4 +96,4 @@ private: boost::signals2::connection mMaxARTChangedSignal; }; -#endif // LL_LLFLOATERPERFORMANCE_H +#endif // FS_FLOATERPERFORMANCE_H From 530666c9a309cc0c57014ecad7d52c4ca4e5a981 Mon Sep 17 00:00:00 2001 From: Beq Date: Thu, 4 Nov 2021 01:58:00 +0000 Subject: [PATCH 323/443] add summary stats --- .../default/xui/en/floater_performance.xml | 6 +++ .../xui/en/panel_performance_complexity.xml | 17 +++++++- .../xui/en/panel_performance_nearby.xml | 41 ++++++++++++------- 3 files changed, 48 insertions(+), 16 deletions(-) diff --git a/indra/newview/skins/default/xui/en/floater_performance.xml b/indra/newview/skins/default/xui/en/floater_performance.xml index 5ca24181e3..8ead5d0ac3 100644 --- a/indra/newview/skins/default/xui/en/floater_performance.xml +++ b/indra/newview/skins/default/xui/en/floater_performance.xml @@ -23,6 +23,12 @@ In Background + + + Total: [TOT_AV] ([TOT_AV_TIME]μs) + + + Total: [TOT_ATT] ([TOT_ATT_TIME]μs) - Avatar complexity + width="250"> + Avatar attachment complexity + + + Total: 50 (120000.10μs) +bevel_style="none" +follows="left|top" +height="530" +width="580" +name="panel_performance_nearby" +layout="topleft" +left="0" +top="0"> - + Back - + Avatar attachment complexity - + Total: 50 (120000.10μs) - + Attachments make your avatar more complex and slower to render. - - + + This screen allows you to view the attachments of your own avatar. - - + + You may remove your own attachments quickly and easily by hitting the 'X'. - - + - - - - + + + + diff --git a/indra/newview/skins/default/xui/en/panel_performance_huds.xml b/indra/newview/skins/default/xui/en/panel_performance_huds.xml index df8aa130d4..ee0be6ac96 100644 --- a/indra/newview/skins/default/xui/en/panel_performance_huds.xml +++ b/indra/newview/skins/default/xui/en/panel_performance_huds.xml @@ -1,15 +1,13 @@ - - - + Back - + Your active HUDs - - Detaching HUDs you aren't using saves memory and can make Second Life run faster. + + Detaching HUDs you aren't using saves memory and can make the viewer run faster. - + + HUDs are often heavily scripted and also contribute to server-side lag. + + Note: Using a HUD's minimize button does not detach it. Use the X to remove it. - - - - + + + + diff --git a/indra/newview/skins/default/xui/en/panel_performance_nearby.xml b/indra/newview/skins/default/xui/en/panel_performance_nearby.xml index 0c98e2c7f6..ee17d7a866 100644 --- a/indra/newview/skins/default/xui/en/panel_performance_nearby.xml +++ b/indra/newview/skins/default/xui/en/panel_performance_nearby.xml @@ -42,8 +42,7 @@ top="0"> top_pad="10" name="av_nearby_title" width="205"> - Avatars nearby - + Avatars nearby width="40" /> - Graphics settings + Graphics settings - From 38f2d8076f144dd33defe17a391144cb3554bd36 Mon Sep 17 00:00:00 2001 From: Beq Date: Fri, 5 Nov 2021 17:14:23 +0000 Subject: [PATCH 329/443] Add HUD stats and fix double count of self rigged attachment --- indra/newview/fsperfstats.cpp | 6 ++- indra/newview/fsperfstats.h | 91 ++++++++++++++++++++++++++--------- 2 files changed, 73 insertions(+), 24 deletions(-) diff --git a/indra/newview/fsperfstats.cpp b/indra/newview/fsperfstats.cpp index aaab2770c5..3a769cd261 100644 --- a/indra/newview/fsperfstats.cpp +++ b/indra/newview/fsperfstats.cpp @@ -37,6 +37,10 @@ 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 @@ -51,7 +55,7 @@ namespace FSPerfStats std::atomic StatsRecorder::writeBuffer{0}; bool StatsRecorder::collectionEnabled{true}; - LLUUID StatsRecorder::focusAv{LLUUID::null}; + LLUUID StatsRecorder::focusAv{LLUUID::null}; std::array StatsRecorder::statsDoubleBuffer{ {} }; std::array StatsRecorder::max{ {} }; std::array StatsRecorder::sum{ {} }; diff --git a/indra/newview/fsperfstats.h b/indra/newview/fsperfstats.h index 93a137f86c..acf038865c 100644 --- a/indra/newview/fsperfstats.h +++ b/indra/newview/fsperfstats.h @@ -57,6 +57,10 @@ 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 extern std::atomic tunedAvatars; extern U32 targetFPS; // desired FPS @@ -101,8 +105,8 @@ namespace FSPerfStats LLUUID avID; LLUUID objID; uint64_t time; - uint32_t count; bool isRigged; + bool isHUD; }; class StatsRecorder{ @@ -211,7 +215,7 @@ namespace FSPerfStats if(ot == ObjType_t::OT_ATTACHMENT) { - if( !upd.isRigged ) + 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); @@ -219,6 +223,10 @@ namespace FSPerfStats 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); } @@ -263,12 +271,13 @@ namespace FSPerfStats auto& instance {StatsRecorder::getInstance()}; FSThreadName( "PerfStats" ); - while( !LLApp::isExiting() ) + while( enabled() && !LLApp::isExiting() ) { FSZone("perf batch"); - auto count = instance.q.wait_dequeue_bulk_timed(upd, 10, std::chrono::milliseconds(5)); + auto count = instance.q.wait_dequeue_bulk_timed(upd, 10, std::chrono::milliseconds(10)); if(count) { + FSZoneValue(count); // LL_INFOS("perfstats") << "processing " << count << " updates." << LL_ENDL; for(auto i =0; i < count; i++) { @@ -298,21 +307,30 @@ namespace FSPerfStats public: StatsRecord stat; - RecordTime( const LLUUID& av, const LLUUID& id, StatType_t type, bool isRiggedAtt=false):start{LLTrace::BlockTimer::getCPUClockCount64()}, - stat{type, ObjTypeDiscriminator, std::move(av), std::move(id), 0, isRiggedAtt}{ + 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(FSPerfStats::inUse){FSZoneText("OVERLAP ATT",11);} if(!stat.isRigged && FSPerfStats::inUseAvatar){FSZoneText("OVERLAP AVATAR",14);} - FSPlot("InUse", (int64_t)FSPerfStats::inUse); - FSPlot("InUseAv", (int64_t)FSPerfStats::inUseAvatar); + FSPlotSq("InUse", (int64_t)FSPerfStats::inUse, (int64_t)FSPerfStats::inUse+1); FSPerfStats::inUse++; - if( !stat.isRigged ) {FSPerfStats::inUseAvatar++;}; - FSPlot("InUse", (int64_t)FSPerfStats::inUse); - FSPlot("InUseAv", (int64_t)FSPerfStats::inUseAvatar); + 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 @@ -322,6 +340,12 @@ namespace FSPerfStats 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 < typename = std::enable_if_t > @@ -332,9 +356,11 @@ namespace FSPerfStats #ifdef USAGE_TRACKING if(FSPerfStats::inUseAvatar){FSZoneText("OVERLAP AVATAR",14);} - FSPlot("InUseAv", (int64_t)FSPerfStats::inUseAvatar); + FSPlotSq("InUseAv", (int64_t)FSPerfStats::inUseAvatar, (int64_t)FSPerfStats::inUseAvatar+1); FSPerfStats::inUseAvatar++; - FSPlot("InUseAv", (int64_t)FSPerfStats::inUseAvatar); + FSPlotSq("InUse", (int64_t)FSPerfStats::inUse, (int64_t)FSPerfStats::inUse+1); + FSPerfStats::inUse++; + #endif }; @@ -350,20 +376,34 @@ namespace FSPerfStats 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) { - FSPlot("InUse", (int64_t)FSPerfStats::inUse); - --FSPerfStats::inUse; - FSPlot("InUse", (int64_t)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; + } } - if( ( stat.objType == FSPerfStats::ObjType_t::OT_ATTACHMENT && !stat.isRigged ) || stat.objType == FSPerfStats::ObjType_t::OT_AVATAR ) + if (stat.objType == FSPerfStats::ObjType_t::OT_GENERAL) { - FSPlot("InUseAv", (int64_t)FSPerfStats::inUseAvatar); + 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; - FSPlot("InUseAv", (int64_t)FSPerfStats::inUseAvatar); } #endif - stat.time = LLTrace::BlockTimer::getCPUClockCount64() - start; #ifdef ATTACHMENT_TRACKING @@ -389,6 +429,7 @@ namespace FSPerfStats using RecordSceneTime = RecordTime; using RecordAvatarTime = RecordTime; using RecordAttachmentTime = RecordTime; + using RecordHudAttachmentTime = RecordTime; };// namespace FSPerfStats @@ -421,6 +462,7 @@ static inline void trackAttachments(const T * vobj, bool isRigged, RATptr* ratPt 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]; @@ -429,9 +471,12 @@ static inline void trackAttachments(const T * vobj, bool isRigged, RATptr* ratPt 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 ); + *ratPtrp = std::make_unique( av, + obj, + ( (LLPipeline::sShadowRender)?FSPerfStats::StatType_t::RENDER_SHADOWS : FSPerfStats::StatType_t::RENDER_GEOMETRY ), + isRigged, + rootAtt->isHUDAttachment()); } - (*ratPtrp)->stat.count++; } return; }; From 233739879bd3c878cb82f8c744a133f79bca9768 Mon Sep 17 00:00:00 2001 From: Beq Date: Fri, 5 Nov 2021 17:15:27 +0000 Subject: [PATCH 330/443] Add debug control to disable perfstats --- indra/newview/llappviewer.cpp | 10 +++++++--- indra/newview/llviewercontrol.cpp | 6 ++++++ 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index e31dfb5968..f8c2821bb6 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -1633,7 +1633,8 @@ bool LLAppViewer::frame() bool LLAppViewer::doFrame() { - { +// Perfstats collection Frame boundary +{ FSPerfStats::RecordSceneTime T (FSPerfStats::StatType_t::RENDER_FRAME); LLEventPump& mainloop(LLEventPumps::instance().obtain("mainloop")); @@ -1670,6 +1671,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(); @@ -1678,8 +1680,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) @@ -1744,7 +1747,7 @@ bool LLAppViewer::doFrame() FSZoneN("Main:Coro"); llcoro::suspend(); } - + }// ensure we have the entire top scope of frame covered if (!LLApp::isExiting()) { pingMainloopTimeout("Main:JoystickKeyboard"); @@ -1825,6 +1828,7 @@ bool LLAppViewer::doFrame() pingMainloopTimeout("Main:Snapshot"); { + FSPerfStats::RecordSceneTime T (FSPerfStats::StatType_t::RENDER_IDLE); FSZoneN("Main:Snapshot"); LLFloaterSnapshot::update(); // take snapshots LLFloaterOutfitSnapshot::update(); diff --git a/indra/newview/llviewercontrol.cpp b/indra/newview/llviewercontrol.cpp index 7893b557f6..54a08e6084 100644 --- a/indra/newview/llviewercontrol.cpp +++ b/indra/newview/llviewercontrol.cpp @@ -1092,6 +1092,11 @@ 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); +} // //////////////////////////////////////////////////////////////////////////// @@ -1355,6 +1360,7 @@ void settings_setup_listeners() gSavedSettings.getControl("FSRenderAvatarMaxART")->getSignal()->connect(boost::bind(&handleRenderAvatarMaxARTChanged, _2)); gSavedSettings.getControl("FSRenderAvatarMaxART")->getSignal()->connect(boost::bind(&handlePerfSmoothingPeriodsChanged, _2)); gSavedSettings.getControl("FSTuningFPSStrategy")->getSignal()->connect(boost::bind(&handleFPSTuningStrategyChanged, _2)); + gSavedSettings.getControl("FSPerfStatsCaptureEnabled")->getSignal()->connect(boost::bind(&handlePerformanceStatsEnabledChanged, _2)); // } From cca11975d69d98d2912f6e82a5574c0f3e98d58e Mon Sep 17 00:00:00 2001 From: Beq Date: Sat, 6 Nov 2021 00:41:48 +0000 Subject: [PATCH 331/443] Fixup class scope to help Linux builds and another Linux friendly fixup --- indra/llcommon/lluuid.h | 4 ++-- indra/newview/fsperfstats.h | 4 +++- indra/newview/llvoavatar.h | 2 +- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/indra/llcommon/lluuid.h b/indra/llcommon/lluuid.h index 270a8e7f06..32f8b6c7c2 100644 --- a/indra/llcommon/lluuid.h +++ b/indra/llcommon/lluuid.h @@ -118,7 +118,7 @@ public: // 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 * LLUUID::toShortString(char *out) const + inline char * toShortString(char *out) const { FSZone; out[0] = hexnybl(mData[14]>>4); @@ -128,7 +128,7 @@ public: return out; } // full uuid - Much lighterweight than default, no allocation, or nul-term added - provide your own, ensure min 36 bytes. - inline char * LLUUID::toStringFast(char *out) const + inline char * toStringFast(char *out) const { FSZone; out[0] = hexnybl(mData[0]>>4); diff --git a/indra/newview/fsperfstats.h b/indra/newview/fsperfstats.h index acf038865c..ad5a784058 100644 --- a/indra/newview/fsperfstats.h +++ b/indra/newview/fsperfstats.h @@ -70,6 +70,8 @@ namespace FSPerfStats extern std::mutex bufferToggleLock; extern bool autoTune; + constexpr U64 ART_UNLIMITED{50000}; + extern U32 smoothingPeriods; // number of frames to smooth over. enum class ObjType_t{ @@ -150,7 +152,7 @@ namespace FSPerfStats return max[getReadBufferIndex()][static_cast(otype)][static_cast(type)]; } - static void StatsRecorder::updateAvatarParams(); + static void updateAvatarParams(); private: StatsRecorder(); diff --git a/indra/newview/llvoavatar.h b/indra/newview/llvoavatar.h index a1747f890d..4b00beae29 100644 --- a/indra/newview/llvoavatar.h +++ b/indra/newview/llvoavatar.h @@ -378,7 +378,7 @@ public: { return(combined?mTooSlow:mTooSlowWithoutShadows); } - void LLVOAvatar::updateTooSlow(); + void updateTooSlow(); // virtual bool isTooComplex() const; // FIRE-29012: Standalone animesh avatars get affected by complexity limit; changed to virtual bool visualParamWeightsAreDefault(); From 0758eda68867c2b34279d8c21ec1ab5c2b59b779 Mon Sep 17 00:00:00 2001 From: Beq Date: Sat, 6 Nov 2021 03:09:12 +0000 Subject: [PATCH 332/443] Fixes for cross compiler compatability also remove now unused timer --- indra/newview/fsfloaterperformance.cpp | 5 ----- indra/newview/fsperfstats.h | 9 ++++++--- indra/newview/pipeline.cpp | 2 +- 3 files changed, 7 insertions(+), 9 deletions(-) diff --git a/indra/newview/fsfloaterperformance.cpp b/indra/newview/fsfloaterperformance.cpp index 115cef25ac..29802da272 100644 --- a/indra/newview/fsfloaterperformance.cpp +++ b/indra/newview/fsfloaterperformance.cpp @@ -202,7 +202,6 @@ void LLFloaterPerformance::draw() gSavedSettings.setU32("FSRenderAvatarMaxART", FSPerfStats::renderAvatarMaxART); } - static auto freq_divisor = get_timer_info().mClockFrequencyInv; if (mUpdateTimer->hasExpired()) { @@ -397,8 +396,6 @@ void LLFloaterPerformance::populateHUDList() hud_complexity_list_t::iterator iter = complexity_list.begin(); hud_complexity_list_t::iterator end = complexity_list.end(); - static auto freq_divisor = get_timer_info().mClockFrequencyInv; - U32 max_complexity = 0; for (; iter != end; ++iter) { @@ -471,8 +468,6 @@ void LLFloaterPerformance::populateHUDList() void LLFloaterPerformance::populateObjectList() { - static auto freq_divisor = get_timer_info().mClockFrequencyInv; - S32 prev_pos = mObjectList->getScrollPos(); auto prev_selected_id = mObjectList->getSelectedSpecialId(); diff --git a/indra/newview/fsperfstats.h b/indra/newview/fsperfstats.h index ad5a784058..89b73cdfd2 100644 --- a/indra/newview/fsperfstats.h +++ b/indra/newview/fsperfstats.h @@ -38,6 +38,7 @@ #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 @@ -275,7 +276,7 @@ namespace FSPerfStats while( enabled() && !LLApp::isExiting() ) { - FSZone("perf batch"); + FSZoneN("perf batch"); auto count = instance.q.wait_dequeue_bulk_timed(upd, 10, std::chrono::milliseconds(10)); if(count) { @@ -338,7 +339,8 @@ namespace FSPerfStats }; - template < typename = std::enable_if_t > + template < ObjType_t OD = ObjTypeDiscriminator, + std::enable_if_t * = nullptr> RecordTime( StatType_t type ):RecordTime(LLUUID::null, LLUUID::null, type ) { FSZone; @@ -350,7 +352,8 @@ namespace FSPerfStats #endif }; - template < typename = std::enable_if_t > + 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); diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp index 49be260468..79afeeae73 100644 --- a/indra/newview/pipeline.cpp +++ b/indra/newview/pipeline.cpp @@ -4055,7 +4055,7 @@ void LLPipeline::postSort(LLCamera& camera) if (hasRenderType(LLPipeline::RENDER_TYPE_PASS_ALPHA)) { - FSZone("Collect Alpha groups"); + FSZoneN("Collect Alpha groups"); LLSpatialGroup::draw_map_t::iterator alpha = group->mDrawMap.find(LLRenderPass::PASS_ALPHA); if (alpha != group->mDrawMap.end()) From e3c223675a9aedf9fa28fd376f3e939277878421 Mon Sep 17 00:00:00 2001 From: Ansariel Date: Sat, 6 Nov 2021 19:42:52 +0100 Subject: [PATCH 333/443] Fix some broken mess... --- .../default/xui/en/menu_attachment_other.xml | 29 +++++++------------ .../default/xui/en/menu_avatar_other.xml | 9 +----- 2 files changed, 12 insertions(+), 26 deletions(-) diff --git a/indra/newview/skins/default/xui/en/menu_attachment_other.xml b/indra/newview/skins/default/xui/en/menu_attachment_other.xml index 88a8ef12ce..7bf0beb2c0 100644 --- a/indra/newview/skins/default/xui/en/menu_attachment_other.xml +++ b/indra/newview/skins/default/xui/en/menu_attachment_other.xml @@ -183,29 +183,22 @@ label="Never Display Full Detail"> - + parameter="1" /> + - + - + - - - - + - - - - + Date: Sat, 6 Nov 2021 20:47:49 +0100 Subject: [PATCH 334/443] Small fix for panel_performance_preferences.xml - translations --- .../skins/default/xui/en/panel_performance_preferences.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/indra/newview/skins/default/xui/en/panel_performance_preferences.xml b/indra/newview/skins/default/xui/en/panel_performance_preferences.xml index 7018b2c36e..d825a9ecfd 100644 --- a/indra/newview/skins/default/xui/en/panel_performance_preferences.xml +++ b/indra/newview/skins/default/xui/en/panel_performance_preferences.xml @@ -437,11 +437,11 @@ the ambience and appearance of the scene. width="150"> Date: Sun, 7 Nov 2021 00:00:55 +0100 Subject: [PATCH 335/443] Updated Polish translation (performance floater) --- .../xui/en/panel_performance_nearby.xml | 8 +- .../xui/pl/floater_avatar_render_settings.xml | 10 +- .../pl/floater_fs_avatar_render_settings.xml | 4 +- .../default/xui/pl/floater_performance.xml | 95 +++++++++++++++++++ .../floater_preferences_graphics_advanced.xml | 2 +- .../default/xui/pl/menu_attachment_other.xml | 6 +- .../default/xui/pl/menu_avatar_other.xml | 6 +- .../xui/pl/menu_avatar_rendering_settings.xml | 6 +- .../pl/menu_avatar_rendering_settings_add.xml | 4 +- .../xui/pl/menu_fs_avatar_render_setting.xml | 6 +- .../menu_perf_avatar_rendering_settings.xml | 8 ++ .../skins/default/xui/pl/menu_viewer.xml | 1 + .../xui/pl/panel_performance_complexity.xml | 23 +++++ .../default/xui/pl/panel_performance_huds.xml | 23 +++++ .../xui/pl/panel_performance_nearby.xml | 38 ++++++++ .../xui/pl/panel_performance_preferences.xml | 84 ++++++++++++++++ .../newview/skins/default/xui/pl/strings.xml | 6 ++ 17 files changed, 304 insertions(+), 26 deletions(-) create mode 100644 indra/newview/skins/default/xui/pl/floater_performance.xml create mode 100644 indra/newview/skins/default/xui/pl/menu_perf_avatar_rendering_settings.xml create mode 100644 indra/newview/skins/default/xui/pl/panel_performance_complexity.xml create mode 100644 indra/newview/skins/default/xui/pl/panel_performance_huds.xml create mode 100644 indra/newview/skins/default/xui/pl/panel_performance_nearby.xml create mode 100644 indra/newview/skins/default/xui/pl/panel_performance_preferences.xml diff --git a/indra/newview/skins/default/xui/en/panel_performance_nearby.xml b/indra/newview/skins/default/xui/en/panel_performance_nearby.xml index ee17d7a866..0f540f921e 100644 --- a/indra/newview/skins/default/xui/en/panel_performance_nearby.xml +++ b/indra/newview/skins/default/xui/en/panel_performance_nearby.xml @@ -149,12 +149,12 @@ top="0"> width="540"> width="40" /> value="2" width="160" /> - + diff --git a/indra/newview/skins/default/xui/pl/floater_avatar_render_settings.xml b/indra/newview/skins/default/xui/pl/floater_avatar_render_settings.xml index 02fee6b3a1..210e5adfc4 100644 --- a/indra/newview/skins/default/xui/pl/floater_avatar_render_settings.xml +++ b/indra/newview/skins/default/xui/pl/floater_avatar_render_settings.xml @@ -1,12 +1,12 @@ - + - - - - + + + + diff --git a/indra/newview/skins/default/xui/pl/floater_fs_avatar_render_settings.xml b/indra/newview/skins/default/xui/pl/floater_fs_avatar_render_settings.xml index a0004117ba..53e1b09282 100644 --- a/indra/newview/skins/default/xui/pl/floater_fs_avatar_render_settings.xml +++ b/indra/newview/skins/default/xui/pl/floater_fs_avatar_render_settings.xml @@ -1,5 +1,5 @@ - + Nigdy @@ -10,7 +10,7 @@ - + From 8dd9554eb504e43e392b858003914be3210ba91e Mon Sep 17 00:00:00 2001 From: Andrey Lihatskiy Date: Tue, 9 Nov 2021 02:38:58 +0200 Subject: [PATCH 341/443] SL-16333 VLC 3 doesn't support -1 == infinity for input-repeat by Callum --- indra/media_plugins/libvlc/media_plugin_libvlc.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/indra/media_plugins/libvlc/media_plugin_libvlc.cpp b/indra/media_plugins/libvlc/media_plugin_libvlc.cpp index ce0947a1bc..1afe25e9a1 100644 --- a/indra/media_plugins/libvlc/media_plugin_libvlc.cpp +++ b/indra/media_plugins/libvlc/media_plugin_libvlc.cpp @@ -354,7 +354,7 @@ void MediaPluginLibVLC::playMedia() // 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); From 634f360ea01b0e753720733cc63525bd6b727d46 Mon Sep 17 00:00:00 2001 From: Ansariel Date: Tue, 9 Nov 2021 15:59:00 +0100 Subject: [PATCH 342/443] Layout fixes for performance floater. Also fixed strange and obscure wordings: * There is no "conventional" or "old-school" ARC - it's still the default measurement -> away with that * JellyDolls don't exist - they are Impostor * Remove SL reference * Replace "Firestorm" with [APP_NAME] substitute --- .../default/xui/en/floater_performance.xml | 35 +++++++------------ .../xui/en/panel_performance_complexity.xml | 4 +-- .../default/xui/en/panel_performance_huds.xml | 8 ++--- .../xui/en/panel_performance_nearby.xml | 4 +-- .../xui/en/panel_performance_preferences.xml | 15 ++++---- 5 files changed, 30 insertions(+), 36 deletions(-) diff --git a/indra/newview/skins/default/xui/en/floater_performance.xml b/indra/newview/skins/default/xui/en/floater_performance.xml index 88c0e71c5c..e09176eac4 100644 --- a/indra/newview/skins/default/xui/en/floater_performance.xml +++ b/indra/newview/skins/default/xui/en/floater_performance.xml @@ -91,24 +91,15 @@ - Allow 5-10 seconds for + width="150" + wrap="true"> + Allow 5-10 seconds for changes to take full effect. - - changes to take full effect. - + width="240"> Auto-Tune Frame Rate @@ -315,7 +306,7 @@ top="115"> left="10" name="avatars_nearby_desc" top_pad="0" - width="305"> + width="345"> Manage which nearby avatars are fully displayed. text_color="White" height="28" layout="topleft" - left_pad="50" + left_pad="10" name="avatars_frme_pct_lbl" top="8" width="75"> @@ -433,7 +424,7 @@ avatars left="10" name="huds_desc" top_pad="0" - width="305"> + width="345"> Removing unnecessary HUDs may improve speed. diff --git a/indra/newview/skins/default/xui/en/panel_performance_complexity.xml b/indra/newview/skins/default/xui/en/panel_performance_complexity.xml index ddf680460a..7518328a35 100644 --- a/indra/newview/skins/default/xui/en/panel_performance_complexity.xml +++ b/indra/newview/skins/default/xui/en/panel_performance_complexity.xml @@ -107,10 +107,10 @@ You may remove your own attachments quickly and easily by hitting the 'X'. width="80" /> diff --git a/indra/newview/skins/default/xui/en/panel_performance_huds.xml b/indra/newview/skins/default/xui/en/panel_performance_huds.xml index ee0be6ac96..398f9a20bb 100644 --- a/indra/newview/skins/default/xui/en/panel_performance_huds.xml +++ b/indra/newview/skins/default/xui/en/panel_performance_huds.xml @@ -77,7 +77,7 @@ column_padding="1" draw_stripes="true" draw_heading="true" - height="400" + height="380" follows="left|top" layout="topleft" name="hud_list" @@ -90,16 +90,16 @@ diff --git a/indra/newview/skins/default/xui/en/panel_performance_nearby.xml b/indra/newview/skins/default/xui/en/panel_performance_nearby.xml index 53c1df0292..047edb7ed4 100644 --- a/indra/newview/skins/default/xui/en/panel_performance_nearby.xml +++ b/indra/newview/skins/default/xui/en/panel_performance_nearby.xml @@ -71,7 +71,7 @@ top="0"> width="80" /> + width="100" + wrap="true"> Quality vs speed + width="100" + wrap="true"> Visibility distance + width="40" + top_delta="0"> Faster Photographers need high quality, but this is often -at the cost of frame rate. Firestorm phototools can +at the cost of frame rate. [APP_NAME] phototools can help you find the right balance. + + Back + + +Auto Tune Preferences + + + +Distant Avatars + + + + + +Avatars that are further away still have a high impact. +Control how far away an avatar should before being optimized. + + + +Visibility distance tuning limits + + + + + + +When adjusting scene parameters, autotune will optimise draw distance to between the minimum and the preferred. + + From 1363016bb27ff53d0ae7dd32c2c542c5339324df Mon Sep 17 00:00:00 2001 From: PanteraPolnocy Date: Wed, 10 Nov 2021 12:47:03 +0100 Subject: [PATCH 353/443] Updated Polish translation, minor translatability fixes --- .../menu_perf_avatar_rendering_settings.xml | 2 +- .../xui/en/panel_performance_autotune.xml | 4 +-- .../default/xui/pl/floater_performance.xml | 9 +++---- .../menu_perf_avatar_rendering_settings.xml | 2 +- .../xui/pl/panel_performance_autotune.xml | 26 +++++++++++++++++++ .../xui/pl/panel_performance_complexity.xml | 2 +- .../default/xui/pl/panel_performance_huds.xml | 4 +-- .../xui/pl/panel_performance_nearby.xml | 4 +-- .../xui/pl/panel_performance_preferences.xml | 2 +- 9 files changed, 39 insertions(+), 16 deletions(-) create mode 100644 indra/newview/skins/default/xui/pl/panel_performance_autotune.xml diff --git a/indra/newview/skins/default/xui/en/menu_perf_avatar_rendering_settings.xml b/indra/newview/skins/default/xui/en/menu_perf_avatar_rendering_settings.xml index 6a01242afd..5bde641b5c 100644 --- a/indra/newview/skins/default/xui/en/menu_perf_avatar_rendering_settings.xml +++ b/indra/newview/skins/default/xui/en/menu_perf_avatar_rendering_settings.xml @@ -33,7 +33,7 @@ diff --git a/indra/newview/skins/default/xui/en/panel_performance_autotune.xml b/indra/newview/skins/default/xui/en/panel_performance_autotune.xml index 299fac6771..0f2f3b052a 100644 --- a/indra/newview/skins/default/xui/en/panel_performance_autotune.xml +++ b/indra/newview/skins/default/xui/en/panel_performance_autotune.xml @@ -84,7 +84,7 @@ Distant Avatars label_width="80" label_wrap="true" follows="top|left" - name="min_dd_autotune" + name="ffa_autotune" left_pad="40" decimal_digits="2" min_val="16" @@ -149,7 +149,7 @@ Visibility distance tuning limits label_width="80" label_wrap="true" follows="top|left" - name="min_dd_autotune" + name="pref_dd_autotune" left_pad="20" min_val="32" max_val="256" diff --git a/indra/newview/skins/default/xui/pl/floater_performance.xml b/indra/newview/skins/default/xui/pl/floater_performance.xml index 143e0f54d9..d0040d839d 100644 --- a/indra/newview/skins/default/xui/pl/floater_performance.xml +++ b/indra/newview/skins/default/xui/pl/floater_performance.xml @@ -24,10 +24,7 @@ klatek na sekundę - Poczekaj 5-10 sekund, by - - - nastąpiły zmiany. + Poczekaj 5-10 sekund, by nastąpiły zmiany. Tutaj pojawi się analiza klatek. @@ -37,7 +34,7 @@ Autostrojenie klatek - + Autostrojenie ustawień, by utrzymać FPS. @@ -45,7 +42,7 @@ - + diff --git a/indra/newview/skins/default/xui/pl/menu_perf_avatar_rendering_settings.xml b/indra/newview/skins/default/xui/pl/menu_perf_avatar_rendering_settings.xml index 80d472f226..8c0137fc68 100644 --- a/indra/newview/skins/default/xui/pl/menu_perf_avatar_rendering_settings.xml +++ b/indra/newview/skins/default/xui/pl/menu_perf_avatar_rendering_settings.xml @@ -4,5 +4,5 @@ - + diff --git a/indra/newview/skins/default/xui/pl/panel_performance_autotune.xml b/indra/newview/skins/default/xui/pl/panel_performance_autotune.xml new file mode 100644 index 0000000000..94bbb8f04f --- /dev/null +++ b/indra/newview/skins/default/xui/pl/panel_performance_autotune.xml @@ -0,0 +1,26 @@ + + + + Wstecz + + + Opcje autostrojenia + + + Odległe awatary + + + + +Awatary, które są dalej, nadal wpływają na renderowanie. +Określ odległość po której awatar zostanie zoptymalizowany. + + + Limity dostrajania pola widzenia + + + + + Podczas przetwarzania sceny autostrojenie zoptymalizuje pole widzenia między minimalnym a preferowanym. + + diff --git a/indra/newview/skins/default/xui/pl/panel_performance_complexity.xml b/indra/newview/skins/default/xui/pl/panel_performance_complexity.xml index 43d66032ed..eb0561dfe0 100644 --- a/indra/newview/skins/default/xui/pl/panel_performance_complexity.xml +++ b/indra/newview/skins/default/xui/pl/panel_performance_complexity.xml @@ -17,7 +17,7 @@ - + diff --git a/indra/newview/skins/default/xui/pl/panel_performance_huds.xml b/indra/newview/skins/default/xui/pl/panel_performance_huds.xml index 3590d2bc9b..16481fff80 100644 --- a/indra/newview/skins/default/xui/pl/panel_performance_huds.xml +++ b/indra/newview/skins/default/xui/pl/panel_performance_huds.xml @@ -16,8 +16,8 @@ Uwaga: Minimalizacja HUDa nie powoduje jego odłączenia. Użyj X, aby go usunąć. - - + + diff --git a/indra/newview/skins/default/xui/pl/panel_performance_nearby.xml b/indra/newview/skins/default/xui/pl/panel_performance_nearby.xml index e8aa88809f..047c28aa5e 100644 --- a/indra/newview/skins/default/xui/pl/panel_performance_nearby.xml +++ b/indra/newview/skins/default/xui/pl/panel_performance_nearby.xml @@ -9,7 +9,7 @@ Ukryj najbardziej złożone awatary, aby zwiększyć szybkość. - + bez limitu @@ -17,7 +17,7 @@ - + diff --git a/indra/newview/skins/default/xui/pl/panel_performance_preferences.xml b/indra/newview/skins/default/xui/pl/panel_performance_preferences.xml index b735b16555..f1fcaa1c97 100644 --- a/indra/newview/skins/default/xui/pl/panel_performance_preferences.xml +++ b/indra/newview/skins/default/xui/pl/panel_performance_preferences.xml @@ -78,7 +78,7 @@ ale wpływa na atmosferę i wygląd sceny. Fotografowie wymagają lepszej jakości, często dzieje się to kosztem liczby klatek na sekundę. -Narzędzia Firestorma pomogą znaleźć równowagę. +Narzędzia [APP_NAME] pomogą znaleźć równowagę. - - + + top="60" /> + top="60" /> + top="60" /> + top="60" /> + top="60" /> diff --git a/indra/newview/skins/default/xui/en/panel_performance_autotune.xml b/indra/newview/skins/default/xui/en/panel_performance_autotune.xml index 0c96d9eeea..41c9f266af 100644 --- a/indra/newview/skins/default/xui/en/panel_performance_autotune.xml +++ b/indra/newview/skins/default/xui/en/panel_performance_autotune.xml @@ -2,7 +2,7 @@ column_padding="1" draw_stripes="true" draw_heading="true" - height="280" + height="335" left="20" follows="left|top" layout="topleft" diff --git a/indra/newview/skins/default/xui/en/panel_performance_preferences.xml b/indra/newview/skins/default/xui/en/panel_performance_preferences.xml index 8fbff6a4db..369615e235 100644 --- a/indra/newview/skins/default/xui/en/panel_performance_preferences.xml +++ b/indra/newview/skins/default/xui/en/panel_performance_preferences.xml @@ -2,7 +2,7 @@ - - - Autostrojenie klatek - - - - Autostrojenie ustawień, by utrzymać FPS. - - - - - - - - - - - - Ustawienia grafiki - - - Wybierz ustawienia odległości, wody, oświetlenia itd. - - - - - Awatary w pobliżu - - - Ustaw, które awatary są w pełni wyświetlane. - - + + + + Autostrojenie klatek + + + + Autostrojenie ustawień, by utrzymać FPS. + + + + + + + + + + Ustawienia grafiki + + + Wybierz ustawienia odległości, wody, oświetlenia itd. + + + + + Awatary w pobliżu + + + Ustaw, które awatary są w pełni wyświetlane. + + Czas rysowania awatarów - - - - - Złożoność awatara - - - Bądź dobrą osobą. Zajmij się złożonością swojego awatara. - - - - - Aktywne HUDy - - - Usunięcie zbędnych HUDów poprawi szybkość. - - + + + + + Złożoność awatara + + + Bądź dobrą osobą. Zajmij się złożonością swojego awatara. + + + + + Aktywne HUDy + + + Usunięcie zbędnych HUDów poprawi szybkość. + + Czas rysowania HUDów - + + From 1a0a75e8ea3785cb66f6e07db3d4ae590d428908 Mon Sep 17 00:00:00 2001 From: Ansariel Date: Wed, 10 Nov 2021 23:08:15 +0100 Subject: [PATCH 358/443] Build fix and change silly Git didn't pick up in the merge --- indra/newview/Info-Firestorm.plist | 2 +- indra/newview/llpanelface.cpp | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) 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/llpanelface.cpp b/indra/newview/llpanelface.cpp index 015d1a84ee..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, bumpytexture_ctrl->getImageItemID() ); + //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, texture_ctrl->getImageItemID() ); + //LLSelectMgr::getInstance()->selectionSetShiny(shiny, texture_ctrl->getImageItemID()); + LLSelectMgr::getInstance()->selectionSetShiny(shiny, mShinyTextureCtrl->getImageItemID()); updateShinyControls(!specmap.isNull(), true); From 8f8fc99f06b5f38c7acfa88aad19c8f7acb2bade Mon Sep 17 00:00:00 2001 From: Ansariel Date: Wed, 10 Nov 2021 20:11:47 +0100 Subject: [PATCH 359/443] Revert "Properly hide all auto-tune panels when showing details panel" This reverts commit 144901a76838ee75dab6f35a5f3e4c653047dfd9. --- indra/newview/fsfloaterperformance.cpp | 2 +- .../default/xui/de/floater_performance.xml | 102 +++++++++--------- .../default/xui/en/floater_performance.xml | 32 +++--- .../xui/en/panel_performance_autotune.xml | 2 +- .../xui/en/panel_performance_complexity.xml | 4 +- .../default/xui/en/panel_performance_huds.xml | 4 +- .../xui/en/panel_performance_nearby.xml | 4 +- .../xui/en/panel_performance_preferences.xml | 2 +- .../default/xui/pl/floater_performance.xml | 102 +++++++++--------- 9 files changed, 127 insertions(+), 127 deletions(-) diff --git a/indra/newview/fsfloaterperformance.cpp b/indra/newview/fsfloaterperformance.cpp index 860a1e2fd9..64a3855efa 100644 --- a/indra/newview/fsfloaterperformance.cpp +++ b/indra/newview/fsfloaterperformance.cpp @@ -116,7 +116,7 @@ BOOL FSFloaterPerformance::postBuild() 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"); + auto tgt_panel = getChild("target_subpanel"); if (tgt_panel) { tgt_panel->getChild("target_btn")->setCommitCallback(boost::bind(&FSFloaterPerformance::showSelectedPanel, this, mAutoTunePanel)); diff --git a/indra/newview/skins/default/xui/de/floater_performance.xml b/indra/newview/skins/default/xui/de/floater_performance.xml index a6f242359c..28a98d3e55 100644 --- a/indra/newview/skins/default/xui/de/floater_performance.xml +++ b/indra/newview/skins/default/xui/de/floater_performance.xml @@ -36,63 +36,63 @@ Frame-Aufschlüsselung erfolgt hier. - - - - Auto-Anpassung Ziel-FPS - - - - Einstellungen automatisch für FPS anpassen. - - - - - - - - - - Grafik-Einstellungen - - - Einstellungen für Distanz, Wasser, Beleuchtung uvm. - - - - - Avatar in der Nähe - - - Einstellen, welche Avatare vollständig dargestellt werden. - - + + + Auto-Anpassung Ziel-FPS + + + + Einstellungen automatisch für FPS anpassen. + + + + + + + + + + + + Grafik-Einstellungen + + + Einstellungen für Distanz, Wasser, Beleuchtung uvm. + + + + + Avatar in der Nähe + + + Einstellen, welche Avatare vollständig dargestellt werden. + + Benötigte Renderzeit für Avatare - - - - - Eigene Avatar-Komplexität - - - Sei ein guter Einwohner - verwalte den Einfluss des eigenen Avatars. - - - - - Aktive HUDs - - - Entfernen von HUDs kann Geschwindigkeit verbessern. - - + + + + + Eigene Avatar-Komplexität + + + Sei ein guter Einwohner - verwalte den Einfluss des eigenen Avatars. + + + + + Aktive HUDs + + + Entfernen von HUDs kann Geschwindigkeit verbessern. + + Benötigte Renderzeit für HUDs - - + diff --git a/indra/newview/skins/default/xui/en/floater_performance.xml b/indra/newview/skins/default/xui/en/floater_performance.xml index 40b5356f03..64d214f486 100644 --- a/indra/newview/skins/default/xui/en/floater_performance.xml +++ b/indra/newview/skins/default/xui/en/floater_performance.xml @@ -115,16 +115,6 @@ Frame breakdown will appear here. - + + - + top="115" /> + top="115" /> + top="115" /> + top="115" /> + top="115" /> diff --git a/indra/newview/skins/default/xui/en/panel_performance_autotune.xml b/indra/newview/skins/default/xui/en/panel_performance_autotune.xml index 41c9f266af..0c96d9eeea 100644 --- a/indra/newview/skins/default/xui/en/panel_performance_autotune.xml +++ b/indra/newview/skins/default/xui/en/panel_performance_autotune.xml @@ -2,7 +2,7 @@ column_padding="1" draw_stripes="true" draw_heading="true" - height="335" + height="280" left="20" follows="left|top" layout="topleft" diff --git a/indra/newview/skins/default/xui/en/panel_performance_preferences.xml b/indra/newview/skins/default/xui/en/panel_performance_preferences.xml index 369615e235..8fbff6a4db 100644 --- a/indra/newview/skins/default/xui/en/panel_performance_preferences.xml +++ b/indra/newview/skins/default/xui/en/panel_performance_preferences.xml @@ -2,7 +2,7 @@ - - - - Autostrojenie klatek - - - - Autostrojenie ustawień, by utrzymać FPS. - - - - - - - - - - Ustawienia grafiki - - - Wybierz ustawienia odległości, wody, oświetlenia itd. - - - - - Awatary w pobliżu - - - Ustaw, które awatary są w pełni wyświetlane. - - + + + Autostrojenie klatek + + + + Autostrojenie ustawień, by utrzymać FPS. + + + + + + + + + + + + Ustawienia grafiki + + + Wybierz ustawienia odległości, wody, oświetlenia itd. + + + + + Awatary w pobliżu + + + Ustaw, które awatary są w pełni wyświetlane. + + Czas rysowania awatarów - - - - - Złożoność awatara - - - Bądź dobrą osobą. Zajmij się złożonością swojego awatara. - - - - - Aktywne HUDy - - - Usunięcie zbędnych HUDów poprawi szybkość. - - + + + + + Złożoność awatara + + + Bądź dobrą osobą. Zajmij się złożonością swojego awatara. + + + + + Aktywne HUDy + + + Usunięcie zbędnych HUDów poprawi szybkość. + + Czas rysowania HUDów - - + From 6fcbf921cef3e7822328c673f3951dd794f40308 Mon Sep 17 00:00:00 2001 From: Beq Date: Wed, 10 Nov 2021 23:28:55 +0000 Subject: [PATCH 360/443] Redesign target panel to visually distinguish from others --- indra/newview/fsfloaterperformance.cpp | 3 ++- .../default/xui/en/floater_performance.xml | 21 ++++++++++--------- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/indra/newview/fsfloaterperformance.cpp b/indra/newview/fsfloaterperformance.cpp index 64a3855efa..0d1e6df8ba 100644 --- a/indra/newview/fsfloaterperformance.cpp +++ b/indra/newview/fsfloaterperformance.cpp @@ -116,10 +116,11 @@ BOOL FSFloaterPerformance::postBuild() getChild("settings_subpanel")->setMouseDownCallback(boost::bind(&FSFloaterPerformance::showSelectedPanel, this, mSettingsPanel)); getChild("huds_subpanel")->setMouseDownCallback(boost::bind(&FSFloaterPerformance::showSelectedPanel, this, mHUDsPanel)); - auto tgt_panel = getChild("target_subpanel"); + 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("FPSTuningFPSStrategy")); } initBackBtn(mNearbyPanel); diff --git a/indra/newview/skins/default/xui/en/floater_performance.xml b/indra/newview/skins/default/xui/en/floater_performance.xml index 64d214f486..0c0d9de9bd 100644 --- a/indra/newview/skins/default/xui/en/floater_performance.xml +++ b/indra/newview/skins/default/xui/en/floater_performance.xml @@ -107,26 +107,27 @@ text_color="White" height="20" layout="topleft" - left="20" + halign="center" + left="5" top="38" name="frame_breakdown" - width="520"> -Frame breakdown will appear here. + width="550"> +[--------------------Frame breakdown will appear here.---------------------] + top_pad="0"> From 95a9bc2b210a1521b880f7a7834527699c1ba915 Mon Sep 17 00:00:00 2001 From: Beq Date: Thu, 11 Nov 2021 01:54:27 +0000 Subject: [PATCH 361/443] Make Self Imposter an option Also adds the ability to see the "revised" render time rather than the original. This can be confusing when auto tuning so defaults off. Cleaned up some text --- indra/newview/app_settings/settings.xml | 22 ++ indra/newview/fsfloaterperformance.cpp | 3 +- indra/newview/fsperfstats.cpp | 2 +- indra/newview/llvoavatar.cpp | 3 +- .../xui/en/panel_performance_autotune.xml | 192 ++++++++++++------ .../default/xui/en/panel_performance_huds.xml | 2 +- .../xui/en/panel_performance_nearby.xml | 4 +- 7 files changed, 155 insertions(+), 73 deletions(-) diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index e27ef4c0e4..a6d946e5be 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -25800,6 +25800,28 @@ Change of this parameter will affect the layout of buttons in notification toast 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 diff --git a/indra/newview/fsfloaterperformance.cpp b/indra/newview/fsfloaterperformance.cpp index 0d1e6df8ba..15296d85fa 100644 --- a/indra/newview/fsfloaterperformance.cpp +++ b/indra/newview/fsfloaterperformance.cpp @@ -551,6 +551,7 @@ void FSFloaterPerformance::populateObjectList() 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(); @@ -612,7 +613,7 @@ void FSFloaterPerformance::populateNearbyList() row[1]["column"] = "art_value"; row[1]["type"] = "text"; - if (is_slow) + if (is_slow && !showTunedART) { row[1]["value"] = llformat( "%.2f", FSPerfStats::raw_to_us( avatar->getLastART() ) ); } diff --git a/indra/newview/fsperfstats.cpp b/indra/newview/fsperfstats.cpp index 3f94f9cf1d..1febba5f35 100644 --- a/indra/newview/fsperfstats.cpp +++ b/indra/newview/fsperfstats.cpp @@ -82,7 +82,7 @@ namespace FSPerfStats using ST = StatType_t; bool unreliable{false}; - LLCachedControl smoothingPeriods(gSavedSettings, "FSPerfFloaterSmoothingPeriods"); + 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]; diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp index cc13cc5b56..9a3e3e9da0 100644 --- a/indra/newview/llvoavatar.cpp +++ b/indra/newview/llvoavatar.cpp @@ -9145,6 +9145,7 @@ 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) @@ -9200,7 +9201,7 @@ void LLVOAvatar::updateTooSlow() { bool render_friend_or_exception = ( alwaysRenderFriends && LLAvatarTracker::instance().isBuddy( id ) ) || ( getVisualMuteSettings() == LLVOAvatar::AV_ALWAYS_RENDER ); - if(!render_friend_or_exception) + 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); diff --git a/indra/newview/skins/default/xui/en/panel_performance_autotune.xml b/indra/newview/skins/default/xui/en/panel_performance_autotune.xml index 0c96d9eeea..1ad096d21c 100644 --- a/indra/newview/skins/default/xui/en/panel_performance_autotune.xml +++ b/indra/newview/skins/default/xui/en/panel_performance_autotune.xml @@ -78,84 +78,142 @@ Distant Avatars width="190" label_wrap="true" /> + control_name="FSAutoTuneImpostorFarAwayDistance" + height="20" + layout="topleft" + label="Farthest full avatar" + label_width="80" + label_wrap="true" + follows="top|left" + name="ffa_autotune" + left_pad="40" + decimal_digits="2" + min_val="16" + max_val="256" + width="140" > +follows="left|top" +font="SansSerifSmall" +text_color="White" +height="28" +layout="topleft" +top_pad="15" +left="160" +name="distant_av_advice" +width="450"> Avatars that are further away still have a high impact. Set the distance from camera beyond which an avatar will be optimized. +bevel_style="in" +height="0" +layout="topleft" +name="border2" +top_pad="8" +left="20" +width="540" /> +follows="left|top" +font="SansSerifSmall" +text_color="White" +height="36" +layout="topleft" +top_pad="20" +left="20" +name="distance_lbl" +width="100" +wrap="true"> Visibility distance tuning limits +control_name="FSAutoTuneRenderFarClipMin" +height="20" +layout="topleft" +label="Minimum Distance" +label_width="80" +label_wrap="true" +top_delta="0" +follows="top|left" +name="min_dd_autotune" +decimal_digits="2" +left_pad="40" +min_val="32" +max_val="256" +width="140"> +control_name="FSAutoTuneRenderFarClipTarget" +height="20" +layout="topleft" +label="Preferred distance" +label_width="80" +label_wrap="true" +follows="top|left" +name="pref_dd_autotune" +left_pad="20" +min_val="32" +max_val="256" +width="140"> + +When adjusting scene parameters, autotune will optimize draw distance to between the minimum and the preferred. + + + +Sundry Settings + + + -When adjusting scene parameters, autotune will optimize draw distance to between the minimum and the preferred. +These options control more subtle settings. Use the online help page to get more information on what these do. diff --git a/indra/newview/skins/default/xui/en/panel_performance_huds.xml b/indra/newview/skins/default/xui/en/panel_performance_huds.xml index 398f9a20bb..d4a7da3b63 100644 --- a/indra/newview/skins/default/xui/en/panel_performance_huds.xml +++ b/indra/newview/skins/default/xui/en/panel_performance_huds.xml @@ -88,7 +88,7 @@ name="art_visual" width="90" /> diff --git a/indra/newview/skins/default/xui/en/panel_performance_nearby.xml b/indra/newview/skins/default/xui/en/panel_performance_nearby.xml index 047edb7ed4..35c941ec7e 100644 --- a/indra/newview/skins/default/xui/en/panel_performance_nearby.xml +++ b/indra/newview/skins/default/xui/en/panel_performance_nearby.xml @@ -153,7 +153,7 @@ top="0"> name="art_visual" width="90" /> @@ -215,7 +215,7 @@ top="0"> Date: Thu, 11 Nov 2021 02:43:02 +0000 Subject: [PATCH 362/443] Step 1 - resizeable floater make the top level perf floater resizable TBD - make subpanels follow sensibly --- .../default/xui/en/floater_performance.xml | 123 +++++++++--------- .../xui/en/panel_performance_nearby.xml | 4 +- 2 files changed, 66 insertions(+), 61 deletions(-) diff --git a/indra/newview/skins/default/xui/en/floater_performance.xml b/indra/newview/skins/default/xui/en/floater_performance.xml index 0c0d9de9bd..87a37e346e 100644 --- a/indra/newview/skins/default/xui/en/floater_performance.xml +++ b/indra/newview/skins/default/xui/en/floater_performance.xml @@ -6,6 +6,10 @@ help_topic="fs_performance_floater" save_rect="true" title="Improve Graphics Speed (Experimental)" + can_resize="true" + min_height="652" + max_height="652" + min_width="580" width="580"> Frame: [TOT_FRAME_TIME]ms - Scenery:[SCENERY_FRAME_PCT]% Avatars:[AV_FRAME_PCT]% UI:[UI_FRAME_PCT]% HUDS:[HUDS_FRAME_PCT]% SWAP:[SWAP_FRAME_PCT]% TASKS:[IDLE_FRAME_PCT]% @@ -33,7 +37,7 @@ - - Graphics settings - - - Choose settings for distance, water, lighting and more. - - - + background_opaque="false" + border="true" + bevel_style="none" + follows="left|top|right" + height="50" + width="560" + name="settings_subpanel" + layout="topleft" + left="10" + top_pad="10"> + + Graphics settings + + + Choose settings for distance, water, lighting and more. + + + Manage which nearby avatars are fully displayed. draw_heading="true" height="280" left="20" - follows="left|top" + follows="left|top|right" layout="topleft" sort_column="art_value" short_names="true" From 03762ecdae8c9db13ccc506483737103072cd1b8 Mon Sep 17 00:00:00 2001 From: PanteraPolnocy Date: Thu, 11 Nov 2021 06:16:59 +0100 Subject: [PATCH 363/443] Updated Polish translation --- .../skins/default/xui/en/panel_performance_autotune.xml | 2 +- .../newview/skins/default/xui/pl/floater_performance.xml | 4 ++-- .../skins/default/xui/pl/panel_performance_autotune.xml | 8 ++++++++ .../skins/default/xui/pl/panel_performance_huds.xml | 2 +- .../skins/default/xui/pl/panel_performance_nearby.xml | 4 ++-- 5 files changed, 14 insertions(+), 6 deletions(-) diff --git a/indra/newview/skins/default/xui/en/panel_performance_autotune.xml b/indra/newview/skins/default/xui/en/panel_performance_autotune.xml index 1ad096d21c..81337e4874 100644 --- a/indra/newview/skins/default/xui/en/panel_performance_autotune.xml +++ b/indra/newview/skins/default/xui/en/panel_performance_autotune.xml @@ -185,7 +185,7 @@ height="36" layout="topleft" top_pad="20" left="20" -name="distance_lbl" +name="sundry_lbl" width="100" wrap="true"> Sundry Settings diff --git a/indra/newview/skins/default/xui/pl/floater_performance.xml b/indra/newview/skins/default/xui/pl/floater_performance.xml index d0040d839d..a4a3c34b68 100644 --- a/indra/newview/skins/default/xui/pl/floater_performance.xml +++ b/indra/newview/skins/default/xui/pl/floater_performance.xml @@ -27,7 +27,7 @@ Poczekaj 5-10 sekund, by nastąpiły zmiany. - Tutaj pojawi się analiza klatek. + [----------------- Tutaj pojawi się analiza klatek. -----------------] @@ -45,7 +45,7 @@ - + Ustawienia grafiki diff --git a/indra/newview/skins/default/xui/pl/panel_performance_autotune.xml b/indra/newview/skins/default/xui/pl/panel_performance_autotune.xml index 94bbb8f04f..895c82cc4c 100644 --- a/indra/newview/skins/default/xui/pl/panel_performance_autotune.xml +++ b/indra/newview/skins/default/xui/pl/panel_performance_autotune.xml @@ -23,4 +23,12 @@ Określ odległość po której awatar zostanie zoptymalizowany. Podczas przetwarzania sceny autostrojenie zoptymalizuje pole widzenia między minimalnym a preferowanym. + + Różne + + + + + Te opcje kontrolują dość subtelne ustawienia. Skorzystaj z pomocy online, aby uzyskać więcej informacji. + diff --git a/indra/newview/skins/default/xui/pl/panel_performance_huds.xml b/indra/newview/skins/default/xui/pl/panel_performance_huds.xml index 16481fff80..2983933a8f 100644 --- a/indra/newview/skins/default/xui/pl/panel_performance_huds.xml +++ b/indra/newview/skins/default/xui/pl/panel_performance_huds.xml @@ -16,7 +16,7 @@ Uwaga: Minimalizacja HUDa nie powoduje jego odłączenia. Użyj X, aby go usunąć. - + diff --git a/indra/newview/skins/default/xui/pl/panel_performance_nearby.xml b/indra/newview/skins/default/xui/pl/panel_performance_nearby.xml index 047c28aa5e..32e7959a74 100644 --- a/indra/newview/skins/default/xui/pl/panel_performance_nearby.xml +++ b/indra/newview/skins/default/xui/pl/panel_performance_nearby.xml @@ -16,7 +16,7 @@ - + @@ -26,7 +26,7 @@