From 4b7710eab2e01c2e8f827b3741caae3fe03b1bbd Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Thu, 16 Jan 2020 20:33:59 -0500 Subject: [PATCH 001/256] 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/256] 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/256] 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/256] 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 1a4b66e89cae064184aa89e86a4f2fca2a33f215 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Fri, 16 Oct 2020 19:04:13 +0300 Subject: [PATCH 005/256] 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 006/256] 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 007/256] 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 008/256] 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 009/256] 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 010/256] 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 011/256] 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 012/256] 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 013/256] 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 014/256] 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 015/256] 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 016/256] 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 017/256] 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 018/256] 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 019/256] 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 020/256] 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 021/256] 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 022/256] 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 023/256] 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 024/256] 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 025/256] 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 026/256] 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 027/256] 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 028/256] 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 029/256] 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 030/256] 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 031/256] 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 032/256] 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 033/256] 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 034/256] 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 035/256] 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 036/256] 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 037/256] 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 038/256] 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 039/256] 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 040/256] 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 041/256] 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 042/256] 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 043/256] 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 044/256] 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 045/256] 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 046/256] 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 047/256] 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 048/256] 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 049/256] 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 050/256] 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 051/256] 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 052/256] 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 053/256] 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 054/256] 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 055/256] 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 056/256] 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 057/256] 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 058/256] 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 059/256] 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 060/256] 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 061/256] 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 062/256] 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 063/256] 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 064/256] 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 065/256] 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 066/256] 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 067/256] 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 36064412c68468ebd6818c8409c7e59a72f050c8 Mon Sep 17 00:00:00 2001 From: Mnikolenko Productengine Date: Tue, 2 Feb 2021 17:28:10 +0200 Subject: [PATCH 068/256] 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 069/256] 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 070/256] 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 8f717b988ad6a1bc7156d0779b5c7e424c6bf932 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Fri, 19 Feb 2021 00:01:15 +0200 Subject: [PATCH 071/256] 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 2d4a894b706d0dcbdc753318c2c400b0d3ee92b7 Mon Sep 17 00:00:00 2001 From: Mnikolenko Productengine Date: Thu, 25 Feb 2021 16:55:11 +0200 Subject: [PATCH 072/256] 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 073/256] 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: Fri, 2 Apr 2021 22:52:26 +0200 Subject: [PATCH 074/256] 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 5ab76453bb53424bbbc77a0d0b818ba05bceb92d Mon Sep 17 00:00:00 2001 From: Ansariel Date: Mon, 5 Apr 2021 20:52:49 +0200 Subject: [PATCH 075/256] 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 076/256] 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 5b92d266df00c8d8b8a6353061b4a9672bfa97f5 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Mon, 14 Jun 2021 21:19:55 +0300 Subject: [PATCH 097/256] 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 098/256] 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 099/256] 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 100/256] 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 101/256] 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 zcmeI3c{tSF-^agh-S(}bl5~$HNoHj*(-_NGvt_%DrDe=!vJ5jLOC?K|(oIr`NQ-Qd zR3sE7DqEB`TSAf>_f4e|oCa`8FUKGiwppP&(iIw4)%j9bSJvr7+S=H9<`v`$q0e$3}Zv36I9d` zgrzpeD4cpKV_Ut{*m#NDoy-{ixVX?mGPdes2SuI;_9>i>i#QW=@ZMz4?lYc`Dkfew zPG5P99XLOpeyLfoN=PipOv4r#Dwb=wcIoqox|-UaK8Svph_WvrC3K0Tz?@Rz1Kx*V zFdG%C1g`^pfe%E5fGVrBD%hIn8Ohg%$KCis_w!Y;5_BwtLZt!y;5fr`fW8S|XnKl@ zJ&?Hs*ilb(?*+DifgS7jy?g+KroTVFn-6e3svyIcnE-&6lVgkkk4?b&=06V_19%u9 zO|hs!0Z+gH%-o4$1{9S7RZUW&#ek3)0JDvW+yE@u4eYq1q!bA3KMqKnj5%Tc-B>6! zpvES3yckoaj4}>$6$1MSIyphssy3Og+$gO@_>GXN54jn1Tow_gDfxW70RS=+WZ0t} zp9*Y}C~RudiYt-W4t{+@U`Em1y?465Ip0?w0D4#D- zBci7{U}jWr$~1Ew5K1vW;s*fRjFce`_b%zx2?2mnW|&%$f!v$wRq9m&YpQ?ms22US zLusVUSe=ZXgNXQSqz{1LA+9&(8}YH?-i=emMn`^2HlO3wpFx9K$^kr4myAw&E&^) z8NZ>T-At|}Y`Oy=!aqe-n8J^S72E1Q6uW{e%h6uF-{iFDeG&_v8owel?LOo3YTZLx zrv~oldq_Tu$KvW>Rj*bFYSehaAhov)FY2fZClc!~DxMe1uU%dA=Xw6}18<4V7Xy|o z3p1_~)>;x^2qLUCFvDBot)H0XfYvB$E`27fEzG~)_U3xU#2kyuD%X~Ns9EKXfJfua z)Ri7Bi(d|v+8u+d(NuvR8(Wc3UiCBg44$ytoB&xF+scVigj&i=drcc$@iUF>jzC= zCBNc-6CfrYB@LsgYcTP3)PDjTrsLW<=%*$1(*bq+9X_)yBgamnL!N4#2z+8&vN zdm_g+A5%Fdrv`P%%{!OZl_%;r?pW^-pS#U|Z=s2!hJA0Y@WZ5h$Gr3{L-um^)Z9%u z(RtJyx`W=?5a+1_0?xNAZ`t6^+Gbwd-dj-%5+%xB3RG9{6wiG$*j`=|Du*&^91taQn(j;7U38nxo3YuSqtV&o5^1$l80!uZoSIA-nHJfXH*1K6jUs% zUR#Z%+F6yI+i-4^gx~P}rlw2j77x%fG za~>(F@QHLmIcMP=UAA5_DM&9^_o%#}JbP(&nRTLde#Rr}t)hQR?v~`1$`Z_p@x=jpZ36%x{_MPj2MrJJzx=D4@t&C(&TD8?^O0}X1(>>+7sOR zHa+c9+Rfpd_6s9gBeap|j*|_VCpTm`YcTKMx`TUe+ux!mdh!^|v-^CA4bCQvdSyTf zN`xjj6+A8~%?ikyAdIfWzQZz3_F{W6+Fgh)=j{#JRi$@I>uqk)Gqy)|Pn-+ zZBQ4$n~`eRJjhPWGwo}d*Ys*36z7IEd^+CT%VG@*qE@Ko<8{6J)9`roi}V+wy}MVY zK<{kz4La3y^G#&-id@Jtb##)xWsJ4X(SHo2)N)oFS~s>lU|pO@&`tT9R7GfuR!hti zoSWKO>oGGmtKcJlCsZJVly7TfsrQ%dU!Qxp!cyF_GYy@wB6SzY8=;G?ghw1nIP7Pb zr(l&>LVZnrN!e9@o*Y>`ecLCt6uS19;9bv4htL1+3>GOdJon1MMfI_oU@?{KM7hy; z;2tU|KVxI#aKoj0?T58bjGmksUUqX?&ykX>C<`aBJpN_n`JJd@j9*Z@NUzNA8>9Xd zIFGq{utd$f%_e`?DY-DDQYF~RGi+P+z3}QQe4az1jw1b$dxtt64{x=>L!G;?5I#nw z%VA{>94wS>Uzsek?}=(hV82{6{oak^9Y-(c=GT;wnklW6!Ixd&3|EPyyyTb35^PfpET*cwZPijZ@7-Xm48Z5 zNuuO&*~2#ZR$T|X_(vOuOeO06xIUde8UPm85_kOTMC}VDU!$PD!3p8+iM8VBXS)vV zKHnqw;E!GMRC(x5!_=`tomPfCuo6XP7TdEDVH?b%@X zgGB0B^P%)(>3c&UA3AolpDx)wKy2#XDM=r_CdKM$HJ*tb*i^Bp$!+W^Ypl4vf4S3D zr_>AR?cT3huQAh!4{YknPn4$?mbrPBjRaR-*-e=kl*`a=>U>if^zVw9M{OA>-OkGK zVEV-EiMQP=Izt%ir<&@^p9ZWSDX6fi*#1U;*x)IyGrCRBb-LrpXve;tRRNjfEghy4 z0+A8T(+O|mC2_yUACIq(5|0|n(7~cmFZ38wgP*c-&7@|PjFr=;r|Sz>u7HNTZyS2t z)RNM2DtRn9@rL)Ftf|*kL$VjzYj4)By?!@P1HSFepOeGY0UZJIqi4D$ZTj|r_NmTz ze7N}5{(kmkqHJQ~%o6^T@lQkza615?J7^Ag7T(GdO{9B62qd~Y84~F2%RYz#07fs+ zmq7F+vq0`-D$Pe%akTt~B8W!PRdhmH!K{37WDlBIFoSF#Z0$e{_9UW6ih5WPOdy&q z;7w)`K!M&~K1_6=uHu|7nteZ83{?cpRbhGRDjLi-2*O)!0paKjG6)Glf{8E$9Hfnc zz>%6LI9wfsfWbAOa2OPU0>j~GO>Hz>3-tL?#EP)*Fbom}ZD(ZixjD9_tLVXE`J$oF zfPerB$H*li`|pYBl}^4 zOot#}GSrUDr28|7WaC|AAC}UOI^p}}o5YXhzPf)p3KH>aq_022YYs4p2qk-wz1eLt z*>Uh6j)6s^EKJTfLzwmav^jDh?I&Tgp82r3RG6P33_JhOI0l)(qB9)mbT90DmMwgL zVt;*7b)xx@=mE?P7$|4$g{fW;A{!A{WGsT6nqZg~7^dL>*G3~?Xt>5km1rQiy z11dWw{+neuFZgW)r!odQyC-|m{txDWN!azjn}J_jLjT`qU?F#j9t0mMnS_OYN!u?4 zzcy*}Q~B+B`mzmtzy2^^pGoL1>)(LAgUv2e=C{c(w@eKQ)Ne~?yZt$JzHAzBIGjkL zkTti z#^UIO;sub4qS(LvZJGb+56iSOH3XR(p#fze5PYvif&i3pBE*Z-n8fOt_?JcxGvKQWn#(ual zXSZyG*5?>b#}5OYe-^mN@i}llxfUHm=Ms6olzqr$pRb``57^)3_}2%;fAVHwME^-u z4lQ0I96-36JY3xQaCmvRIDl|BdAPXq;qdZsaRA|N@^EqI!{O!O;sCiE)F2vO&%`pd^o&3TpU2S zn><|H`EYo7xHy1tH+i_Y^WpIFaB%?PZt`$(=fmOU;o<LUcaw*UJ0A`&4;Kdz?j{cxcRn0m9xe_b+)W-X?tD1BJX{<=xSKp&-1%^L zdAK-$a5s6lxbxxg@^Eng;coJ9ap%L~<>BH0!rkPGOJw1dRk9EJJ=FmA3#n1T9rEm# zSwTcIJ1YPPUIzf75diREhW$AR0RAulc)f%D9&8E#tfU{=e%k~9e*0iLA3Df?PD8D!~dv?{6jxEgg<$tCNkeW zR@BK@AR*kc0A!}x08(Q|S*7ON8_ie4$e zu%7JckB4rQS=G5J;oakXJ0AJ^5IYTY}QP)kV#q^BJW!WBC$;Ve&r<-m(w5)p!$n$-}OBt872=h6Cc_D5gJp~paAS|fC@S)?_U!MYvH*MNf@`;QpSvSPD-}z2gV7yMe-(Q>l zedRF(!>jjtS!xe1YhUFSQ)v9JTl{Gg>7E|Gvszgv-W^Ag?qp>z{(d4ULqw zJKBzTFs=cAiMMsO)?Vr{05*SdH0H%xk@_MLpFxktljud#gkZ|h`8s#nV))5Mcax8f>VqrAPe zH+zj67fJ2OaI+|Kj1?C5sVAe{rp4Z`HfyRR%*=>>v - - 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 103/256] 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 104/256] 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 105/256] 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 106/256] 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 107/256] 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 108/256] 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 109/256] 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 110/256] 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 111/256] 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 112/256] 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 113/256] 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 114/256] 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 115/256] 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 116/256] 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 77aac9579170369a11f0884e16bd730f8cbb8bdb Mon Sep 17 00:00:00 2001 From: Mnikolenko Productengine Date: Wed, 14 Jul 2021 14:49:43 +0300 Subject: [PATCH 117/256] 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 09f53a672bc42bed83bf43632013969000065c25 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Thu, 15 Jul 2021 18:37:02 +0300 Subject: [PATCH 118/256] 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 119/256] 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 120/256] 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 121/256] 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 928191f525cf8a02816718eefd9a65097d8ecb8b Mon Sep 17 00:00:00 2001 From: Mnikolenko Productengine Date: Mon, 19 Jul 2021 20:07:03 +0300 Subject: [PATCH 122/256] 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"> + + + + + + + + + + + + - - - - + + + @@ -250,6 +250,6 @@ - + diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index 0acedf9a39..952b36adea 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -8308,7 +8308,7 @@ PushToTalkToggle Comment - Should the push-to-talk button behave as a toggle + Should the push-to-talk toolbar button behave as a toggle Persist 1 Type From 28e07331acf45edb380c094179cef6ea5adeb010 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Fri, 17 Sep 2021 23:15:14 +0300 Subject: [PATCH 166/256] SL-15594 Ignore voice keys when keybinding is waiting for a key --- indra/newview/llsetkeybinddialog.h | 2 ++ indra/newview/llviewerinput.cpp | 21 +++++++++++++++++++++ 2 files changed, 23 insertions(+) diff --git a/indra/newview/llsetkeybinddialog.h b/indra/newview/llsetkeybinddialog.h index a34b952233..24dfa1dbfd 100644 --- a/indra/newview/llsetkeybinddialog.h +++ b/indra/newview/llsetkeybinddialog.h @@ -76,6 +76,8 @@ public: static void onDefault(void* user_data); static void onClickTimeout(void* user_data, MASK mask); + static bool isRecording() { return sRecordKeys; } + class Updater; private: diff --git a/indra/newview/llviewerinput.cpp b/indra/newview/llviewerinput.cpp index 6629a2ffac..94ec534732 100644 --- a/indra/newview/llviewerinput.cpp +++ b/indra/newview/llviewerinput.cpp @@ -38,6 +38,7 @@ #include "llkeybind.h" // LLKeyData #include "llmorphview.h" #include "llmoveview.h" +#include "llsetkeybinddialog.h" #include "lltoolfocus.h" #include "lltoolpie.h" #include "llviewercontrol.h" @@ -1052,18 +1053,38 @@ BOOL LLViewerInput::handleKeyUp(KEY translated_key, MASK translated_mask) bool LLViewerInput::handleGlobalBindsKeyDown(KEY key, MASK mask) { + if (LLSetKeyBindDialog::isRecording()) + { + // handleGlobalBindsKeyDown happens before view handling, so can't + // be interupted by LLSetKeyBindDialog, check manually + return false; + } S32 mode = getMode(); return scanKey(mGlobalKeyBindings[mode], mGlobalKeyBindings[mode].size(), key, mask, TRUE, FALSE, FALSE, FALSE); } bool LLViewerInput::handleGlobalBindsKeyUp(KEY key, MASK mask) { + if (LLSetKeyBindDialog::isRecording()) + { + // handleGlobalBindsKeyUp happens before view handling, so can't + // be interupted by LLSetKeyBindDialog, check manually + return false; + } + S32 mode = getMode(); return scanKey(mGlobalKeyBindings[mode], mGlobalKeyBindings[mode].size(), key, mask, FALSE, TRUE, FALSE, FALSE); } bool LLViewerInput::handleGlobalBindsMouse(EMouseClickType clicktype, MASK mask, bool down) { + if (LLSetKeyBindDialog::isRecording()) + { + // handleGlobalBindsMouse happens before view handling, so can't + // be interupted by LLSetKeyBindDialog, check manually + return false; + } + bool res = false; S32 mode = getMode(); if (down) From ce660c7e7bb6e19a23d634fb6d3249330bf2d74c Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Fri, 17 Sep 2021 23:18:58 +0300 Subject: [PATCH 167/256] SL-11841 Fix PushToTalkToggle being set incorectly Due to changed defaults, legacy compatibility will no longer work corectly, remove it --- indra/newview/llappviewer.cpp | 24 ------------------------ indra/newview/llkeyconflict.cpp | 1 - 2 files changed, 25 deletions(-) diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index ecd62cadf8..573cca248c 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -4562,11 +4562,6 @@ void LLAppViewer::loadKeyBindings() LLKeyboard::keyFromString(key_string, &key); } - value = gSavedSettings.getBOOL("PushToTalkToggle"); - std::string control_name = value ? "toggle_voice" : "voice_follow_key"; - third_person_view.registerControl(control_name, 0, mouse, key, MASK_NONE, true); - sitting_view.registerControl(control_name, 0, mouse, key, MASK_NONE, true); - if (third_person_view.hasUnsavedChanges()) { // calls loadBindingsXML() @@ -4578,25 +4573,6 @@ void LLAppViewer::loadKeyBindings() // calls loadBindingsXML() sitting_view.saveToSettings(); } - - // in case of voice we need to repeat this in other modes - - for (U32 i = 0; i < LLKeyConflictHandler::MODE_COUNT - 1; ++i) - { - // edit and first person modes; MODE_SAVED_SETTINGS not in use at the moment - if (i != LLKeyConflictHandler::MODE_THIRD_PERSON && i != LLKeyConflictHandler::MODE_SITTING) - { - LLKeyConflictHandler handler((LLKeyConflictHandler::ESourceMode)i); - - handler.registerControl(control_name, 0, mouse, key, MASK_NONE, true); - - if (handler.hasUnsavedChanges()) - { - // calls loadBindingsXML() - handler.saveToSettings(); - } - } - } } // since something might have gone wrong or there might have been nothing to save // (and because otherwise following code will have to be encased in else{}), diff --git a/indra/newview/llkeyconflict.cpp b/indra/newview/llkeyconflict.cpp index b6107eeedf..52e14d48f7 100644 --- a/indra/newview/llkeyconflict.cpp +++ b/indra/newview/llkeyconflict.cpp @@ -644,7 +644,6 @@ void LLKeyConflictHandler::saveToSettings(bool temporary) data = getControl("voice_follow_key", 0); } - gSavedSettings.setBOOL("PushToTalkToggle", can_toggle); if (data.isEmpty()) { // legacy viewer has a bug that might crash it if NONE value is assigned. From f30cc7b5bb79aae6f012f04f54b461fdb7ee3f64 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Tue, 21 Sep 2021 00:17:05 +0300 Subject: [PATCH 168/256] =?UTF-8?q?Revert=20"SL-11841=20make=20=E2=80=98Pu?= =?UTF-8?q?sh=20to=20talk=E2=80=99=20the=20default=20setting"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commits: 126877bc5ba45ff6b0b31368c55f894a0beaf5bf b661f62a7ad4dad9806eda8f4c8f2c9d64b3efbb ce660c7e7bb6e19a23d634fb6d3249330bf2d74c --- indra/newview/app_settings/key_bindings.xml | 8 +++---- indra/newview/app_settings/settings.xml | 4 ++-- indra/newview/llappviewer.cpp | 24 +++++++++++++++++++++ indra/newview/llkeyconflict.cpp | 1 + 4 files changed, 31 insertions(+), 6 deletions(-) diff --git a/indra/newview/app_settings/key_bindings.xml b/indra/newview/app_settings/key_bindings.xml index 2ec9a2586c..4f6deb1f98 100644 --- a/indra/newview/app_settings/key_bindings.xml +++ b/indra/newview/app_settings/key_bindings.xml @@ -32,7 +32,7 @@ - + @@ -125,7 +125,7 @@ - + @@ -223,7 +223,7 @@ - + @@ -250,6 +250,6 @@ - + diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index 952b36adea..eeb7e6f0aa 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -8308,13 +8308,13 @@ PushToTalkToggle Comment - Should the push-to-talk toolbar button behave as a toggle + Should the push-to-talk button behave as a toggle Persist 1 Type Boolean Value - 0 + 1 QAMode diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 573cca248c..ecd62cadf8 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -4562,6 +4562,11 @@ void LLAppViewer::loadKeyBindings() LLKeyboard::keyFromString(key_string, &key); } + value = gSavedSettings.getBOOL("PushToTalkToggle"); + std::string control_name = value ? "toggle_voice" : "voice_follow_key"; + third_person_view.registerControl(control_name, 0, mouse, key, MASK_NONE, true); + sitting_view.registerControl(control_name, 0, mouse, key, MASK_NONE, true); + if (third_person_view.hasUnsavedChanges()) { // calls loadBindingsXML() @@ -4573,6 +4578,25 @@ void LLAppViewer::loadKeyBindings() // calls loadBindingsXML() sitting_view.saveToSettings(); } + + // in case of voice we need to repeat this in other modes + + for (U32 i = 0; i < LLKeyConflictHandler::MODE_COUNT - 1; ++i) + { + // edit and first person modes; MODE_SAVED_SETTINGS not in use at the moment + if (i != LLKeyConflictHandler::MODE_THIRD_PERSON && i != LLKeyConflictHandler::MODE_SITTING) + { + LLKeyConflictHandler handler((LLKeyConflictHandler::ESourceMode)i); + + handler.registerControl(control_name, 0, mouse, key, MASK_NONE, true); + + if (handler.hasUnsavedChanges()) + { + // calls loadBindingsXML() + handler.saveToSettings(); + } + } + } } // since something might have gone wrong or there might have been nothing to save // (and because otherwise following code will have to be encased in else{}), diff --git a/indra/newview/llkeyconflict.cpp b/indra/newview/llkeyconflict.cpp index 52e14d48f7..b6107eeedf 100644 --- a/indra/newview/llkeyconflict.cpp +++ b/indra/newview/llkeyconflict.cpp @@ -644,6 +644,7 @@ void LLKeyConflictHandler::saveToSettings(bool temporary) data = getControl("voice_follow_key", 0); } + gSavedSettings.setBOOL("PushToTalkToggle", can_toggle); if (data.isEmpty()) { // legacy viewer has a bug that might crash it if NONE value is assigned. From 35410bdeb6bbfc3fda46c5c7a5344be348cba608 Mon Sep 17 00:00:00 2001 From: Beq Date: Sat, 25 Sep 2021 16:07:45 +0100 Subject: [PATCH 169/256] Perf Floater with auto-FPS --- indra/newview/app_settings/settings.xml | 55 ++++++ indra/newview/llappviewer.cpp | 2 +- indra/newview/lldrawpoolavatar.cpp | 4 +- indra/newview/llfloaterperformance.cpp | 128 +++++++++++-- indra/newview/llfloaterperformance.h | 3 + indra/newview/llfloaterpreference.cpp | 22 +++ indra/newview/llfloaterpreference.h | 2 + indra/newview/llvoavatar.cpp | 63 ++++++- indra/newview/llvoavatar.h | 5 + indra/newview/pipeline.cpp | 7 +- indra/newview/pipeline.h | 1 + .../default/xui/en/floater_performance.xml | 178 ++++++++++++++---- .../default/xui/en/menu_avatar_other.xml | 9 +- .../xui/en/panel_performance_nearby.xml | 46 +++++ 14 files changed, 460 insertions(+), 65 deletions(-) diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index 90dfad49fb..87ad1598c3 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -25701,6 +25701,28 @@ Change of this parameter will affect the layout of buttons in notification toast Value 0 + FSTargetFPS + + Comment + Desired minimum FPS + Persist + 1 + Type + U32 + Value + 25 + + FSAutoTuneFPS + + Comment + Allow the viewer to adjust your settings to achieve target FPS + Persist + 1 + Type + Boolean + Value + 0 + FSAutoUnmuteSounds Comment @@ -25723,5 +25745,38 @@ Change of this parameter will affect the layout of buttons in notification toast Value 0 + RenderJellyDollsAsImpostors + + Comment + Use an impostor instead of a JellyDoll for better visuals (true) + Persist + 1 + Type + Boolean + Value + 1 + + RenderAvatarUseART + + Comment + Use Avatar Render Time (ART) instead of complexity (ARC) (true) + Persist + 1 + Type + Boolean + Value + 1 + + RenderAvatarMaxART + + Comment + Render Time Limit in microseconds (0.0 = no limit) + Persist + 1 + Type + F32 + Value + 0.0 + diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index c6701864e2..17fac803cb 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -1970,7 +1970,7 @@ bool LLAppViewer::doFrame() LLPROFILE_UPDATE(); } FSTelemetry::RecordSceneTime::toggleBuffer(); - FSTelemetry::RecordObjectTime::toggleBuffer(); + FSTelemetry::RecordObjectTime::toggleBuffer(); return ! LLApp::isRunning(); } diff --git a/indra/newview/lldrawpoolavatar.cpp b/indra/newview/lldrawpoolavatar.cpp index a0e69c513f..e8e6267cc6 100644 --- a/indra/newview/lldrawpoolavatar.cpp +++ b/indra/newview/lldrawpoolavatar.cpp @@ -579,7 +579,7 @@ void LLDrawPoolAvatar::renderShadow(S32 pass) { return; } - FSTelemetry::RecordObjectTime T(avatarp, FSTelemetry::ObjStatType::RENDER_SHADOWS); + FSTelemetry::RecordObjectTime T(avatarp, FSTelemetry::ObjStatType::RENDER_SHADOWS); LLVOAvatar::AvatarOverallAppearance oa = avatarp->getOverallAppearance(); BOOL impostor = !LLPipeline::sImpostorRender && avatarp->isImpostor(); @@ -1500,7 +1500,7 @@ void LLDrawPoolAvatar::renderAvatars(LLVOAvatar* single_avatar, S32 pass) { return; } - FSTelemetry::RecordObjectTime T(avatarp, FSTelemetry::ObjStatType::RENDER_GEOMETRY); + FSTelemetry::RecordObjectTime T(avatarp, FSTelemetry::ObjStatType::RENDER_GEOMETRY); // Add avatar hitbox debug static LLCachedControl render_hitbox(gSavedSettings, "DebugRenderHitboxes", false); diff --git a/indra/newview/llfloaterperformance.cpp b/indra/newview/llfloaterperformance.cpp index 317ec817b0..c967337773 100644 --- a/indra/newview/llfloaterperformance.cpp +++ b/indra/newview/llfloaterperformance.cpp @@ -129,8 +129,14 @@ BOOL LLFloaterPerformance::postBuild() mComplexityChangedSignal = gSavedSettings.getControl("RenderAvatarMaxComplexity")->getCommitSignal()->connect(boost::bind(&LLFloaterPerformance::updateComplexityText, this)); mNearbyPanel->getChild("IndirectMaxComplexity")->setCommitCallback(boost::bind(&LLFloaterPerformance::updateMaxComplexity, this)); + updateMaxRenderTime(); + updateMaxRenderTimeText(); + mMaxARTChangedSignal = gSavedSettings.getControl("RenderAvatarMaxART")->getCommitSignal()->connect(boost::bind(&LLFloaterPerformance::updateMaxRenderTimeText, this)); + mNearbyPanel->getChild("RenderAvatarMaxART")->setCommitCallback(boost::bind(&LLFloaterPerformance::updateMaxRenderTime, this)); + LLAvatarComplexityControls::setIndirectMaxArc(); + return TRUE; } @@ -157,7 +163,10 @@ void LLFloaterPerformance::showSelectedPanel(LLPanel* selected_panel) void LLFloaterPerformance::draw() { const S32 NUM_PERIODS = 50; - static LLCachedControl max_fps(gSavedSettings, "FramePerSecondLimit"); + static LLCachedControl fps_cap(gSavedSettings, "FramePerSecondLimit"); // user limited FPS + static LLCachedControl target_fps(gSavedSettings, "FSTargetFPS"); // desired FPS + static LLCachedControl auto_tune(gSavedSettings, "FSAutoTuneFPS"); // auto tune enabled? + static LLCachedControl max_render_cost(gSavedSettings, "RenderAvatarMaxART", 0); if (mUpdateTimer->hasExpired()) { @@ -166,8 +175,9 @@ void LLFloaterPerformance::draw() auto fps = LLTrace::get_frame_recording().getPeriodMedianPerSec(LLStatViewer::FPS, NUM_PERIODS); getChild("fps_value")->setValue((S32)llround(fps)); auto tot_frame_time_ns = 1000000000/fps; - auto tot_avatar_time = FSTelemetry::RecordObjectTime::getSum(FSTelemetry::ObjStatType::RENDER_COMBINED); - auto tot_huds_time = FSTelemetry::RecordSceneTime::get(FSTelemetry::SceneStatType::RENDER_HUDS); + auto target_frame_time_ns = 1000000000/(target_fps==0?1:target_fps); + auto tot_avatar_time = FSTelemetry::RecordObjectTime::getSum(FSTelemetry::ObjStatType::RENDER_COMBINED); + auto tot_huds_time = FSTelemetry::RecordSceneTime::get(FSTelemetry::SceneStatType::RENDER_HUDS) ; auto tot_sleep_time = FSTelemetry::RecordSceneTime::get(FSTelemetry::SceneStatType::RENDER_SLEEP); auto tot_ui_time = FSTelemetry::RecordSceneTime::get(FSTelemetry::SceneStatType::RENDER_UI); auto tot_idle_time = FSTelemetry::RecordSceneTime::get(FSTelemetry::SceneStatType::RENDER_IDLE); @@ -198,27 +208,82 @@ void LLFloaterPerformance::draw() args["IDLE_FRAME_PCT"] = llformat("%02u", (U32)llround(pct_idle_time)); args["SWAP_FRAME_PCT"] = llformat("%02u", (U32)llround(pct_swap_time)); args["SCENE_FRAME_PCT"] = llformat("%02u", (U32)llround(pct_scene_time)); - args["FPSCAP"] = llformat("%02u", (U32)max_fps); + args["FPSCAP"] = llformat("%02u", (U32)fps_cap); + args["FPSTARGET"] = llformat("%02u", (U32)target_fps); getChild("av_frame_stats")->setText(getString("av_frame_pct", args)); + getChild("huds_frame_stats")->setText(getString("huds_frame_pct", args)); getChild("frame_breakdown")->setText(getString("frame_stats", args)); - auto textbox = getChild("fps_sleep_warning"); + auto textbox = getChild("fps_warning"); if(tot_sleep_time > 0) // We are sleeping because view is not focussed { textbox->setVisible(true); textbox->setText(getString("focus_fps")); + textbox->setColor(LLUIColorTable::instance().getColor("DrYellow")); } else if (tot_limit_time > 0) { textbox->setVisible(true); textbox->setText(getString("limit_fps", args)); + textbox->setColor(LLUIColorTable::instance().getColor("DrYellow")); + } + else if(auto_tune) + { + textbox->setVisible(true); + textbox->setText(getString("tuning_fps", args)); + textbox->setColor(LLUIColorTable::instance().getColor("green")); } else { textbox->setVisible(false); } + if( auto_tune ) + { + auto av_render_max = FSTelemetry::RecordObjectTime::getMax(FSTelemetry::ObjStatType::RENDER_COMBINED); + + // if( target_frame_time_ns <= tot_frame_time_ns ) + // { + // U32 non_avatar_time_ns = tot_frame_time_ns - tot_avatar_time; + // if( non_avatar_time_ns < target_frame_time_ns ) + // { + // F32 target_avatar_time_ms {F32(target_frame_time_ns-non_avatar_time_ns)/1000000}; + // gSavedSettings.setF32( "RenderAvatarMaxART", target_avatar_time_ms / LLVOAvatar::sMaxNonImpostors ); + // LL_INFOS() << "AUTO_TUNE: Target frame time:"<= max_render_cost) + { + // we caught a bad frame possibly with a forced refresh render. + new_render_limit = max_render_cost - 0.1; + } + gSavedSettings.setF32( "RenderAvatarMaxART", new_render_limit); + LL_INFOS() << "AUTO_TUNE: avatar_budget adjusted to:" << new_render_limit << LL_ENDL; + } + LL_INFOS() << "AUTO_TUNE: Target frame time:"<getVisible()) { populateHUDList(); @@ -290,14 +355,15 @@ void LLFloaterPerformance::populateHUDList() row[0]["column"] = "complex_visual"; row[0]["type"] = "bar"; LLSD& value = row[0]["value"]; - value["ratio"] = (F32)obj_cost_short / max_complexity * 1000; + value["ratio"] = (F32)hud_render_time / huds_max_render_time; 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(obj_cost_short); + LL_INFOS() << "HUD : hud[" << hud_ptr << " time:" << hud_render_time <<" total_time:" << huds_max_render_time << LL_ENDL; + row[1]["value"] = llformat("%.2f",((double)hud_render_time / 1000000000)); row[1]["font"]["name"] = "SANSSERIF"; row[2]["column"] = "name"; @@ -386,19 +452,28 @@ void LLFloaterPerformance::populateNearbyList() mNearbyList->clearRows(); mNearbyList->updateColumns(true); - static LLCachedControl max_render_cost(gSavedSettings, "RenderAvatarMaxComplexity", 0); + static LLCachedControl max_render_cost(gSavedSettings, "RenderAvatarMaxART", 0); + updateMaxRenderTime(); + updateMaxRenderTimeText(); + std::vector valid_nearby_avs; getNearbyAvatars(valid_nearby_avs); std::vector::iterator char_iter = valid_nearby_avs.begin(); - auto render_max = FSTelemetry::RecordObjectTime::getMax(FSTelemetry::ObjStatType::RENDER_COMBINED); + auto render_max = FSTelemetry::RecordObjectTime::getMax(FSTelemetry::ObjStatType::RENDER_COMBINED); while (char_iter != valid_nearby_avs.end()) { LLVOAvatar* avatar = dynamic_cast(*char_iter); - if (avatar && (LLVOAvatar::AOA_INVISIBLE != avatar->getOverallAppearance())) + if (avatar) { + auto overall_appearance = avatar->getOverallAppearance(); + if(overall_appearance == LLVOAvatar::AOA_INVISIBLE) + continue; + // S32 complexity_short = llmax((S32)avatar->getVisualComplexity() / 1000, 1); - auto render_av = FSTelemetry::RecordObjectTime::get(avatar,FSTelemetry::ObjStatType::RENDER_COMBINED); + auto render_av = FSTelemetry::RecordObjectTime::get(avatar,FSTelemetry::ObjStatType::RENDER_COMBINED); + auto is_slow = avatar->isTooSlow(); + LLSD item; item["id"] = avatar->getID(); LLSD& row = item["columns"]; @@ -412,8 +487,17 @@ void LLFloaterPerformance::populateNearbyList() row[1]["column"] = "complex_value"; row[1]["type"] = "text"; - row[1]["value"] = llformat("%.2f",((double)render_av / 1000000)); + if(is_slow) + { + row[1]["value"] = llformat("%.2f", ((double)avatar->getLastART() / 1000000)); + } + else + { + row[1]["value"] = llformat("%.2f",((double)render_av / 1000000)); + } + row[1]["font"]["name"] = "SANSSERIF"; + row[1]["width"] = "50"; row[2]["column"] = "name"; row[2]["type"] = "text"; @@ -438,7 +522,7 @@ void LLFloaterPerformance::populateNearbyList() else { std::string color = "white"; - if (LLVOAvatar::AOA_JELLYDOLL == avatar->getOverallAppearance()) + if (is_slow || LLVOAvatar::AOA_JELLYDOLL == overall_appearance) { color = "LabelDisabledColor"; LLScrollListBar* bar = dynamic_cast(av_item->getColumn(0)); @@ -447,7 +531,7 @@ void LLFloaterPerformance::populateNearbyList() bar->setColor(LLUIColorTable::instance().getColor(color)); } } - else if (LLVOAvatar::AOA_NORMAL == avatar->getOverallAppearance()) + else if (LLVOAvatar::AOA_NORMAL == overall_appearance) { color = LLAvatarActions::isFriend(avatar->getID()) ? "ConversationFriendColor" : "white"; } @@ -533,6 +617,22 @@ void LLFloaterPerformance::updateMaxComplexity() true); } +void LLFloaterPerformance::updateMaxRenderTime() +{ + LLAvatarComplexityControls::updateMaxRenderTime( + mNearbyPanel->getChild("RenderAvatarMaxART"), + mNearbyPanel->getChild("RenderAvatarMaxARTText"), + true); +} + +void LLFloaterPerformance::updateMaxRenderTimeText() +{ + LLAvatarComplexityControls::setRenderTimeText( + gSavedSettings.getF32("RenderAvatarMaxART"), + mNearbyPanel->getChild("RenderAvatarMaxARTText", true), + true); +} + void LLFloaterPerformance::updateComplexityText() { LLAvatarComplexityControls::setText(gSavedSettings.getU32("RenderAvatarMaxComplexity"), diff --git a/indra/newview/llfloaterperformance.h b/indra/newview/llfloaterperformance.h index a5549685f6..0e1289df23 100644 --- a/indra/newview/llfloaterperformance.h +++ b/indra/newview/llfloaterperformance.h @@ -65,6 +65,8 @@ private: void updateMaxComplexity(); void updateComplexityText(); + void updateMaxRenderTime(); + void updateMaxRenderTimeText(); void getNearbyAvatars(std::vector &valid_nearby_avs); @@ -84,6 +86,7 @@ private: S32 mNearbyMaxComplexity; boost::signals2::connection mComplexityChangedSignal; + boost::signals2::connection mMaxARTChangedSignal; }; #endif // LL_LLFLOATERPERFORMANCE_H diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp index bc70fadf89..4d7e07c36f 100644 --- a/indra/newview/llfloaterpreference.cpp +++ b/indra/newview/llfloaterpreference.cpp @@ -2874,6 +2874,28 @@ void LLAvatarComplexityControls::setText(U32 value, LLTextBox* text_box, bool sh } } +void LLAvatarComplexityControls::updateMaxRenderTime(LLSliderCtrl* slider, LLTextBox* value_label, bool short_val) +{ + // Called when the IndirectMaxComplexity control changes + // Responsible for fixing the slider label (IndirectMaxComplexityText) and setting RenderAvatarMaxComplexity + auto indirect_value = slider->getValue().asReal(); + + gSavedSettings.setF32("RenderAvatarMaxART", indirect_value); + setRenderTimeText(indirect_value, value_label, short_val); +} + +void LLAvatarComplexityControls::setRenderTimeText(F32 value, LLTextBox* text_box, bool short_val) +{ + if (0.0 == value) + { + text_box->setText(LLTrans::getString("no_limit")); + } + else + { + text_box->setText(llformat("%.2f", value)); + } +} + void LLFloaterPreference::updateMaxComplexity() { // Called when the IndirectMaxComplexity control changes diff --git a/indra/newview/llfloaterpreference.h b/indra/newview/llfloaterpreference.h index c73130a95e..008551f356 100644 --- a/indra/newview/llfloaterpreference.h +++ b/indra/newview/llfloaterpreference.h @@ -479,6 +479,8 @@ class LLAvatarComplexityControls public: 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 updateMaxRenderTime(LLSliderCtrl* slider, LLTextBox* value_label, bool short_val = false); + static void setRenderTimeText(F32 value, LLTextBox* text_box, bool short_val = false); static void setIndirectControls(); static void setIndirectMaxNonImpostors(); static void setIndirectMaxArc(); diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp index c1c8f0c2d1..7012301afc 100644 --- a/indra/newview/llvoavatar.cpp +++ b/indra/newview/llvoavatar.cpp @@ -4696,11 +4696,13 @@ void LLVOAvatar::updateFootstepSounds() void LLVOAvatar::computeUpdatePeriod() { bool visually_muted = isVisuallyMuted(); + bool slow = isTooSlow(); if (mDrawable.notNull() + && slow && isVisible() && (!isSelf() || visually_muted) && !isUIAvatar() - && (sLimitNonImpostors || visually_muted) + && (sLimitNonImpostors || visually_muted || slow) // imposter slow avatars irrespective of nonimposter setting. && !mNeedsAnimUpdate && !sFreezeCounter) { @@ -4712,8 +4714,11 @@ void LLVOAvatar::computeUpdatePeriod() const S32 UPDATE_RATE_SLOW = 64; const S32 UPDATE_RATE_MED = 48; const S32 UPDATE_RATE_FAST = 32; - - if (visually_muted) + if(slow) + { + mUpdatePeriod = UPDATE_RATE_FAST; + } + else if (visually_muted) { // visually muted avatars update at lowest rate mUpdatePeriod = UPDATE_RATE_SLOW; } @@ -9118,6 +9123,41 @@ BOOL LLVOAvatar::isFullyLoaded() const // return (mRenderUnloadedAvatar || mFullyLoaded); } +// use Avatar Render Time as complexity metric +//virtual +bool LLVOAvatar::isTooSlow() const +{ + static LLCachedControl use_render_time(gSavedSettings, "RenderAvatarUseART"); + auto now = LLTimer::getElapsedSeconds(); + if( ( mLastARTTime > 0 ) && ( now > (mLastARTTime + 2.0) ) ) //TODO(Beq) make this a constant. how frequently do we decloak to refresh the render time + { + // LL_INFOS() << this->getFullname() << " timer expired need refresh mLastARTTime=" << mLastARTTime << " time now="<(this)->mLastARTTime = 0; + return false; // force a render + } + else if (mLastARTTime == 0) + { + static LLCachedControl render_time_cap(gSavedSettings, "RenderAvatarMaxART"); + auto render_time = FSTelemetry::RecordObjectTime::get(this,FSTelemetry::ObjStatType::RENDER_COMBINED); + if( (render_time_cap > 0.0) && (render_time >= llround(render_time_cap*1000000)) ) + { + const_cast(this)->mLastARTTime = gFrameTimeSeconds; + const_cast(this)->mLastART = render_time; + // LL_INFOS() << this->getFullname() << " (imposter) mLastART too high =" << mLastART << " vs ("<< llround(render_time_cap*1000000) << " set @ " << mLastARTTime << LL_ENDL; + return true; + } + else + { + // LL_INFOS() << this->getFullname() << " good render time " << LL_ENDL; + return false; + } + } + // timer has not expired and time is non zero so must be true. + return true; +} +// + bool LLVOAvatar::isTooComplex() const { bool too_complex; @@ -10132,7 +10172,6 @@ void LLVOAvatar::processAvatarAppearance( LLMessageSystem* mesgsys ) //bool enable_verbose_dumps = gSavedSettings.getBOOL("DebugAvatarAppearanceMessage"); static LLCachedControl enable_verbose_dumps(gSavedSettings, "DebugAvatarAppearanceMessage"); // - std::string dump_prefix = getFullname() + "_" + (isSelf()?"s":"o") + "_"; if (gSavedSettings.getBOOL("BlockAvatarAppearanceMessages")) { LL_WARNS() << "Blocking AvatarAppearance message" << LL_ENDL; @@ -10145,6 +10184,7 @@ void LLVOAvatar::processAvatarAppearance( LLMessageSystem* mesgsys ) parseAppearanceMessage(mesgsys, *contents); if (enable_verbose_dumps) { + std::string dump_prefix = getFullname() + "_" + (isSelf()?"s":"o") + "_"; dumpAppearanceMsgParams(dump_prefix + "appearance_msg", *contents); } @@ -10426,6 +10466,7 @@ void LLVOAvatar::applyParsedAppearanceMessage(LLAppearanceMessageContents& conte updateMeshTextures(); updateMeshVisibility(); + markARTStale(); } @@ -11409,7 +11450,12 @@ void LLVOAvatar::updateImpostors() // virtual BOOL LLVOAvatar::isImpostor() { - return isVisuallyMuted() || (sLimitNonImpostors && (mUpdatePeriod > 1)); + return ( + isVisuallyMuted() || + ( + (sLimitNonImpostors || isTooSlow() ) && + (mUpdatePeriod > 1) + ); } BOOL LLVOAvatar::shouldImpostor(const F32 rank_factor) @@ -11422,6 +11468,12 @@ BOOL LLVOAvatar::shouldImpostor(const F32 rank_factor) { return true; } + static LLCachedControl render_jellys_As_imposters(gSavedSettings, "RenderJellyDollsAsImpostors"); + + if (isTooSlow() && render_jellys_As_imposters) + { + return true; + } return sLimitNonImpostors && (mVisibilityRank > sMaxNonImpostors * rank_factor); } @@ -11712,6 +11764,7 @@ void LLVOAvatar::accountRenderComplexityForObject( LLHUDComplexity hud_object_complexity; hud_object_complexity.objectName = attached_object->getAttachmentItemName(); hud_object_complexity.objectId = attached_object->getAttachmentItemID(); + hud_object_complexity.objectPtr = attached_object; std::string joint_name; gAgentAvatarp->getAttachedPointName(attached_object->getAttachmentItemID(), joint_name); hud_object_complexity.jointName = joint_name; diff --git a/indra/newview/llvoavatar.h b/indra/newview/llvoavatar.h index 0113a38dd8..96347701b5 100644 --- a/indra/newview/llvoavatar.h +++ b/indra/newview/llvoavatar.h @@ -368,6 +368,7 @@ public: //-------------------------------------------------------------------- public: BOOL isFullyLoaded() const; + virtual bool isTooSlow() const; virtual bool isTooComplex() const; // FIRE-29012: Standalone animesh avatars get affected by complexity limit; changed to virtual bool visualParamWeightsAreDefault(); virtual bool getIsCloud() const; @@ -406,6 +407,8 @@ private: LLColor4 mMutedAVColor; LLFrameTimer mFullyLoadedTimer; LLFrameTimer mRuthTimer; + F64SecondsImplicit mLastARTTime{0}; + U64 mLastART{0}; private: LLViewerStats::PhaseMap mPhases; @@ -1189,6 +1192,8 @@ public: // COF version of last appearance message received for this av. S32 mLastUpdateReceivedCOFVersion; + U64 getLastART() const { return mLastART; } + /** Diagnostics ** ** *******************************************************************************/ diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp index c4439858d3..21b97292c3 100644 --- a/indra/newview/pipeline.cpp +++ b/indra/newview/pipeline.cpp @@ -370,6 +370,7 @@ bool LLPipeline::sReflectionRender = false; bool LLPipeline::sDistortionRender = false; bool LLPipeline::sImpostorRender = false; bool LLPipeline::sImpostorRenderAlphaDepthPass = false; +bool LLPipeline::sShowJellyDollAsImpostor = true; bool LLPipeline::sUnderWaterRender = false; bool LLPipeline::sTextureBindTest = false; bool LLPipeline::sRenderFrameTest = false; @@ -1197,6 +1198,7 @@ void LLPipeline::refreshCachedSettings() LLPipeline::sAutoMaskAlphaDeferred = gSavedSettings.getBOOL("RenderAutoMaskAlphaDeferred"); LLPipeline::sAutoMaskAlphaNonDeferred = gSavedSettings.getBOOL("RenderAutoMaskAlphaNonDeferred"); LLPipeline::sUseFarClip = gSavedSettings.getBOOL("RenderUseFarClip"); + LLPipeline::sShowJellyDollAsImpostor = gSavedSettings.getBOOL("RenderJellyDollsAsImpostors"); LLVOAvatar::sMaxNonImpostors = gSavedSettings.getU32("RenderAvatarMaxNonImpostors"); LLVOAvatar::updateImpostorRendering(LLVOAvatar::sMaxNonImpostors); LLPipeline::sDelayVBUpdate = gSavedSettings.getBOOL("RenderDelayVBUpdate"); @@ -2831,6 +2833,7 @@ void LLPipeline::doOcclusion(LLCamera& camera, LLRenderTarget& source, LLRenderT void LLPipeline::doOcclusion(LLCamera& camera) { + FSZoneN("doOcclusion"); if (LLPipeline::sUseOcclusion > 1 && !LLSpatialPartition::sTeleportRequested && (sCull->hasOcclusionGroups() || LLVOCachePartition::sNeedsOcclusionCheck)) { @@ -11243,9 +11246,11 @@ void LLPipeline::generateImpostor(LLVOAvatar* avatar) << " is " << ( too_complex ? "" : "not ") << "too complex" << LL_ENDL; + bool too_slow = avatar->isTooSlow(); + pushRenderTypeMask(); - if (visually_muted || too_complex) + if ( !too_slow && ( visually_muted || too_complex ) ) { andRenderTypeMask(LLPipeline::RENDER_TYPE_AVATAR, LLPipeline::RENDER_TYPE_CONTROL_AV, diff --git a/indra/newview/pipeline.h b/indra/newview/pipeline.h index 92135d2fae..9ad6379c7b 100644 --- a/indra/newview/pipeline.h +++ b/indra/newview/pipeline.h @@ -600,6 +600,7 @@ public: static bool sDistortionRender; static bool sImpostorRender; static bool sImpostorRenderAlphaDepthPass; + static bool sShowJellyDollAsImpostor; static bool sUnderWaterRender; static bool sRenderGlow; static bool sTextureBindTest; diff --git a/indra/newview/skins/default/xui/en/floater_performance.xml b/indra/newview/skins/default/xui/en/floater_performance.xml index 0b67998f53..30be14a0ab 100644 --- a/indra/newview/skins/default/xui/en/floater_performance.xml +++ b/indra/newview/skins/default/xui/en/floater_performance.xml @@ -10,10 +10,16 @@ Scenery:[SCENE_FRAME_PCT]% Avatars:[AV_FRAME_PCT]% UI:[UI_FRAME_PCT]% HUDS:[HUDS_FRAME_PCT]% SWAP:[SWAP_FRAME_PCT]% TASKS:[IDLE_FRAME_PCT]% - FPS capped at [FPSCAP] + FPS capped at [FPSCAP] fps + + + Auto Tune target [FPSTARGET] fps [AV_FRAME_PCT]% + + +[HUDS_FRAME_PCT]% In Background @@ -72,7 +78,7 @@ height="28" layout="topleft" left_pad="10" - name="fps_sleep_warning" + name="fps_warning" top="8" width="150"> @@ -130,7 +136,7 @@ background_visible="true" follows="left|top" height="50" width="560" - name="settings_subpanel" + name="target_subpanel" layout="topleft" left="10" top="5"> @@ -144,7 +150,7 @@ background_visible="true" name="settings_lbl" top="7" width="180"> - Graphics settings + Target frame rate - Choose settings for distance, water, lighting and more. + width="350"> + Automatically tune display to give a smoother experience + - + + + Graphics settings + + + Choose settings for distance, water, lighting and more. + + + + - Avatars nearby + Avatars nearby - Manage which nearby avatars are fully displayed. - - + Manage which nearby avatars are fully displayed. + + Time spent @@ -274,7 +344,7 @@ avatars name="complexity_info" top_pad="0" width="455"> - Reduce the complexity of your avatar if you aren't satisfied with current FPS. + Be a good citizen. Manage the impact of your avatar - Removing HUDs you are not using can improve speed. + width="305"> + Removing unnecessary HUDs may improve speed. + +Time spent +drawing +HUDs + + + 00% + - + + + + 0 + + + + 0 + + + Date: Sun, 26 Sep 2021 00:08:26 +0100 Subject: [PATCH 170/256] Improvements to the auto tuning fps --- indra/newview/lldrawpoolavatar.cpp | 3 +- indra/newview/llfloaterperformance.cpp | 3 +- indra/newview/llfloaterpreference.cpp | 12 ++- indra/newview/llvoavatar.cpp | 91 +++++++++++++------ indra/newview/llvoavatar.h | 13 ++- .../xui/en/panel_performance_nearby.xml | 2 +- 6 files changed, 86 insertions(+), 38 deletions(-) diff --git a/indra/newview/lldrawpoolavatar.cpp b/indra/newview/lldrawpoolavatar.cpp index e8e6267cc6..767027e60d 100644 --- a/indra/newview/lldrawpoolavatar.cpp +++ b/indra/newview/lldrawpoolavatar.cpp @@ -587,7 +587,8 @@ void LLDrawPoolAvatar::renderShadow(S32 pass) // if (oa == LLVOAvatar::AOA_INVISIBLE || // (impostor && oa == LLVOAvatar::AOA_JELLYDOLL)) // Note: Impostors should not cast shadows, also all JDs are impostor nowadays so we do not need the extra check at all. - if (impostor || (oa == LLVOAvatar::AOA_INVISIBLE) ) + // also no shadows if the shadows are causing this avatar to breach the limit. + if ( avatarp->isTooSlow(true) || impostor || (oa == LLVOAvatar::AOA_INVISIBLE) ) // { // No shadows for jellydolled or invisible avs. diff --git a/indra/newview/llfloaterperformance.cpp b/indra/newview/llfloaterperformance.cpp index c967337773..8e0ca64368 100644 --- a/indra/newview/llfloaterperformance.cpp +++ b/indra/newview/llfloaterperformance.cpp @@ -472,7 +472,8 @@ void LLFloaterPerformance::populateNearbyList() // S32 complexity_short = llmax((S32)avatar->getVisualComplexity() / 1000, 1); auto render_av = FSTelemetry::RecordObjectTime::get(avatar,FSTelemetry::ObjStatType::RENDER_COMBINED); - auto is_slow = avatar->isTooSlow(); + auto is_slow = avatar->isTooSlow(true); + // auto is_slow_without_shadows = avatar->isTooSlow(); LLSD item; item["id"] = avatar->getID(); diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp index 4d7e07c36f..2cc8d63343 100644 --- a/indra/newview/llfloaterpreference.cpp +++ b/indra/newview/llfloaterpreference.cpp @@ -2879,9 +2879,17 @@ void LLAvatarComplexityControls::updateMaxRenderTime(LLSliderCtrl* slider, LLTex // Called when the IndirectMaxComplexity control changes // Responsible for fixing the slider label (IndirectMaxComplexityText) and setting RenderAvatarMaxComplexity auto indirect_value = slider->getValue().asReal(); - gSavedSettings.setF32("RenderAvatarMaxART", indirect_value); - setRenderTimeText(indirect_value, value_label, short_val); + if(indirect_value == slider->getMaxValue()) + { + LLVOAvatar::sRenderTimeCap_ns = 0; + setRenderTimeText(0.0, value_label, short_val); + } + else + { + LLVOAvatar::sRenderTimeCap_ns = llround(indirect_value * 1000000); + setRenderTimeText(indirect_value, value_label, short_val); + } } void LLAvatarComplexityControls::setRenderTimeText(F32 value, LLTextBox* text_box, bool short_val) diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp index 7012301afc..6e962c94b3 100644 --- a/indra/newview/llvoavatar.cpp +++ b/indra/newview/llvoavatar.cpp @@ -601,7 +601,7 @@ bool LLVOAvatar::sLimitNonImpostors = false; // True unless RenderAvatarMaxNonIm F32 LLVOAvatar::sRenderDistance = 256.f; S32 LLVOAvatar::sNumVisibleAvatars = 0; S32 LLVOAvatar::sNumLODChangesThisFrame = 0; - +U64 LLVOAvatar::sRenderTimeCap_ns {0}; // const LLUUID LLVOAvatar::sStepSoundOnLand("e8af4a28-aa83-4310-a7c4-c047e15ea0df"); - Commented out for FIRE-3169: Option to change the default footsteps sound const LLUUID LLVOAvatar::sStepSounds[LL_MCODE_END] = { @@ -4696,7 +4696,7 @@ void LLVOAvatar::updateFootstepSounds() void LLVOAvatar::computeUpdatePeriod() { bool visually_muted = isVisuallyMuted(); - bool slow = isTooSlow(); + bool slow = isTooSlow();// the geometry alone is forcing this to be slow so we must imposter if (mDrawable.notNull() && slow && isVisible() @@ -9124,37 +9124,71 @@ BOOL LLVOAvatar::isFullyLoaded() const } // use Avatar Render Time as complexity metric +void LLVOAvatar::markARTStale() +{ + // mark stale and set the frameupdate to now so that we can wait at least one frame. + mARTStale=true; + mLastARTUpdateFrame = LLFrameTimer::getFrameCount(); +} + +// default will test only the geometry (combined=false). +// this allows us to disable shadows separately on complex avatars. //virtual -bool LLVOAvatar::isTooSlow() const +bool LLVOAvatar::isTooSlow(bool combined) const { static LLCachedControl use_render_time(gSavedSettings, "RenderAvatarUseART"); auto now = LLTimer::getElapsedSeconds(); - if( ( mLastARTTime > 0 ) && ( now > (mLastARTTime + 2.0) ) ) //TODO(Beq) make this a constant. how frequently do we decloak to refresh the render time + auto abuse_constness = const_cast(this); + + if( mARTStale ) { - // LL_INFOS() << this->getFullname() << " timer expired need refresh mLastARTTime=" << mLastARTTime << " time now="<(this)->mLastARTTime = 0; - return false; // force a render - } - else if (mLastARTTime == 0) - { - static LLCachedControl render_time_cap(gSavedSettings, "RenderAvatarMaxART"); - auto render_time = FSTelemetry::RecordObjectTime::get(this,FSTelemetry::ObjStatType::RENDER_COMBINED); - if( (render_time_cap > 0.0) && (render_time >= llround(render_time_cap*1000000)) ) + if (LLFrameTimer::getFrameCount() - mLastARTUpdateFrame < 2 ) { - const_cast(this)->mLastARTTime = gFrameTimeSeconds; - const_cast(this)->mLastART = render_time; - // LL_INFOS() << this->getFullname() << " (imposter) mLastART too high =" << mLastART << " vs ("<< llround(render_time_cap*1000000) << " set @ " << mLastARTTime << LL_ENDL; - return true; - } - else - { - // LL_INFOS() << this->getFullname() << " good render time " << LL_ENDL; + LL_INFOS() << this->getFullname() << " marked stale " << LL_ENDL; + // we've not had a chance to update yet (allow now+1 to be certain a full frame has passed) return false; } + + abuse_constness->mARTStale = false; + abuse_constness->mARTCapped = false; + LL_INFOS() << this->getFullname() << " refreshed ART combined = " << mRenderTime << " @ " << mLastARTUpdateFrame << LL_ENDL; } - // timer has not expired and time is non zero so must be true. - return true; + + // Either we're not stale or we've updated. + U64 render_time; + U64 render_geom_time; + + if(!mARTCapped) + { + // no cap, so we use the live values + render_time = FSTelemetry::RecordObjectTime::get(this,FSTelemetry::ObjStatType::RENDER_COMBINED); + render_geom_time = FSTelemetry::RecordObjectTime::get(this,FSTelemetry::ObjStatType::RENDER_GEOMETRY); + } + else + { + // use the cached values. + render_time = mRenderTime; + render_geom_time = mGeomTime; + } + if( (LLVOAvatar::sRenderTimeCap_ns > 0) && (render_time >= LLVOAvatar::sRenderTimeCap_ns) ) + { + if(!mARTCapped) + { + // if we weren't capped, we are now + abuse_constness->mRenderTime = FSTelemetry::RecordObjectTime::get(this,FSTelemetry::ObjStatType::RENDER_COMBINED); + abuse_constness->mGeomTime = FSTelemetry::RecordObjectTime::get(this,FSTelemetry::ObjStatType::RENDER_GEOMETRY); + abuse_constness->mARTStale = false; + abuse_constness->mARTCapped = true; + abuse_constness->mLastARTUpdateFrame = LLFrameTimer::getFrameCount(); + LL_INFOS() << this->getFullname() << " ("<< (combined?"combined":"geometry") << ") mLastART too high = " << render_time << " vs ("<< LLVOAvatar::sRenderTimeCap_ns << " set @ " << mLastARTUpdateFrame << LL_ENDL; + } + // return true only if that is the case in the context of the combined/geom_only flag. + return combined ? true : (render_geom_time >= LLVOAvatar::sRenderTimeCap_ns); + } + + LL_INFOS() << this->getFullname() << " ("<< (combined?"combined":"geometry") << ") good render time = " << render_time << " vs ("<< LLVOAvatar::sRenderTimeCap_ns << " set @ " << mLastARTUpdateFrame << LL_ENDL; + abuse_constness->mARTCapped = false; + return false; } // @@ -11452,10 +11486,9 @@ BOOL LLVOAvatar::isImpostor() { return ( isVisuallyMuted() || - ( - (sLimitNonImpostors || isTooSlow() ) && - (mUpdatePeriod > 1) - ); + ( (sLimitNonImpostors || isTooSlow(false) ) && + (mUpdatePeriod > 1) ) + ); } BOOL LLVOAvatar::shouldImpostor(const F32 rank_factor) @@ -11470,7 +11503,7 @@ BOOL LLVOAvatar::shouldImpostor(const F32 rank_factor) } static LLCachedControl render_jellys_As_imposters(gSavedSettings, "RenderJellyDollsAsImpostors"); - if (isTooSlow() && render_jellys_As_imposters) + if (isTooSlow(false) && render_jellys_As_imposters) { return true; } diff --git a/indra/newview/llvoavatar.h b/indra/newview/llvoavatar.h index 96347701b5..c034a3b5aa 100644 --- a/indra/newview/llvoavatar.h +++ b/indra/newview/llvoavatar.h @@ -355,6 +355,7 @@ public: static F32 sPhysicsLODFactor; // user-settable physics LOD factor static BOOL sJointDebug; // output total number of joints being touched for each avatar static BOOL sDebugAvatarRotation; + static U64 sRenderTimeCap_ns; // nanosecond time limit for avatar rendering 0 is unlimited. static LLPartSysData sCloud; //-------------------------------------------------------------------- @@ -368,7 +369,7 @@ public: //-------------------------------------------------------------------- public: BOOL isFullyLoaded() const; - virtual bool isTooSlow() const; + virtual bool isTooSlow(bool combined = false) const; virtual bool isTooComplex() const; // FIRE-29012: Standalone animesh avatars get affected by complexity limit; changed to virtual bool visualParamWeightsAreDefault(); virtual bool getIsCloud() const; @@ -390,6 +391,7 @@ public: void logMetricsTimerRecord(const std::string& phase_name, F32 elapsed, bool completed); void calcMutedAVColor(); + void markARTStale(); protected: LLViewerStats::PhaseMap& getPhases() { return mPhases; } @@ -407,8 +409,11 @@ private: LLColor4 mMutedAVColor; LLFrameTimer mFullyLoadedTimer; LLFrameTimer mRuthTimer; - F64SecondsImplicit mLastARTTime{0}; - U64 mLastART{0}; + U32 mLastARTUpdateFrame{0}; + U64 mRenderTime{0}; + U64 mGeomTime{0}; + bool mARTStale{true}; + bool mARTCapped{false}; private: LLViewerStats::PhaseMap mPhases; @@ -1192,7 +1197,7 @@ public: // COF version of last appearance message received for this av. S32 mLastUpdateReceivedCOFVersion; - U64 getLastART() const { return mLastART; } + U64 getLastART() const { return mRenderTime; } /** Diagnostics ** ** 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 fd346bee0d..ad0710e6d0 100644 --- a/indra/newview/skins/default/xui/en/panel_performance_nearby.xml +++ b/indra/newview/skins/default/xui/en/panel_performance_nearby.xml @@ -101,7 +101,7 @@ label_width="165" layout="topleft" min_val="0.01" - max_val="10.0" + max_val="50.0" name="RenderAvatarMaxART" show_text="false" left_delta="-304" From e3b869e6f12a9d285ca3db4a2e7f4f0fa1ff8b26 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Mon, 27 Sep 2021 22:13:40 +0300 Subject: [PATCH 171/256] SL-16087 [D545] New clothes do not have the word 'New' in their names --- indra/newview/llwearablelist.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/indra/newview/llwearablelist.cpp b/indra/newview/llwearablelist.cpp index 00f8bace70..de01fbb73d 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 = LLWearableType::getInstance()->getTypeLabel(wearable->getType()); + // LLWearableType has pre-translated getTypeLabel(), but it returns 'name', not 'New Name'. + std::string name = LLTrans::getString( LLWearableType::getInstance()->getTypeDefaultNewName(wearable->getType()) ); wearable->setName( name ); LLPermissions perm; From adcd08fbf4d96f8f52cef81895bda202c9e45896 Mon Sep 17 00:00:00 2001 From: Andrey Lihatskiy Date: Tue, 28 Sep 2021 19:07:48 +0300 Subject: [PATCH 172/256] Revert "Merge branch 'c++17' into DRTVWR-522-maint" This reverts commit 203ea3a70a775a09cbbffb1740ab7c58f1780baa, reversing changes made to 8e3f0778863a5aa337d1148a243ea91d238a8ac5. # Conflicts: # indra/newview/llmachineid.cpp --- autobuild.xml | 14 +- indra/cmake/00-Common.cmake | 5 +- indra/edit-me-to-trigger-new-build.txt | 2 +- indra/llcommon/llsd.h | 43 +++++ indra/llcommon/llstl.h | 237 ++++++++++++++++++++++++- indra/llcommon/tests/llleap_test.cpp | 2 +- indra/llinventory/llparcel.cpp | 2 +- indra/llmessage/llcircuit.cpp | 11 +- indra/llmessage/lldispatcher.cpp | 2 +- indra/llmessage/llmessagethrottle.cpp | 22 +++ indra/llui/lldockablefloater.h | 4 +- indra/newview/llappearancemgr.h | 2 +- indra/newview/llexperiencelog.cpp | 4 + indra/newview/llfavoritesbar.cpp | 2 +- indra/newview/llfloaterregioninfo.cpp | 4 +- indra/newview/llgesturemgr.cpp | 2 +- indra/newview/lltoast.h | 2 +- indra/newview/llwatchdog.cpp | 4 +- indra/test/lldoubledispatch_tut.cpp | 8 +- 19 files changed, 338 insertions(+), 34 deletions(-) diff --git a/autobuild.xml b/autobuild.xml index e1e5c19871..5ad6f6293c 100644 --- a/autobuild.xml +++ b/autobuild.xml @@ -308,9 +308,9 @@ archive hash - f5a81594374c8a7f0825e2177510e079 + 02e6a8207dcdaf243dcb6da19b8c3534 url - https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/82030/770590/colladadom-2.3.559710-darwin64-559710.tar.bz2 + http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/64099/601302/colladadom-2.3.545362-darwin64-545362.tar.bz2 name darwin64 @@ -344,9 +344,9 @@ archive hash - 5d0729b835d63b7fe69acdc6b7c60188 + 8a02a10fc69c8f504dc5335644db184a url - https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/82050/770692/colladadom-2.3.559710-windows-559710.tar.bz2 + http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/64104/601313/colladadom-2.3.545362-windows-545362.tar.bz2 name windows @@ -356,16 +356,16 @@ archive hash - 985e3081e41c76b6176d39e44d7fb4b8 + 742180324fca7ab92b6a61a36aab4f9d url - https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/82049/770686/colladadom-2.3.559710-windows64-559710.tar.bz2 + http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/64103/601314/colladadom-2.3.545362-windows64-545362.tar.bz2 name windows64 version - 2.3.559710 + 2.3.545362 curl diff --git a/indra/cmake/00-Common.cmake b/indra/cmake/00-Common.cmake index 0da530c6a2..8aea50e02b 100644 --- a/indra/cmake/00-Common.cmake +++ b/indra/cmake/00-Common.cmake @@ -66,8 +66,7 @@ if (WINDOWS) # CP changed to only append the flag for 32bit builds - on 64bit builds, # locally at least, the build output is spammed with 1000s of 'D9002' # warnings about this switch being ignored. - # We need std::string_view, but that's not available without /std:c++17. - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /MP /std:c++17") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /MP") if( ADDRESS_SIZE EQUAL 32 ) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /p:PreferredToolArchitecture=x64") endif() @@ -176,7 +175,7 @@ if (DARWIN) # Until we decide to set -std=c++14 in viewer-build-variables/variables, set # it locally here: we want to at least prevent inadvertently reintroducing # viewer code that would fail with C++14. - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${DARWIN_extra_cstar_flags} -std=c++17") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${DARWIN_extra_cstar_flags} -std=c++14") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${DARWIN_extra_cstar_flags}") # NOTE: it's critical that the optimization flag is put in front. # NOTE: it's critical to have both CXX_FLAGS and C_FLAGS covered. diff --git a/indra/edit-me-to-trigger-new-build.txt b/indra/edit-me-to-trigger-new-build.txt index ade83202cf..5366987cff 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 +euclid 4/29/2021 \ No newline at end of file diff --git a/indra/llcommon/llsd.h b/indra/llcommon/llsd.h index 6638b25feb..5b6d5545af 100644 --- a/indra/llcommon/llsd.h +++ b/indra/llcommon/llsd.h @@ -413,6 +413,49 @@ public: static std::string typeString(Type type); // Return human-readable type as a string }; +struct llsd_select_bool : public std::unary_function +{ + LLSD::Boolean operator()(const LLSD& sd) const + { + return sd.asBoolean(); + } +}; +struct llsd_select_integer : public std::unary_function +{ + LLSD::Integer operator()(const LLSD& sd) const + { + return sd.asInteger(); + } +}; +struct llsd_select_real : public std::unary_function +{ + LLSD::Real operator()(const LLSD& sd) const + { + return sd.asReal(); + } +}; +struct llsd_select_float : public std::unary_function +{ + F32 operator()(const LLSD& sd) const + { + return (F32)sd.asReal(); + } +}; +struct llsd_select_uuid : public std::unary_function +{ + LLSD::UUID operator()(const LLSD& sd) const + { + return sd.asUUID(); + } +}; +struct llsd_select_string : public std::unary_function +{ + LLSD::String operator()(const LLSD& sd) const + { + return sd.asString(); + } +}; + LL_COMMON_API std::ostream& operator<<(std::ostream& s, const LLSD& llsd); namespace llsd diff --git a/indra/llcommon/llstl.h b/indra/llcommon/llstl.h index d28260b9f8..a90c2c7e08 100644 --- a/indra/llcommon/llstl.h +++ b/indra/llcommon/llstl.h @@ -40,6 +40,30 @@ // For strcmp #include #endif +// Use to compare the first element only of a pair +// e.g. typedef std::set, compare_pair > some_pair_set_t; +template +struct compare_pair_first +{ + bool operator()(const std::pair& a, const std::pair& b) const + { + return a.first < b.first; + } +}; + +template +struct compare_pair_greater +{ + bool operator()(const std::pair& a, const std::pair& b) const + { + if (!(a.first < b.first)) + return true; + else if (!(b.first < a.first)) + return false; + else + return !(a.second < b.second); + } +}; // Use to compare the contents of two pointers (e.g. std::string*) template @@ -99,6 +123,58 @@ struct DeletePairedPointerArray }; +// Alternate version of the above so that has a more cumbersome +// syntax, but it can be used with compositional functors. +// NOTE: The functor retuns a bool because msdev bombs during the +// composition if you return void. Once we upgrade to a newer +// compiler, the second unary_function template parameter can be set +// to void. +// +// Here's a snippet showing how you use this object: +// +// typedef std::map map_type; +// map_type widget_map; +// ... // add elements +// // delete them all +// for_each(widget_map.begin(), +// widget_map.end(), +// llcompose1(DeletePointerFunctor(), +// llselect2nd())); + +template +struct DeletePointerFunctor : public std::unary_function +{ + bool operator()(T* ptr) const + { + delete ptr; + return true; + } +}; + +// See notes about DeleteArray for why you should consider avoiding this. +template +struct DeleteArrayFunctor : public std::unary_function +{ + bool operator()(T* ptr) const + { + delete[] ptr; + return true; + } +}; + +// CopyNewPointer is a simple helper which accepts a pointer, and +// returns a new pointer built with the copy constructor. Example: +// +// transform(in.begin(), in.end(), out.end(), CopyNewPointer()); + +struct CopyNewPointer +{ + template T* operator()(const T* ptr) const + { + return new T(*ptr); + } +}; + template void delete_and_clear(std::list& list) { @@ -287,6 +363,161 @@ OutputIter ll_transform_n( } + +/* + * + * Copyright (c) 1994 + * Hewlett-Packard Company + * + * Permission to use, copy, modify, distribute and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. Hewlett-Packard Company makes no + * representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + * + * + * Copyright (c) 1996-1998 + * Silicon Graphics Computer Systems, Inc. + * + * Permission to use, copy, modify, distribute and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. Silicon Graphics makes no + * representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + */ + + +// helper to deal with the fact that MSDev does not package +// select... with the stl. Look up usage on the sgi website. + +template +struct _LLSelect1st : public std::unary_function<_Pair, typename _Pair::first_type> { + const typename _Pair::first_type& operator()(const _Pair& __x) const { + return __x.first; + } +}; + +template +struct _LLSelect2nd : public std::unary_function<_Pair, typename _Pair::second_type> +{ + const typename _Pair::second_type& operator()(const _Pair& __x) const { + return __x.second; + } +}; + +template struct llselect1st : public _LLSelect1st<_Pair> {}; +template struct llselect2nd : public _LLSelect2nd<_Pair> {}; + +// helper to deal with the fact that MSDev does not package +// compose... with the stl. Look up usage on the sgi website. + +template +class ll_unary_compose : + public std::unary_function +{ +protected: + _Operation1 __op1; + _Operation2 __op2; +public: + ll_unary_compose(const _Operation1& __x, const _Operation2& __y) + : __op1(__x), __op2(__y) {} + typename _Operation1::result_type + operator()(const typename _Operation2::argument_type& __x) const { + return __op1(__op2(__x)); + } +}; + +template +inline ll_unary_compose<_Operation1,_Operation2> +llcompose1(const _Operation1& __op1, const _Operation2& __op2) +{ + return ll_unary_compose<_Operation1,_Operation2>(__op1, __op2); +} + +template +class ll_binary_compose + : public std::unary_function { +protected: + _Operation1 _M_op1; + _Operation2 _M_op2; + _Operation3 _M_op3; +public: + ll_binary_compose(const _Operation1& __x, const _Operation2& __y, + const _Operation3& __z) + : _M_op1(__x), _M_op2(__y), _M_op3(__z) { } + typename _Operation1::result_type + operator()(const typename _Operation2::argument_type& __x) const { + return _M_op1(_M_op2(__x), _M_op3(__x)); + } +}; + +template +inline ll_binary_compose<_Operation1, _Operation2, _Operation3> +llcompose2(const _Operation1& __op1, const _Operation2& __op2, + const _Operation3& __op3) +{ + return ll_binary_compose<_Operation1,_Operation2,_Operation3> + (__op1, __op2, __op3); +} + +// helpers to deal with the fact that MSDev does not package +// bind... with the stl. Again, this is from sgi. +template +class llbinder1st : + public std::unary_function { +protected: + _Operation op; + typename _Operation::first_argument_type value; +public: + llbinder1st(const _Operation& __x, + const typename _Operation::first_argument_type& __y) + : op(__x), value(__y) {} + typename _Operation::result_type + operator()(const typename _Operation::second_argument_type& __x) const { + return op(value, __x); + } +}; + +template +inline llbinder1st<_Operation> +llbind1st(const _Operation& __oper, const _Tp& __x) +{ + typedef typename _Operation::first_argument_type _Arg1_type; + return llbinder1st<_Operation>(__oper, _Arg1_type(__x)); +} + +template +class llbinder2nd + : public std::unary_function { +protected: + _Operation op; + typename _Operation::second_argument_type value; +public: + llbinder2nd(const _Operation& __x, + const typename _Operation::second_argument_type& __y) + : op(__x), value(__y) {} + typename _Operation::result_type + operator()(const typename _Operation::first_argument_type& __x) const { + return op(__x, value); + } +}; + +template +inline llbinder2nd<_Operation> +llbind2nd(const _Operation& __oper, const _Tp& __x) +{ + typedef typename _Operation::second_argument_type _Arg2_type; + return llbinder2nd<_Operation>(__oper, _Arg2_type(__x)); +} + /** * Compare std::type_info* pointers a la std::less. We break this out as a * separate function for use in two different std::less specializations. @@ -317,7 +548,8 @@ bool before(const std::type_info* lhs, const std::type_info* rhs) namespace std { template <> - struct less + struct less: + public std::binary_function { bool operator()(const std::type_info* lhs, const std::type_info* rhs) const { @@ -326,7 +558,8 @@ namespace std }; template <> - struct less + struct less: + public std::binary_function { bool operator()(std::type_info* lhs, std::type_info* rhs) const { diff --git a/indra/llcommon/tests/llleap_test.cpp b/indra/llcommon/tests/llleap_test.cpp index fd96aa01d5..9d71e327d8 100644 --- a/indra/llcommon/tests/llleap_test.cpp +++ b/indra/llcommon/tests/llleap_test.cpp @@ -530,7 +530,7 @@ namespace tut result.ensure(); } - struct TestLargeMessage + struct TestLargeMessage: public std::binary_function { TestLargeMessage(const std::string& PYTHON_, const std::string& reader_module_, const std::string& test_name_): diff --git a/indra/llinventory/llparcel.cpp b/indra/llinventory/llparcel.cpp index 2f577bfb07..e2469f3c7e 100644 --- a/indra/llinventory/llparcel.cpp +++ b/indra/llinventory/llparcel.cpp @@ -1268,5 +1268,5 @@ U32 LLParcel::countExperienceKeyType( U32 type ) return std::count_if( boost::begin(mExperienceKeys | boost::adaptors::map_values), boost::end(mExperienceKeys | boost::adaptors::map_values), - [type](U32 key){ return key == type; }); + std::bind2nd(std::equal_to(), type)); } diff --git a/indra/llmessage/llcircuit.cpp b/indra/llmessage/llcircuit.cpp index a39989515e..8baa2e328b 100644 --- a/indra/llmessage/llcircuit.cpp +++ b/indra/llmessage/llcircuit.cpp @@ -436,11 +436,12 @@ LLCircuit::LLCircuit(const F32Seconds circuit_heartbeat_interval, const F32Secon LLCircuit::~LLCircuit() { - // delete pointers in the map. - for (auto circ_pair : mCircuitData) - { - delete circ_pair.second; - } + // delete pointers in the map. + std::for_each(mCircuitData.begin(), + mCircuitData.end(), + llcompose1( + DeletePointerFunctor(), + llselect2nd())); } LLCircuitData *LLCircuit::addCircuitData(const LLHost &host, TPACKETID in_id) diff --git a/indra/llmessage/lldispatcher.cpp b/indra/llmessage/lldispatcher.cpp index 8dfd924f31..717ef10f70 100644 --- a/indra/llmessage/lldispatcher.cpp +++ b/indra/llmessage/lldispatcher.cpp @@ -62,7 +62,7 @@ void LLDispatcher::copyAllHandlerNames(keys_t& names) const mHandlers.begin(), mHandlers.end(), std::back_insert_iterator(names), - [](const dispatch_map_t::value_type& pair){ return pair.first; }); + llselect1st()); } bool LLDispatcher::dispatch( diff --git a/indra/llmessage/llmessagethrottle.cpp b/indra/llmessage/llmessagethrottle.cpp index c5ae8b4547..579d6d7187 100644 --- a/indra/llmessage/llmessagethrottle.cpp +++ b/indra/llmessage/llmessagethrottle.cpp @@ -32,8 +32,18 @@ #include "llframetimer.h" // This is used for the stl search_n function. +#if _MSC_VER >= 1500 // VC9 has a bug in search_n +struct eq_message_throttle_entry : public std::binary_function< LLMessageThrottleEntry, LLMessageThrottleEntry, bool > +{ + bool operator()(const LLMessageThrottleEntry& a, const LLMessageThrottleEntry& b) const + { + return a.getHash() == b.getHash(); + } +}; +#else bool eq_message_throttle_entry(LLMessageThrottleEntry a, LLMessageThrottleEntry b) { return a.getHash() == b.getHash(); } +#endif const U64 SEC_TO_USEC = 1000000; @@ -108,8 +118,14 @@ BOOL LLMessageThrottle::addViewerAlert(const LLUUID& to, const std::string& mesg LLMessageThrottleEntry entry(hash, LLFrameTimer::getTotalTime()); // Check if this message is already in the list. +#if _MSC_VER >= 1500 // VC9 has a bug in search_n + // SJB: This *should* work but has not been tested yet *TODO: Test! + message_list_iterator_t found = std::find_if(message_list->begin(), message_list->end(), + std::bind2nd(eq_message_throttle_entry(), entry)); +#else message_list_iterator_t found = std::search_n(message_list->begin(), message_list->end(), 1, entry, eq_message_throttle_entry); +#endif if (found == message_list->end()) { // This message was not found. Add it to the list. @@ -136,8 +152,14 @@ BOOL LLMessageThrottle::addAgentAlert(const LLUUID& agent, const LLUUID& task, c LLMessageThrottleEntry entry(hash, LLFrameTimer::getTotalTime()); // Check if this message is already in the list. +#if _MSC_VER >= 1500 // VC9 has a bug in search_n + // SJB: This *should* work but has not been tested yet *TODO: Test! + message_list_iterator_t found = std::find_if(message_list->begin(), message_list->end(), + std::bind2nd(eq_message_throttle_entry(), entry)); +#else message_list_iterator_t found = std::search_n(message_list->begin(), message_list->end(), 1, entry, eq_message_throttle_entry); +#endif if (found == message_list->end()) { diff --git a/indra/llui/lldockablefloater.h b/indra/llui/lldockablefloater.h index 1110342f08..89c9852f4a 100644 --- a/indra/llui/lldockablefloater.h +++ b/indra/llui/lldockablefloater.h @@ -108,7 +108,7 @@ public: * * By default returns false. */ - virtual bool overlapsScreenChannel() const { return mOverlapsScreenChannel && getVisible() && isDocked(); } + virtual bool overlapsScreenChannel() { return mOverlapsScreenChannel && getVisible() && isDocked(); } virtual void setOverlapsScreenChannel(bool overlaps) { mOverlapsScreenChannel = overlaps; } bool getUniqueDocking() { return mUniqueDocking; } @@ -131,7 +131,7 @@ protected: boost::function mIsDockedStateForcedCallback; private: - std::unique_ptr mDockControl; + std::auto_ptr mDockControl; LLUIImagePtr mDockTongue; static LLHandle sInstanceHandle; /** diff --git a/indra/newview/llappearancemgr.h b/indra/newview/llappearancemgr.h index a5265a392f..8a55a848db 100644 --- a/indra/newview/llappearancemgr.h +++ b/indra/newview/llappearancemgr.h @@ -276,7 +276,7 @@ private: LLUUID mCOFImageID; - std::unique_ptr mUnlockOutfitTimer; + std::auto_ptr mUnlockOutfitTimer; // Set of temp attachment UUIDs that should be removed typedef std::set doomed_temp_attachments_t; diff --git a/indra/newview/llexperiencelog.cpp b/indra/newview/llexperiencelog.cpp index c441fbc09f..ee5d561927 100644 --- a/indra/newview/llexperiencelog.cpp +++ b/indra/newview/llexperiencelog.cpp @@ -149,6 +149,10 @@ std::string LLExperienceLog::getPermissionString( const LLSD& message, const std { buf.str(entry); } + else + { + buf.str(); + } } if(buf.str().empty()) diff --git a/indra/newview/llfavoritesbar.cpp b/indra/newview/llfavoritesbar.cpp index a7147c3f04..cca6b9ce32 100644 --- a/indra/newview/llfavoritesbar.cpp +++ b/indra/newview/llfavoritesbar.cpp @@ -841,7 +841,7 @@ void LLFavoritesBarCtrl::updateButtons(bool force_update) { //find last visible child to get the rightest button offset child_list_const_reverse_iter_t last_visible_it = std::find_if(childs->rbegin(), childs->rend(), - [](child_list_t::value_type child){ return child->getVisible(); }); + std::mem_fun(&LLView::getVisible)); if(last_visible_it != childs->rend()) { last_right_edge = (*last_visible_it)->getRect().mRight; diff --git a/indra/newview/llfloaterregioninfo.cpp b/indra/newview/llfloaterregioninfo.cpp index a10ba7a39d..17e55b5f2c 100644 --- a/indra/newview/llfloaterregioninfo.cpp +++ b/indra/newview/llfloaterregioninfo.cpp @@ -659,7 +659,9 @@ void LLFloaterRegionInfo::refreshFromRegion(LLViewerRegion* region) std::for_each( mInfoPanels.begin(), mInfoPanels.end(), - [region](info_panels_t::value_type panel){ panel->refreshFromRegion(region); }); + llbind2nd( + std::mem_fun(&LLPanelRegionInfo::refreshFromRegion), + region)); mEnvironmentPanel->refreshFromRegion(region); } diff --git a/indra/newview/llgesturemgr.cpp b/indra/newview/llgesturemgr.cpp index eb0e77311b..950a6cfaef 100644 --- a/indra/newview/llgesturemgr.cpp +++ b/indra/newview/llgesturemgr.cpp @@ -752,7 +752,7 @@ S32 LLGestureMgr::getPlayingCount() const } -struct IsGesturePlaying +struct IsGesturePlaying : public std::unary_function { bool operator()(const LLMultiGesture* gesture) const { diff --git a/indra/newview/lltoast.h b/indra/newview/lltoast.h index 2b1fedf74d..69074b1670 100644 --- a/indra/newview/lltoast.h +++ b/indra/newview/lltoast.h @@ -222,7 +222,7 @@ private: LLPanel* mWrapperPanel; // timer counts a lifetime of a toast - std::unique_ptr mTimer; + std::auto_ptr mTimer; F32 mToastLifetime; // in seconds F32 mToastFadingTime; // in seconds diff --git a/indra/newview/llwatchdog.cpp b/indra/newview/llwatchdog.cpp index a3036ff6d0..0aa0280b25 100644 --- a/indra/newview/llwatchdog.cpp +++ b/indra/newview/llwatchdog.cpp @@ -224,7 +224,7 @@ void LLWatchdog::run() LL_INFOS() << "Watchdog thread delayed: resetting entries." << LL_ENDL; std::for_each(mSuspects.begin(), mSuspects.end(), - [](SuspectsRegistry::value_type suspect){ suspect->reset(); } + std::mem_fun(&LLWatchdogEntry::reset) ); } else @@ -232,7 +232,7 @@ void LLWatchdog::run() SuspectsRegistry::iterator result = std::find_if(mSuspects.begin(), mSuspects.end(), - [](SuspectsRegistry::value_type suspect){ return ! suspect->isAlive(); } + std::not1(std::mem_fun(&LLWatchdogEntry::isAlive)) ); if(result != mSuspects.end()) { diff --git a/indra/test/lldoubledispatch_tut.cpp b/indra/test/lldoubledispatch_tut.cpp index e38d0e92a3..ad8f6454d4 100644 --- a/indra/test/lldoubledispatch_tut.cpp +++ b/indra/test/lldoubledispatch_tut.cpp @@ -135,10 +135,10 @@ namespace tut // Instantiate a few GameObjects. Make sure we refer to them // polymorphically, and don't let them leak. - std::unique_ptr home; - std::unique_ptr obstacle; - std::unique_ptr tug; - std::unique_ptr patrol; + std::auto_ptr home; + std::auto_ptr obstacle; + std::auto_ptr tug; + std::auto_ptr patrol; // prototype objects Asteroid dummyAsteroid; From 70551782f1c4627f9a7b75c720b0d1d8499bcbb0 Mon Sep 17 00:00:00 2001 From: Andrey Lihatskiy Date: Tue, 28 Sep 2021 19:44:52 +0300 Subject: [PATCH 173/256] DRTVWR-545 New line for the coding policy check --- indra/edit-me-to-trigger-new-build.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 From 390c13643096bb6e16e82d2c4e913f18f4d69ba0 Mon Sep 17 00:00:00 2001 From: Beq Date: Wed, 13 Oct 2021 02:04:05 +0100 Subject: [PATCH 174/256] Migrate perfstats away from telemetry/profiling perfstats is now a standalone module. --- indra/llcommon/CMakeLists.txt | 19 +- indra/llcommon/fsperfstats.cpp | 36 +++ indra/llcommon/fsperfstats.h | 299 +++++++++++++++++++++++++ indra/llcommon/fstelemetry.cpp | 6 - indra/llcommon/fstelemetry.h | 167 +------------- indra/newview/llappviewer.cpp | 14 +- indra/newview/llavatarrendernotifier.h | 5 + indra/newview/lldrawpool.cpp | 22 ++ indra/newview/lldrawpoolalpha.cpp | 44 ++++ indra/newview/lldrawpoolavatar.cpp | 50 ++++- indra/newview/lldrawpoolbump.cpp | 39 ++++ indra/newview/lldrawpoolmaterials.cpp | 25 ++- indra/newview/llface.cpp | 15 ++ indra/newview/llfloaterperformance.cpp | 37 +-- indra/newview/llviewerdisplay.cpp | 7 +- indra/newview/llviewerjointmesh.cpp | 18 ++ indra/newview/llvoavatar.cpp | 13 +- indra/newview/llvovolume.cpp | 16 +- 18 files changed, 619 insertions(+), 213 deletions(-) create mode 100644 indra/llcommon/fsperfstats.cpp create mode 100644 indra/llcommon/fsperfstats.h diff --git a/indra/llcommon/CMakeLists.txt b/indra/llcommon/CMakeLists.txt index 9664617fa4..463f8286a0 100644 --- a/indra/llcommon/CMakeLists.txt +++ b/indra/llcommon/CMakeLists.txt @@ -258,13 +258,18 @@ set(llcommon_HEADER_FILES StackWalker.h ) -# Add all nd* files. memory pool, intrinsics, ... -# Tracy Profiler support -list(APPEND llcommon_SOURCE_FILES fstelemetry.cpp) -if (USE_TRACY_PROFILER) - list(APPEND llcommon_SOURCE_FILES fstracyclient.cpp) -endif() - + # Tracy Profiler support + list(APPEND llcommon_SOURCE_FILES fstelemetry.cpp) + if (USE_TRACY_PROFILER) + list(APPEND llcommon_SOURCE_FILES fstracyclient.cpp) + endif() + # Tracy Profiler support + # Performance stast support + list(APPEND llcommon_SOURCE_FILES fsperfstats.cpp) + list(APPEND llcommon_HEADER_FILES fsperfstats.h) + # + + # Add all nd* files. memory pool, intrinsics, ... SET( llcommon_ND_SOURCE_FILES nd/ndexceptions.cpp nd/ndlogthrottle.cpp diff --git a/indra/llcommon/fsperfstats.cpp b/indra/llcommon/fsperfstats.cpp new file mode 100644 index 0000000000..f428b83d9f --- /dev/null +++ b/indra/llcommon/fsperfstats.cpp @@ -0,0 +1,36 @@ +/** + * @file fsperfstats.cpp + * @brief Stats collection to support perf floater and auto tune + * + * $LicenseInfo:firstyear=2021&license=fsviewerlgpl$ + * Phoenix Firestorm Viewer Source Code + * Copyright (C) 2021, The Phoenix Firestorm Project, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * The Phoenix Firestorm Project, Inc., 1831 Oakwood Drive, Fairmont, Minnesota 56031-3225 USA + * http://www.firestormviewer.org + * $/LicenseInfo$ + */ +#include "fsperfstats.h" +namespace FSPerfStats +{ + int RecordSceneTime::writeBuffer{0}; + + bool RecordSceneTime::collectionEnabled{true}; + + std::array< typename RecordSceneTime::StatsArray, 2 > RecordSceneTime::stats{ {} }; + +} \ No newline at end of file diff --git a/indra/llcommon/fsperfstats.h b/indra/llcommon/fsperfstats.h new file mode 100644 index 0000000000..cab3679dcd --- /dev/null +++ b/indra/llcommon/fsperfstats.h @@ -0,0 +1,299 @@ +#pragma once +#ifndef FS_PERFSTATS_H_INCLUDED +#define FS_PERFSTATS_H_INCLUDED +/** + * @file fsperfstats.h + * @brief Statistics collection to support autotune and perf flaoter. + * + * $LicenseInfo:firstyear=2021&license=fsviewerlgpl$ + * Phoenix Firestorm Viewer Source Code + * Copyright (C) 2021, The Phoenix Firestorm Project, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * The Phoenix Firestorm Project, Inc., 1831 Oakwood Drive, Fairmont, Minnesota 56031-3225 USA + * http://www.firestormviewer.org + * $/LicenseInfo$ + */ + +#include +#include +#include + +namespace FSPerfStats +{ + enum class ObjStatType_t{ + RENDER_GEOMETRY=0, + RENDER_SHADOWS, + RENDER_COMBINED, + STATS_COUNT + }; + enum class SceneStatType_t{ + RENDER_GEOMETRY=0, + RENDER_SHADOWS, + RENDER_HUDS, + RENDER_UI, + RENDER_COMBINED, + RENDER_SWAP, + RENDER_FRAME, + RENDER_SLEEP, + RENDER_LFS, + RENDER_MESHREPO, + RENDER_FPSLIMIT, + RENDER_FPS, + RENDER_IDLE, + STATS_COUNT + }; + + using ObjStatType = ObjStatType_t; + using SceneStatType = SceneStatType_t; + + class RecordSceneTime + { + using StatsEnum = SceneStatType; + using StatsArray = std::array(StatsEnum::STATS_COUNT)>; + // using StatsBlock = std::unordered_map; + + static int writeBuffer; + static std::array stats; + static bool collectionEnabled; + + RecordSceneTime(const RecordSceneTime&) = delete; + RecordSceneTime() = delete; + + const StatsEnum type; + std::chrono::steady_clock::time_point start; + public: + + static inline void enable(){collectionEnabled=true;}; + static inline void disable(){collectionEnabled=false;}; + static inline bool enabled(){return(collectionEnabled);}; + + RecordSceneTime(SceneStatType type):start{std::chrono::steady_clock::now()}, type{type} {} + + ~RecordSceneTime() + { + auto val = std::chrono::duration(std::chrono::steady_clock::now() - start).count(); + stats[writeBuffer][static_cast(type)] += val; + }; + + static inline void toggleBuffer() + { + if(enabled()) + { + // stats[writeBuffer][static_cast(SceneStatType::RENDER_FPS)] = LLTrace::get_frame_recording().getPeriodMeanPerSec(LLStatViewer::FPS,3); // last 3 Frames + writeBuffer = (writeBuffer+1)%2; + }; // not we are relying on atomic updates here. The risk is low and would cause minor errors in the stats display. + + auto& statsArray = stats[writeBuffer]; + std::fill_n(statsArray.begin() ,static_cast(SceneStatType::STATS_COUNT),0); + } + static inline int getReadBufferIndex(){return (writeBuffer+1)%2;}; + static inline StatsArray getCurrentStatsBuffer(){ return stats[getReadBufferIndex()];} + static inline uint64_t get(StatsEnum type){return stats[getReadBufferIndex()][static_cast(type)];} + }; + + template + class RecordObjectTime + { + using StatsEnum = ObjStatType; + using StatsArray = std::array(StatsEnum::STATS_COUNT)>; + using StatsBlock = std::unordered_map; + + static int writeBuffer; + static std::array stats; + + static std::array max; + static std::array sum; + static bool collectionEnabled; + + RecordObjectTime(const RecordObjectTime&) = delete; + RecordObjectTime() = delete; + const T key; + const StatsEnum type; + std::chrono::steady_clock::time_point start; + + public: + static inline void enable(){collectionEnabled=true;}; + static inline void disable(){collectionEnabled=false;}; + static inline bool enabled(){return(collectionEnabled);}; + + RecordObjectTime(T key, ObjStatType type):start{std::chrono::steady_clock::now()}, key{key}, type{type} {} + + ~RecordObjectTime() + { + using ST = StatsEnum; + // Note: nullptr is used as the key for global stats + constexpr auto period{500}; + auto val = std::chrono::duration(std::chrono::steady_clock::now() - start).count(); + if(key) + { + stats[writeBuffer][key][static_cast(type)] += val; + stats[writeBuffer][key][static_cast(ST::RENDER_COMBINED)] += val; + if(max[writeBuffer][static_cast(type)] < stats[writeBuffer][key][static_cast(type)]) + { + max[writeBuffer][static_cast(type)] = stats[writeBuffer][key][static_cast(type)]; + } + if(max[writeBuffer][static_cast(ST::RENDER_COMBINED)] < stats[writeBuffer][key][static_cast(ST::RENDER_COMBINED)]) + { + max[writeBuffer][static_cast(ST::RENDER_COMBINED)] = stats[writeBuffer][key][static_cast(ST::RENDER_COMBINED)]; + } + sum[writeBuffer][static_cast(type)] += val; + sum[writeBuffer][static_cast(ST::RENDER_COMBINED)] += val; + } + }; + static inline void toggleBuffer() + { + using ST = StatsEnum; + + // auto& statsMap = stats[writeBuffer]; + // for(auto& stat_entry : statsMap) + // { + // auto val = stat_entry.second[static_cast(ST::RENDER_COMBINED)]; + // auto avg = stats[(writeBuffer+1)%2][stat_entry.first][static_cast(ST::RENDER_COMBINED)]; + // stat_entry.second[static_cast(ST::RENDER_COMBINED)] = avg + (val/500) - (avg/500); + // } + if(enabled()) + { + writeBuffer = (writeBuffer+1)%2; + }; // note we are relying on atomic updates here. The risk is low and would cause minor errors in the stats display. + auto& statsMap = stats[writeBuffer]; + for(auto& stat_entry : statsMap) + { + std::fill_n(stat_entry.second.begin() ,static_cast(ST::STATS_COUNT),0); + } + statsMap.clear(); + std::fill_n(max[writeBuffer].begin(),static_cast(ST::STATS_COUNT),0); + std::fill_n(sum[writeBuffer].begin(),static_cast(ST::STATS_COUNT),0); + } + static inline int getReadbufferIndex(){return (writeBuffer+1)%2;}; + static inline StatsBlock& getCurrentStatsBuffer(){ return stats[(writeBuffer+1)%2]; } + static inline uint64_t getMax(StatsEnum type){return max[(writeBuffer+1)%2][static_cast(type)];} + static inline uint64_t getSum(StatsEnum type){return sum[(writeBuffer+1)%2][static_cast(type)];} + static inline uint64_t getNum(){return stats[(writeBuffer+1)%2].size();} + static inline uint64_t get(T key, StatsEnum type){return stats[(writeBuffer+1)%2][key][static_cast(type)];} + }; + template + class RecordAttachmentTime + { + using StatsEnum = ObjStatType; + using StatsArray = std::array(StatsEnum::STATS_COUNT)>; + using StatsBlock = std::unordered_map; + + static int writeBuffer; + static std::array stats; + + static std::array max; + static std::array sum; + static bool collectionEnabled; + + RecordAttachmentTime(const RecordAttachmentTime&) = delete; + RecordAttachmentTime() = delete; + const T key; + const StatsEnum type; + std::chrono::steady_clock::time_point start; + + public: + static inline void enable(){collectionEnabled=true;}; + static inline void disable(){collectionEnabled=false;}; + static inline bool enabled(){return(collectionEnabled);}; + + RecordAttachmentTime(T key, ObjStatType type):start{std::chrono::steady_clock::now()}, key{key}, type{type} {} + + ~RecordAttachmentTime() + { + using ST = StatsEnum; + // Note: nullptr is used as the key for global stats + auto val = std::chrono::duration(std::chrono::steady_clock::now() - start).count(); + stats[writeBuffer][key][static_cast(type)] += val; + stats[writeBuffer][key][static_cast(ST::RENDER_COMBINED)] += val; + if(max[writeBuffer][static_cast(type)] < stats[writeBuffer][key][static_cast(type)]) + { + max[writeBuffer][static_cast(type)] = stats[writeBuffer][key][static_cast(type)]; + } + if(max[writeBuffer][static_cast(ST::RENDER_COMBINED)] < stats[writeBuffer][key][static_cast(ST::RENDER_COMBINED)]) + { + max[writeBuffer][static_cast(ST::RENDER_COMBINED)] = stats[writeBuffer][key][static_cast(ST::RENDER_COMBINED)]; + } + sum[writeBuffer][static_cast(type)] += val; + sum[writeBuffer][static_cast(ST::RENDER_COMBINED)] += val; + }; + static inline void toggleBuffer() + { + using ST = StatsEnum; + if(enabled()) + { + writeBuffer = (writeBuffer+1)%2; + }; // note we are relying on atomic updates here. The risk is low and would cause minor errors in the stats display. + + auto& statsMap = stats[writeBuffer]; + for(auto& stat_entry : statsMap) + { + std::fill_n(stat_entry.second.begin() ,static_cast(ST::STATS_COUNT),0); + } + statsMap.clear(); + std::fill_n(max[writeBuffer].begin(),static_cast(ST::STATS_COUNT),0); + std::fill_n(sum[writeBuffer].begin(),static_cast(ST::STATS_COUNT),0); + } + static inline int getReadbufferIndex(){return (writeBuffer+1)%2;}; + static inline StatsBlock& getCurrentStatsBuffer(){ return stats[(writeBuffer+1)%2]; } + static inline uint64_t getMax(StatsEnum type){return max[(writeBuffer+1)%2][static_cast(type)];} + static inline uint64_t getSum(StatsEnum type){return sum[(writeBuffer+1)%2][static_cast(type)];} + static inline uint64_t getNum(){return stats[(writeBuffer+1)%2].size();} + static inline uint64_t get(T key, StatsEnum type){return stats[(writeBuffer+1)%2][key][static_cast(type)];} + }; + + static inline void toggleBuffer() + { + // RecordObjectTime::toggleBuffer(); + RecordSceneTime::toggleBuffer(); + } + + template< typename T > + int RecordObjectTime::writeBuffer{0}; + + template< typename T > + bool RecordObjectTime::collectionEnabled{true}; + + template< typename T > + std::array< typename RecordObjectTime< T >::StatsArray, 2 > RecordObjectTime::max; + + template< typename T > + std::array< typename RecordObjectTime< T >::StatsArray, 2 > RecordObjectTime::sum; + + template< typename T > + std::array< typename RecordObjectTime< T >::StatsBlock, 2 > RecordObjectTime< T >::stats{ {{}} }; + + template< typename T > + int RecordAttachmentTime::writeBuffer{0}; + + template< typename T > + bool RecordAttachmentTime::collectionEnabled{true}; + + template< typename T > + std::array< typename RecordAttachmentTime< T >::StatsArray, 2 > RecordAttachmentTime::max; + + template< typename T > + std::array< typename RecordAttachmentTime< T >::StatsArray, 2 > RecordAttachmentTime::sum; + + template< typename T > + std::array< typename RecordAttachmentTime< T >::StatsBlock, 2 > RecordAttachmentTime< T >::stats{ {{}} }; +}// namespace FSPerfStats + + + + + +#endif \ No newline at end of file diff --git a/indra/llcommon/fstelemetry.cpp b/indra/llcommon/fstelemetry.cpp index 12c31d521d..7be6e4b6bb 100644 --- a/indra/llcommon/fstelemetry.cpp +++ b/indra/llcommon/fstelemetry.cpp @@ -29,10 +29,4 @@ namespace FSTelemetry { bool active{false}; - int RecordSceneTime::writeBuffer{0}; - - bool RecordSceneTime::collectionEnabled{true}; - - std::array< typename RecordSceneTime::StatsArray, 2 > RecordSceneTime::stats{ {} }; - } \ No newline at end of file diff --git a/indra/llcommon/fstelemetry.h b/indra/llcommon/fstelemetry.h index 3d8560bb3d..ca9d33f9fe 100644 --- a/indra/llcommon/fstelemetry.h +++ b/indra/llcommon/fstelemetry.h @@ -46,6 +46,7 @@ #define FSPlot( name, value ) TracyPlot( name, value) #define FSFrameMark FrameMark #define FSThreadName( name ) tracy::SetThreadName( name ) +#define FSMessageL ( message ) tracy::Profiler::Message( message, 0 ) #define FSTelemetryIsConnected TracyIsConnected #else // (no telemetry) @@ -60,6 +61,7 @@ #define FSPlot( name, value ) #define FSFrameMark #define FSThreadName( name ) +#define FSMessageL ( message ) #define FSTelemetryIsConnected #endif // TRACY_ENABLE @@ -71,171 +73,6 @@ namespace FSTelemetry { extern bool active; - enum class ObjStatType_t{ - RENDER_GEOMETRY=0, - RENDER_SHADOWS, - RENDER_COMBINED, - STATS_COUNT - }; - enum class SceneStatType_t{ - RENDER_GEOMETRY=0, - RENDER_SHADOWS, - RENDER_HUDS, - RENDER_UI, - RENDER_COMBINED, - RENDER_SWAP, - RENDER_FRAME, - RENDER_SLEEP, - RENDER_LFS, - RENDER_MESHREPO, - RENDER_FPSLIMIT, - RENDER_FPS, - RENDER_IDLE, - STATS_COUNT - }; - - using ObjStatType = ObjStatType_t; - using SceneStatType = SceneStatType_t; - - class RecordSceneTime - { - using StatsEnum = SceneStatType; - using StatsArray = std::array(StatsEnum::STATS_COUNT)>; - // using StatsBlock = std::unordered_map; - - static int writeBuffer; - static std::array stats; - static bool collectionEnabled; - - RecordSceneTime(const RecordSceneTime&) = delete; - RecordSceneTime() = delete; - - const StatsEnum type; - std::chrono::steady_clock::time_point start; - public: - - static inline void enable(){collectionEnabled=true;}; - static inline void disable(){collectionEnabled=false;}; - static inline bool enabled(){return(collectionEnabled);}; - - RecordSceneTime(SceneStatType type):start{std::chrono::steady_clock::now()}, type{type} {} - - ~RecordSceneTime() - { - auto val = std::chrono::duration(std::chrono::steady_clock::now() - start).count(); - stats[writeBuffer][static_cast(type)] += val; - }; - - static inline void toggleBuffer() - { - if(enabled()) - { - // stats[writeBuffer][static_cast(SceneStatType::RENDER_FPS)] = LLTrace::get_frame_recording().getPeriodMeanPerSec(LLStatViewer::FPS,3); // last 3 Frames - writeBuffer = (writeBuffer+1)%2; - }; // not we are relying on atomic updates here. The risk is low and would cause minor errors in the stats display. - - auto& statsArray = stats[writeBuffer]; - std::fill_n(statsArray.begin() ,static_cast(SceneStatType::STATS_COUNT),0); - } - static inline int getReadBufferIndex(){return (writeBuffer+1)%2;}; - static inline StatsArray getCurrentStatsBuffer(){ return stats[getReadBufferIndex()];} - static inline uint64_t get(StatsEnum type){return stats[getReadBufferIndex()][static_cast(type)];} - }; - - template - class RecordObjectTime - { - using StatsEnum = ObjStatType; - using StatsArray = std::array(StatsEnum::STATS_COUNT)>; - using StatsBlock = std::unordered_map; - - static int writeBuffer; - static std::array stats; - - static std::array max; - static std::array sum; - static bool collectionEnabled; - - RecordObjectTime(const RecordObjectTime&) = delete; - RecordObjectTime() = delete; - const T key; - const StatsEnum type; - std::chrono::steady_clock::time_point start; - - public: - static inline void enable(){collectionEnabled=true;}; - static inline void disable(){collectionEnabled=false;}; - static inline bool enabled(){return(collectionEnabled);}; - - RecordObjectTime(T key, ObjStatType type):start{std::chrono::steady_clock::now()}, key{key}, type{type} {} - - ~RecordObjectTime() - { - using ST = StatsEnum; - // Note: nullptr is used as the key for global stats - auto val = std::chrono::duration(std::chrono::steady_clock::now() - start).count(); - if(key) - { - stats[writeBuffer][key][static_cast(type)] += val; - stats[writeBuffer][key][static_cast(ST::RENDER_COMBINED)] += val; - if(max[writeBuffer][static_cast(type)] < stats[writeBuffer][key][static_cast(type)]) - { - max[writeBuffer][static_cast(type)] = stats[writeBuffer][key][static_cast(type)]; - } - if(max[writeBuffer][static_cast(ST::RENDER_COMBINED)] < stats[writeBuffer][key][static_cast(ST::RENDER_COMBINED)]) - { - max[writeBuffer][static_cast(ST::RENDER_COMBINED)] = stats[writeBuffer][key][static_cast(ST::RENDER_COMBINED)]; - } - sum[writeBuffer][static_cast(type)] += val; - sum[writeBuffer][static_cast(ST::RENDER_COMBINED)] += val; - } - }; - static inline void toggleBuffer() - { - using ST = StatsEnum; - if(enabled()) - { - writeBuffer = (writeBuffer+1)%2; - }; // note we are relying on atomic updates here. The risk is low and would cause minor errors in the stats display. - - auto& statsMap = stats[writeBuffer]; - for(auto& stat_entry : statsMap) - { - std::fill_n(stat_entry.second.begin() ,static_cast(ST::STATS_COUNT),0); - } - statsMap.clear(); - std::fill_n(max[writeBuffer].begin(),static_cast(ST::STATS_COUNT),0); - std::fill_n(sum[writeBuffer].begin(),static_cast(ST::STATS_COUNT),0); - } - static inline int getReadbufferIndex(){return (writeBuffer+1)%2;}; - static inline StatsBlock& getCurrentStatsBuffer(){ return stats[(writeBuffer+1)%2]; } - static inline uint64_t getMax(StatsEnum type){return max[(writeBuffer+1)%2][static_cast(type)];} - static inline uint64_t getSum(StatsEnum type){return sum[(writeBuffer+1)%2][static_cast(type)];} - static inline uint64_t getNum(){return stats[(writeBuffer+1)%2].size();} - static inline uint64_t get(T key, StatsEnum type){return stats[(writeBuffer+1)%2][key][static_cast(type)];} - }; - - static inline void toggleBuffer() - { - // RecordObjectTime::toggleBuffer(); - RecordSceneTime::toggleBuffer(); - } - - template< typename T > - int RecordObjectTime::writeBuffer{0}; - - template< typename T > - bool RecordObjectTime::collectionEnabled{true}; - - template< typename T > - std::array< typename RecordObjectTime< T >::StatsArray, 2 > RecordObjectTime::max; - - template< typename T > - std::array< typename RecordObjectTime< T >::StatsArray, 2 > RecordObjectTime::sum; - - template< typename T > - std::array< typename RecordObjectTime< T >::StatsBlock, 2 > RecordObjectTime< T >::stats{ {{}} }; - }// namespace FSTelemetry #endif \ No newline at end of file diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 17fac803cb..b74d5a58c5 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -286,6 +286,7 @@ #include "fsassetblacklist.h" #include "fstelemetry.h" // Tracy profiler support +#include "fsperfstats.h" // performance stats support #if LL_LINUX && LL_GTK #include "glib.h" @@ -1632,7 +1633,7 @@ bool LLAppViewer::frame() bool LLAppViewer::doFrame() { { - FSTelemetry::RecordSceneTime T (FSTelemetry::SceneStatType::RENDER_FRAME); + FSPerfStats::RecordSceneTime T (FSPerfStats::SceneStatType::RENDER_FRAME); LLEventPump& mainloop(LLEventPumps::instance().obtain("mainloop")); LLSD newFrame; @@ -1770,7 +1771,7 @@ bool LLAppViewer::doFrame() // Update state based on messages, user input, object idle. { - FSTelemetry::RecordSceneTime T (FSTelemetry::SceneStatType::RENDER_IDLE); + FSPerfStats::RecordSceneTime T (FSPerfStats::SceneStatType::RENDER_IDLE); pauseMainloopTimeout(); // *TODO: Remove. Messages shouldn't be stalling for 20+ seconds! @@ -1850,7 +1851,7 @@ bool LLAppViewer::doFrame() // of equal priority on Windows if (milliseconds_to_sleep > 0) { - FSTelemetry::RecordSceneTime T ( FSTelemetry::SceneStatType::RENDER_SLEEP ); + FSPerfStats::RecordSceneTime T ( FSPerfStats::SceneStatType::RENDER_SLEEP ); ms_sleep(milliseconds_to_sleep); // also pause worker threads during this wait period LLAppViewer::getTextureCache()->pause(); @@ -1928,7 +1929,7 @@ bool LLAppViewer::doFrame() if (fsLimitFramerate && LLStartUp::getStartupState() == STATE_STARTED && !gTeleportDisplay && !logoutRequestSent() && max_fps > F_APPROXIMATELY_ZERO) { // Sleep a while to limit frame rate. - FSTelemetry::RecordSceneTime T (FSTelemetry::SceneStatType::RENDER_FPSLIMIT); + FSPerfStats::RecordSceneTime T (FSPerfStats::SceneStatType::RENDER_FPSLIMIT); F32 min_frame_time = 1.f / (F32)max_fps; S32 milliseconds_to_sleep = llclamp((S32)((min_frame_time - frameTimer.getElapsedTimeF64()) * 1000.f), 0, 1000); if (milliseconds_to_sleep > 0) @@ -1969,8 +1970,9 @@ bool LLAppViewer::doFrame() FSFrameMark; // Tracy support delineate Frame LLPROFILE_UPDATE(); } - FSTelemetry::RecordSceneTime::toggleBuffer(); - FSTelemetry::RecordObjectTime::toggleBuffer(); + FSPerfStats::RecordSceneTime::toggleBuffer(); + FSPerfStats::RecordObjectTime::toggleBuffer(); + FSPerfStats::RecordAttachmentTime::toggleBuffer(); return ! LLApp::isRunning(); } diff --git a/indra/newview/llavatarrendernotifier.h b/indra/newview/llavatarrendernotifier.h index 37130bfcf6..e8077d55c0 100644 --- a/indra/newview/llavatarrendernotifier.h +++ b/indra/newview/llavatarrendernotifier.h @@ -30,6 +30,9 @@ #define LL_llavatarrendernotifier_H #include "llnotificationptr.h" +#include "llviewerobject.h" +#include "llhudobject.h" + class LLViewerRegion; @@ -45,6 +48,7 @@ struct LLHUDComplexity objectName = ""; objectsCost = 0; objectsCount = 0; + objectPtr = nullptr; texturesCost = 0; texturesCount = 0; largeTexturesCount = 0; @@ -58,6 +62,7 @@ struct LLHUDComplexity U32 texturesCost; U32 texturesCount; U32 largeTexturesCount; + const LLViewerObject * objectPtr; F64Bytes texturesMemoryTotal; }; diff --git a/indra/newview/lldrawpool.cpp b/indra/newview/lldrawpool.cpp index d583a692f9..8224394b14 100644 --- a/indra/newview/lldrawpool.cpp +++ b/indra/newview/lldrawpool.cpp @@ -50,6 +50,7 @@ #include "lldrawpoolwlsky.h" #include "llglslshader.h" #include "llglcommonfunc.h" +#include "fsperfstats.h" // performance stats support S32 LLDrawPool::sNumDrawPools = 0; @@ -452,6 +453,27 @@ void LLRenderPass::applyModelMatrix(const LLDrawInfo& params) void LLRenderPass::pushBatch(LLDrawInfo& params, U32 mask, BOOL texture, BOOL batch_textures) { + // Capture render times + LLViewerObject* rootAtt{}; + std::unique_ptr> T{}; + if(params.mFace) + { + LLViewerObject* vobj = (LLViewerObject *)params.mFace->getViewerObject(); + + if(vobj->isAttachment()) + { + auto par = (LLViewerObject*)vobj->getParent(); + rootAtt = vobj; + while( par->isAttachment() ) + { + rootAtt = par; + par = (LLViewerObject*)par->getParent(); + } + LL_INFOS() << "pushBatch recording time for ATT@" << rootAtt << " " << (rootAtt?rootAtt->getAttachmentItemName():"null") << " as " << rootAtt->getAttachmentItemID().getCRC32() << LL_ENDL; + if(rootAtt){T = std::unique_ptr>(new FSPerfStats::RecordAttachmentTime(rootAtt->getAttachmentItemID().getCRC32(), FSPerfStats::ObjStatType::RENDER_GEOMETRY));} + } + } + // if (!params.mCount) { return; diff --git a/indra/newview/lldrawpoolalpha.cpp b/indra/newview/lldrawpoolalpha.cpp index 87bf2cb098..3fbcab9d4a 100644 --- a/indra/newview/lldrawpoolalpha.cpp +++ b/indra/newview/lldrawpoolalpha.cpp @@ -48,6 +48,7 @@ #include "lldrawpoolwater.h" #include "llspatialpartition.h" #include "llglcommonfunc.h" +#include "fsperfstats.h" // performance stats support BOOL LLDrawPoolAlpha::sShowDebugAlpha = FALSE; @@ -352,6 +353,27 @@ void LLDrawPoolAlpha::renderAlphaHighlight(U32 mask) for (LLSpatialGroup::drawmap_elem_t::iterator k = draw_info.begin(); k != draw_info.end(); ++k) { LLDrawInfo& params = **k; + // Capture render times + std::unique_ptr> T{}; + if(params.mFace) + { + LLViewerObject* rootAtt{}; + LLViewerObject* vobj = (LLViewerObject *)params.mFace->getViewerObject(); + + if(vobj->isAttachment()) + { + auto par = (LLViewerObject*)vobj->getParent(); + rootAtt = vobj; + while( par->isAttachment() ) + { + rootAtt = par; + par = (LLViewerObject*)par->getParent(); + } + LL_INFOS() << "recording time for ATT@" << rootAtt << " " << (rootAtt?rootAtt->getAttachmentItemName():"null") << " as " << rootAtt->getAttachmentItemID().getCRC32() << LL_ENDL; + if(rootAtt){T = std::unique_ptr>(new FSPerfStats::RecordAttachmentTime(rootAtt->getAttachmentItemID().getCRC32(), FSPerfStats::ObjStatType::RENDER_GEOMETRY));} + } + } + // if (params.mParticle) { @@ -679,6 +701,28 @@ void LLDrawPoolAlpha::renderAlpha(U32 mask, S32 pass) continue; } + // Capture render times + std::unique_ptr> T{}; + if(params.mFace) + { + LLViewerObject* rootAtt{}; + LLViewerObject* vobj = (LLViewerObject *)params.mFace->getViewerObject(); + + if(vobj->isAttachment()) + { + auto par = (LLViewerObject*)vobj->getParent(); + rootAtt = vobj; + while( par->isAttachment() ) + { + rootAtt = par; + par = (LLViewerObject*)par->getParent(); + } + LL_INFOS() << "ALPHA recording time for ATT@" << rootAtt << " " << (rootAtt?rootAtt->getAttachmentItemName():"null") << " as " << rootAtt->getAttachmentItemID().getCRC32() << LL_ENDL; + if(rootAtt){T = std::unique_ptr>(new FSPerfStats::RecordAttachmentTime(rootAtt->getAttachmentItemID().getCRC32(), FSPerfStats::ObjStatType::RENDER_GEOMETRY));} + } + } + // + // Fix for bug - NORSPEC-271 // If the face is more than 90% transparent, then don't update the Depth buffer for Dof // We don't want the nearly invisible objects to cause of DoF effects diff --git a/indra/newview/lldrawpoolavatar.cpp b/indra/newview/lldrawpoolavatar.cpp index 767027e60d..51fd2760d0 100644 --- a/indra/newview/lldrawpoolavatar.cpp +++ b/indra/newview/lldrawpoolavatar.cpp @@ -59,6 +59,8 @@ // void drawBoxOutline(const LLVector3& pos,const LLVector3& size); // llspatialpartition.cpp // #include "llnetmap.h" +#include "fsperfstats.h" // performance stats support + static U32 sDataMask = LLDrawPoolAvatar::VERTEX_DATA_MASK; static U32 sBufferUsage = GL_STREAM_DRAW_ARB; @@ -579,7 +581,7 @@ void LLDrawPoolAvatar::renderShadow(S32 pass) { return; } - FSTelemetry::RecordObjectTime T(avatarp, FSTelemetry::ObjStatType::RENDER_SHADOWS); + FSPerfStats::RecordObjectTime T(avatarp, FSPerfStats::ObjStatType::RENDER_SHADOWS); LLVOAvatar::AvatarOverallAppearance oa = avatarp->getOverallAppearance(); BOOL impostor = !LLPipeline::sImpostorRender && avatarp->isImpostor(); @@ -1465,6 +1467,7 @@ void LLDrawPoolAvatar::renderAvatars(LLVOAvatar* single_avatar, S32 pass) if (pass == -1) { + FSZoneN("pass -1"); for (S32 i = 1; i < getNumPasses(); i++) { //skip foot shadows prerender(); @@ -1481,7 +1484,7 @@ void LLDrawPoolAvatar::renderAvatars(LLVOAvatar* single_avatar, S32 pass) return; } - LLVOAvatar *avatarp = NULL; + LLVOAvatar *avatarp { nullptr }; if (single_avatar) { @@ -1501,12 +1504,13 @@ void LLDrawPoolAvatar::renderAvatars(LLVOAvatar* single_avatar, S32 pass) { return; } - FSTelemetry::RecordObjectTime T(avatarp, FSTelemetry::ObjStatType::RENDER_GEOMETRY); + FSPerfStats::RecordObjectTime T(avatarp, FSPerfStats::ObjStatType::RENDER_GEOMETRY); // Add avatar hitbox debug static LLCachedControl render_hitbox(gSavedSettings, "DebugRenderHitboxes", false); if (render_hitbox && pass == 2) { + FSZoneN("render_hitbox"); LLGLSLShader* current_shader_program = NULL; // load the debug output shader @@ -1589,6 +1593,7 @@ void LLDrawPoolAvatar::renderAvatars(LLVOAvatar* single_avatar, S32 pass) if (!single_avatar && !avatarp->isFullyLoaded() ) { + FSZoneN("avatar not loaded"); if (pass==0 && (!gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_PARTICLES) || LLViewerPartSim::getMaxPartCount() <= 0)) { // debug code to draw a sphere in place of avatar @@ -1636,6 +1641,7 @@ void LLDrawPoolAvatar::renderAvatars(LLVOAvatar* single_avatar, S32 pass) if (pass == 0) { + FSZoneN("pass 0"); if (!LLPipeline::sReflectionRender) { LLVOAvatar::sNumVisibleAvatars++; @@ -1644,6 +1650,7 @@ void LLDrawPoolAvatar::renderAvatars(LLVOAvatar* single_avatar, S32 pass) // if (impostor || (LLVOAvatar::AV_DO_NOT_RENDER == avatarp->getVisualMuteSettings() && !avatarp->needsImpostorUpdate())) if (impostor || (LLVOAvatar::AOA_NORMAL != avatarp->getOverallAppearance() && !avatarp->needsImpostorUpdate())) { + FSZoneN("render impostor"); if (LLPipeline::sRenderDeferred && !LLPipeline::sReflectionRender && avatarp->mImpostor.isComplete()) { // FIRE-9179: Crash fix @@ -1669,6 +1676,7 @@ void LLDrawPoolAvatar::renderAvatars(LLVOAvatar* single_avatar, S32 pass) if (pass == 1) { + FSZoneN("render rigid meshes (eyeballs)"); // render rigid meshes (eyeballs) first avatarp->renderRigid(); return; @@ -1676,12 +1684,15 @@ void LLDrawPoolAvatar::renderAvatars(LLVOAvatar* single_avatar, S32 pass) if (pass == 3) { + FSZoneN("pass 3"); if (is_deferred_render) { + FSZoneN("deferred rigged simple"); renderDeferredRiggedSimple(avatarp); } else { + FSZoneN("non-deferred rigged"); renderRiggedSimple(avatarp); if (LLPipeline::sRenderDeferred) @@ -1705,12 +1716,15 @@ void LLDrawPoolAvatar::renderAvatars(LLVOAvatar* single_avatar, S32 pass) if (pass == 4) { + FSZoneN("pass 4"); if (is_deferred_render) { + FSZoneN("deferred rigged bump"); renderDeferredRiggedBump(avatarp); } else { + FSZoneN("non-deferred fullbright"); renderRiggedFullbright(avatarp); } @@ -1719,6 +1733,7 @@ void LLDrawPoolAvatar::renderAvatars(LLVOAvatar* single_avatar, S32 pass) if (is_deferred_render && pass >= 5 && pass <= 21) { + FSZoneN("deferred passes 5-21"); S32 p = pass-5; if (p != 1 && @@ -1726,6 +1741,7 @@ void LLDrawPoolAvatar::renderAvatars(LLVOAvatar* single_avatar, S32 pass) p != 9 && p != 13) { + FSZoneN("deferred rigged material"); renderDeferredRiggedMaterial(avatarp, p); } return; @@ -1736,6 +1752,7 @@ void LLDrawPoolAvatar::renderAvatars(LLVOAvatar* single_avatar, S32 pass) if (pass == 5) { + FSZoneN("rigged shiny"); renderRiggedShinySimple(avatarp); return; @@ -1743,6 +1760,7 @@ void LLDrawPoolAvatar::renderAvatars(LLVOAvatar* single_avatar, S32 pass) if (pass == 6) { + FSZoneN("rigged FB shiny"); renderRiggedFullbrightShiny(avatarp); return; } @@ -1751,10 +1769,12 @@ void LLDrawPoolAvatar::renderAvatars(LLVOAvatar* single_avatar, S32 pass) { if (pass == 7) { + FSZoneN("pass 7 rigged Alpha"); renderRiggedAlpha(avatarp); if (LLPipeline::sRenderDeferred && !is_post_deferred_render) { //render transparent materials under water + FSZoneN("rigged Alpha Blend"); LLGLEnable blend(GL_BLEND); gGL.setColorMask(true, true); @@ -1775,6 +1795,7 @@ void LLDrawPoolAvatar::renderAvatars(LLVOAvatar* single_avatar, S32 pass) if (pass == 8) { + FSZoneN("pass 8 rigged FB Alpha"); renderRiggedFullbrightAlpha(avatarp); return; } @@ -1791,6 +1812,7 @@ void LLDrawPoolAvatar::renderAvatars(LLVOAvatar* single_avatar, S32 pass) } { + FSZoneN("post deferred rigged Alpha"); LLGLEnable blend(GL_BLEND); renderDeferredRiggedMaterial(avatarp, p); } @@ -1798,6 +1820,7 @@ void LLDrawPoolAvatar::renderAvatars(LLVOAvatar* single_avatar, S32 pass) } else if (pass == 9) { + FSZoneN("pass 9 - rigged glow"); renderRiggedGlow(avatarp); return; } @@ -1805,6 +1828,7 @@ void LLDrawPoolAvatar::renderAvatars(LLVOAvatar* single_avatar, S32 pass) if (pass == 13) { + FSZoneN("pass 13 - rigged glow"); renderRiggedGlow(avatarp); return; @@ -1812,6 +1836,7 @@ void LLDrawPoolAvatar::renderAvatars(LLVOAvatar* single_avatar, S32 pass) if ((sShaderLevel >= SHADER_LEVEL_CLOTH)) { + FSZoneN("shader level > CLOTH"); LLMatrix4 rot_mat; LLViewerCamera::getInstance()->getMatrixToLocal(rot_mat); LLMatrix4 cfr(OGL_TO_CFR_ROTATION); @@ -1837,6 +1862,7 @@ void LLDrawPoolAvatar::renderAvatars(LLVOAvatar* single_avatar, S32 pass) if( !single_avatar || (avatarp == single_avatar) ) { + FSZoneN("renderSkinned"); avatarp->renderSkinned(); } } @@ -2254,7 +2280,24 @@ void LLDrawPoolAvatar::renderRigged(LLVOAvatar* avatar, U32 type, bool glow) { continue; } + + auto self = avatar->isSelf(); + LLViewerObject * parentAttachment{nullptr}; + if(self && vobj->isAttachment()) + { + LLViewerObject * vtop = vobj; + LLViewerObject * par = (LLViewerObject *) vobj->getParent(); + while (par && !(par->asAvatar())) + { + vtop = par; + par = (LLViewerObject *)vtop->getParent(); + } + parentAttachment = vtop; + } + FSPerfStats::RecordAttachmentTime T(parentAttachment?parentAttachment->getAttachmentItemID().getCRC32():0, FSPerfStats::ObjStatType::RENDER_GEOMETRY); + + LLVolume* volume = vobj->getVolume(); S32 te = face->getTEOffset(); @@ -2555,6 +2598,7 @@ void LLDrawPoolAvatar::updateRiggedVertexBuffers(LLVOAvatar* avatar) { for (U32 i = 0; i < mRiggedFace[type].size(); ++i) { + FSZoneN("updateRiggedVBO"); LLFace* face = mRiggedFace[type][i]; LLDrawable* drawable = face->getDrawable(); if (!drawable) diff --git a/indra/newview/lldrawpoolbump.cpp b/indra/newview/lldrawpoolbump.cpp index c7cb6567b5..b8dcdbb0be 100644 --- a/indra/newview/lldrawpoolbump.cpp +++ b/indra/newview/lldrawpoolbump.cpp @@ -47,6 +47,7 @@ #include "pipeline.h" #include "llspatialpartition.h" #include "llviewershadermgr.h" +#include "fsperfstats.h" // performance stats support //#include "llimagebmp.h" //#include "../tools/imdebug/imdebug.h" @@ -646,7 +647,24 @@ void LLDrawPoolBump::renderGroup(LLSpatialGroup* group, U32 type, U32 mask, BOOL for (LLSpatialGroup::drawmap_elem_t::iterator k = draw_info.begin(); k != draw_info.end(); ++k) { LLDrawInfo& params = **k; + // Capture render times + LLViewerObject* rootAtt{}; + std::unique_ptr> T{}; + LLViewerObject* vobj = (LLViewerObject *)params.mFace->getViewerObject(); + if(vobj->isAttachment()) + { + auto par = (LLViewerObject*)vobj->getParent(); + rootAtt = vobj; + while( par->isAttachment() ) + { + rootAtt = par; + par = (LLViewerObject*)par->getParent(); + } + LL_INFOS() << "recording time for ATT@" << rootAtt << " " << (rootAtt?rootAtt->getAttachmentItemName():"null") << " as " << rootAtt->getAttachmentItemID().getCRC32() << LL_ENDL; + if(rootAtt){T = std::unique_ptr>(new FSPerfStats::RecordAttachmentTime(rootAtt->getAttachmentItemID().getCRC32(), FSPerfStats::ObjStatType::RENDER_GEOMETRY));} + } + // applyModelMatrix(params); if (params.mGroup) @@ -1512,6 +1530,27 @@ void LLDrawPoolBump::renderBump(U32 type, U32 mask) void LLDrawPoolBump::pushBatch(LLDrawInfo& params, U32 mask, BOOL texture, BOOL batch_textures) { + // Capture render times + std::unique_ptr> T{}; + if(params.mFace) + { + LLViewerObject* rootAtt{}; + LLViewerObject* vobj = (LLViewerObject *)params.mFace->getViewerObject(); + + if(vobj->isAttachment()) + { + auto par = (LLViewerObject*)vobj->getParent(); + rootAtt = vobj; + while( par->isAttachment() ) + { + rootAtt = par; + par = (LLViewerObject*)par->getParent(); + } + // LL_INFOS() << "recording time for ATT@" << rootAtt << " " << (rootAtt?rootAtt->getAttachmentItemName():"null") << " as " << rootAtt->getAttachmentItemID().getCRC32() << LL_ENDL; + if(rootAtt){T = std::unique_ptr>(new FSPerfStats::RecordAttachmentTime(rootAtt->getAttachmentItemID().getCRC32(), FSPerfStats::ObjStatType::RENDER_GEOMETRY));} + } + } + // applyModelMatrix(params); bool tex_setup = false; diff --git a/indra/newview/lldrawpoolmaterials.cpp b/indra/newview/lldrawpoolmaterials.cpp index 05b0c1f1a9..710cf5f80b 100644 --- a/indra/newview/lldrawpoolmaterials.cpp +++ b/indra/newview/lldrawpoolmaterials.cpp @@ -31,6 +31,7 @@ #include "llviewershadermgr.h" #include "pipeline.h" #include "llglcommonfunc.h" +#include "fsperfstats.h" // performance stats support S32 diffuse_channel = -1; @@ -138,7 +139,29 @@ void LLDrawPoolMaterials::renderDeferred(S32 pass) for (LLCullResult::drawinfo_iterator i = begin; i != end; ++i) { LLDrawInfo& params = **i; - + + // Capture render times + std::unique_ptr> T{}; + if(params.mFace) + { + LLViewerObject* rootAtt{}; + LLViewerObject* vobj = (LLViewerObject *)params.mFace->getViewerObject(); + + if(vobj->isAttachment()) + { + auto par = (LLViewerObject*)vobj->getParent(); + rootAtt = vobj; + while( par->isAttachment() ) + { + rootAtt = par; + par = (LLViewerObject*)par->getParent(); + } + LL_INFOS() << "MATERIALS recording time for ATT@" << rootAtt << " " << (rootAtt?rootAtt->getAttachmentItemName():"null") << " as " << rootAtt->getAttachmentItemID().getCRC32() << LL_ENDL; + if(rootAtt){T = std::unique_ptr>(new FSPerfStats::RecordAttachmentTime(rootAtt->getAttachmentItemID().getCRC32(), FSPerfStats::ObjStatType::RENDER_GEOMETRY));} + } + } + // + mShader->uniform4f(LLShaderMgr::SPECULAR_COLOR, params.mSpecColor.mV[0], params.mSpecColor.mV[1], params.mSpecColor.mV[2], params.mSpecColor.mV[3]); mShader->uniform1f(LLShaderMgr::ENVIRONMENT_INTENSITY, params.mEnvIntensity); diff --git a/indra/newview/llface.cpp b/indra/newview/llface.cpp index 316951c316..e0251f6d23 100644 --- a/indra/newview/llface.cpp +++ b/indra/newview/llface.cpp @@ -59,6 +59,7 @@ // [RLVa:KB] - Checked: RLVa-2.0.0 #include "rlvhandler.h" // [/RLVa:KB] +#include "fsperfstats.h" // performance stats support #if LL_LINUX // Work-around spurious used before init warning on Vector4a @@ -642,6 +643,20 @@ void renderFace(LLDrawable* drawable, LLFace *face) LLVOVolume* vobj = drawable->getVOVolume(); if (vobj) { + LLVOVolume* rootAtt{}; + std::unique_ptr> T{}; + if(vobj->isAttachment()) + { + auto par = (LLVOVolume*)vobj->getParent(); + rootAtt = vobj; + while( par->isAttachment() ) + { + rootAtt = par; + par = (LLVOVolume*)par->getParent(); + } + // LL_INFOS() << "recording time for ATT@" << rootAtt << " " << (rootAtt?rootAtt->getAttachmentItemName():"null") << LL_ENDL; + if(rootAtt){T = std::unique_ptr>(new FSPerfStats::RecordAttachmentTime(rootAtt->getAttachmentItemID().getCRC32(), FSPerfStats::ObjStatType::RENDER_GEOMETRY));} + } LLVolume* volume = NULL; if (drawable->isState(LLDrawable::RIGGED)) diff --git a/indra/newview/llfloaterperformance.cpp b/indra/newview/llfloaterperformance.cpp index 8e0ca64368..4a18522244 100644 --- a/indra/newview/llfloaterperformance.cpp +++ b/indra/newview/llfloaterperformance.cpp @@ -46,6 +46,7 @@ #include "pipeline.h" #include "llviewercontrol.h" #include "fsavatarrenderpersistence.h" +#include "fsperfstats.h" // performance stats support const F32 REFRESH_INTERVAL = 1.0f; const S32 BAR_LEFT_PAD = 2; @@ -176,13 +177,13 @@ void LLFloaterPerformance::draw() getChild("fps_value")->setValue((S32)llround(fps)); auto tot_frame_time_ns = 1000000000/fps; auto target_frame_time_ns = 1000000000/(target_fps==0?1:target_fps); - auto tot_avatar_time = FSTelemetry::RecordObjectTime::getSum(FSTelemetry::ObjStatType::RENDER_COMBINED); - auto tot_huds_time = FSTelemetry::RecordSceneTime::get(FSTelemetry::SceneStatType::RENDER_HUDS) ; - auto tot_sleep_time = FSTelemetry::RecordSceneTime::get(FSTelemetry::SceneStatType::RENDER_SLEEP); - auto tot_ui_time = FSTelemetry::RecordSceneTime::get(FSTelemetry::SceneStatType::RENDER_UI); - auto tot_idle_time = FSTelemetry::RecordSceneTime::get(FSTelemetry::SceneStatType::RENDER_IDLE); - auto tot_limit_time = FSTelemetry::RecordSceneTime::get(FSTelemetry::SceneStatType::RENDER_FPSLIMIT); - auto tot_swap_time = FSTelemetry::RecordSceneTime::get(FSTelemetry::SceneStatType::RENDER_SWAP); + auto tot_avatar_time = FSPerfStats::RecordObjectTime::getSum(FSPerfStats::ObjStatType::RENDER_COMBINED); + auto tot_huds_time = FSPerfStats::RecordSceneTime::get(FSPerfStats::SceneStatType::RENDER_HUDS) ; + auto tot_sleep_time = FSPerfStats::RecordSceneTime::get(FSPerfStats::SceneStatType::RENDER_SLEEP); + auto tot_ui_time = FSPerfStats::RecordSceneTime::get(FSPerfStats::SceneStatType::RENDER_UI); + auto tot_idle_time = FSPerfStats::RecordSceneTime::get(FSPerfStats::SceneStatType::RENDER_IDLE); + auto tot_limit_time = FSPerfStats::RecordSceneTime::get(FSPerfStats::SceneStatType::RENDER_FPSLIMIT); + auto tot_swap_time = FSPerfStats::RecordSceneTime::get(FSPerfStats::SceneStatType::RENDER_SWAP); // once the rest is extracted what is left is the scene cost (we don't include non-render activities such as network here prlloy should.) auto tot_scene_time = tot_frame_time_ns - tot_avatar_time - tot_huds_time - tot_ui_time - tot_sleep_time - tot_limit_time - tot_swap_time; @@ -241,7 +242,7 @@ void LLFloaterPerformance::draw() if( auto_tune ) { - auto av_render_max = FSTelemetry::RecordObjectTime::getMax(FSTelemetry::ObjStatType::RENDER_COMBINED); + auto av_render_max = FSPerfStats::RecordObjectTime::getMax(FSPerfStats::ObjStatType::RENDER_COMBINED); // if( target_frame_time_ns <= tot_frame_time_ns ) // { @@ -344,10 +345,12 @@ void LLFloaterPerformance::populateHUDList() max_complexity = llmax(max_complexity, (*iter).objectsCost); } + auto huds_max_render_time = FSPerfStats::RecordObjectTime::getMax(FSPerfStats::ObjStatType::RENDER_GEOMETRY); for (iter = complexity_list.begin(); iter != end; ++iter) { - LLHUDComplexity hud_object_complexity = *iter; - S32 obj_cost_short = llmax((S32)hud_object_complexity.objectsCost / 1000, 1); + LLHUDComplexity hud_object_complexity = *iter; + auto hud_ptr = hud_object_complexity.objectPtr; + auto hud_render_time = FSPerfStats::RecordObjectTime::get(hud_ptr, FSPerfStats::ObjStatType::RENDER_GEOMETRY); LLSD item; item["special_id"] = hud_object_complexity.objectId; item["target"] = LLNameListCtrl::SPECIAL; @@ -404,10 +407,13 @@ void LLFloaterPerformance::populateObjectList() max_complexity = llmax(max_complexity, (*iter).objectCost); } + auto max_render_time = FSPerfStats::RecordAttachmentTime::getMax(FSPerfStats::ObjStatType::RENDER_GEOMETRY); + for (iter = complexity_list.begin(); iter != end; ++iter) { LLObjectComplexity object_complexity = *iter; - S32 obj_cost_short = llmax((S32)object_complexity.objectCost / 1000, 1); + // S32 obj_cost_short = llmax((S32)object_complexity.objectCost / 1000, 1); + auto attach_render_time = FSPerfStats::RecordAttachmentTime::get(object_complexity.objectId.getCRC32(), FSPerfStats::ObjStatType::RENDER_GEOMETRY); LLSD item; item["special_id"] = object_complexity.objectId; item["target"] = LLNameListCtrl::SPECIAL; @@ -415,14 +421,15 @@ void LLFloaterPerformance::populateObjectList() row[0]["column"] = "complex_visual"; row[0]["type"] = "bar"; LLSD& value = row[0]["value"]; - value["ratio"] = (F32)obj_cost_short / max_complexity * 1000; + value["ratio"] = (F32)attach_render_time / max_render_time; 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(obj_cost_short); + // row[1]["value"] = std::to_string(obj_cost_short); + row[1]["value"] = llformat("%.3f",((double)attach_render_time / 1000000)); row[1]["font"]["name"] = "SANSSERIF"; row[2]["column"] = "name"; @@ -460,7 +467,7 @@ void LLFloaterPerformance::populateNearbyList() getNearbyAvatars(valid_nearby_avs); std::vector::iterator char_iter = valid_nearby_avs.begin(); - auto render_max = FSTelemetry::RecordObjectTime::getMax(FSTelemetry::ObjStatType::RENDER_COMBINED); + auto render_max = FSPerfStats::RecordObjectTime::getMax(FSPerfStats::ObjStatType::RENDER_COMBINED); while (char_iter != valid_nearby_avs.end()) { LLVOAvatar* avatar = dynamic_cast(*char_iter); @@ -471,7 +478,7 @@ void LLFloaterPerformance::populateNearbyList() continue; // S32 complexity_short = llmax((S32)avatar->getVisualComplexity() / 1000, 1); - auto render_av = FSTelemetry::RecordObjectTime::get(avatar,FSTelemetry::ObjStatType::RENDER_COMBINED); + auto render_av = FSPerfStats::RecordObjectTime::get(avatar,FSPerfStats::ObjStatType::RENDER_COMBINED); auto is_slow = avatar->isTooSlow(true); // auto is_slow_without_shadows = avatar->isTooSlow(); diff --git a/indra/newview/llviewerdisplay.cpp b/indra/newview/llviewerdisplay.cpp index 0bb91556e8..db2f65f4d6 100644 --- a/indra/newview/llviewerdisplay.cpp +++ b/indra/newview/llviewerdisplay.cpp @@ -85,6 +85,7 @@ // [/RLVa:KB] #include "llpresetsmanager.h" #include "fsdata.h" +#include "fsperfstats.h" // performance stats support extern LLPointer gStartTexture; extern bool gShiftFrame; @@ -1192,7 +1193,7 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot) void render_hud_attachments() { - FSTelemetry::RecordSceneTime T (FSTelemetry::SceneStatType::RENDER_HUDS); + FSPerfStats::RecordSceneTime T (FSPerfStats::SceneStatType::RENDER_HUDS); gGL.matrixMode(LLRender::MM_PROJECTION); gGL.pushMatrix(); gGL.matrixMode(LLRender::MM_MODELVIEW); @@ -1400,7 +1401,7 @@ bool setup_hud_matrices(const LLRect& screen_region) void render_ui(F32 zoom_factor, int subfield) { - FSTelemetry::RecordSceneTime T (FSTelemetry::SceneStatType::RENDER_UI); + FSPerfStats::RecordSceneTime T (FSPerfStats::SceneStatType::RENDER_UI); LL_RECORD_BLOCK_TIME(FTM_RENDER_UI); LLGLState::checkStates(); @@ -1486,7 +1487,7 @@ static LLTrace::BlockTimerStatHandle FTM_SWAP("Swap"); void swap() { - FSTelemetry::RecordSceneTime T (FSTelemetry::SceneStatType::RENDER_SWAP); + FSPerfStats::RecordSceneTime T (FSPerfStats::SceneStatType::RENDER_SWAP); LL_RECORD_BLOCK_TIME(FTM_SWAP); if (gDisplaySwapBuffers) diff --git a/indra/newview/llviewerjointmesh.cpp b/indra/newview/llviewerjointmesh.cpp index d2cfe2cf98..0361986a27 100644 --- a/indra/newview/llviewerjointmesh.cpp +++ b/indra/newview/llviewerjointmesh.cpp @@ -55,6 +55,7 @@ #include "m3math.h" #include "m4math.h" #include "llmatrix4a.h" +#include "fsperfstats.h" // performance stats support #if !LL_DARWIN && !LL_LINUX extern PFNGLWEIGHTPOINTERARBPROC glWeightPointerARB; @@ -222,6 +223,7 @@ int compare_int(const void *a, const void *b) //-------------------------------------------------------------------- U32 LLViewerJointMesh::drawShape( F32 pixelArea, BOOL first_pass, BOOL is_dummy) { + FSZone; if (!mValid || !mMesh || !mFace || !mVisible || !mFace->getVertexBuffer() || mMesh->getNumFaces() == 0 || @@ -230,6 +232,22 @@ U32 LLViewerJointMesh::drawShape( F32 pixelArea, BOOL first_pass, BOOL is_dummy) return 0; } + + auto vobj = mFace->getViewerObject(); + if(vobj && !vobj->asAvatar() && vobj->getAvatar()->isSelf()) + { + LLViewerObject * vtop = vobj; + LLViewerObject * par = (LLViewerObject *) vobj->getParent(); + + while (par && !(par->asAvatar())) + { + vtop = par; + par = (LLViewerObject *)vtop->getParent(); + } + vobj = vtop; + } + FSPerfStats::RecordAttachmentTime T(vobj?vobj->getAttachmentItemID().getCRC32():0, FSPerfStats::ObjStatType::RENDER_GEOMETRY); + U32 triangle_count = 0; S32 diffuse_channel = LLDrawPoolAvatar::sDiffuseChannel; diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp index 6e962c94b3..c9490b12c2 100644 --- a/indra/newview/llvoavatar.cpp +++ b/indra/newview/llvoavatar.cpp @@ -134,6 +134,7 @@ #include "fslslbridge.h" // Movelock position refresh #include "fsdiscordconnect.h" // tapping a place that happens on landing in world to start up discord +#include "fsperfstats.h" // performance stats support extern F32 SPEED_ADJUST_MAX; extern F32 SPEED_ADJUST_MAX_SEC; @@ -6928,6 +6929,7 @@ const LLUUID& LLVOAvatar::getID() const LLJoint *LLVOAvatar::getJoint( const JointKey &name ) // { + FSZone; // Query by JointKey rather than just a string, the key can be a U32 index for faster lookup //joint_map_t::iterator iter = mJointMap.find( name ); @@ -9161,8 +9163,8 @@ bool LLVOAvatar::isTooSlow(bool combined) const if(!mARTCapped) { // no cap, so we use the live values - render_time = FSTelemetry::RecordObjectTime::get(this,FSTelemetry::ObjStatType::RENDER_COMBINED); - render_geom_time = FSTelemetry::RecordObjectTime::get(this,FSTelemetry::ObjStatType::RENDER_GEOMETRY); + render_time = FSPerfStats::RecordObjectTime::get(this,FSPerfStats::ObjStatType::RENDER_COMBINED); + render_geom_time = FSPerfStats::RecordObjectTime::get(this,FSPerfStats::ObjStatType::RENDER_GEOMETRY); } else { @@ -9175,8 +9177,8 @@ bool LLVOAvatar::isTooSlow(bool combined) const if(!mARTCapped) { // if we weren't capped, we are now - abuse_constness->mRenderTime = FSTelemetry::RecordObjectTime::get(this,FSTelemetry::ObjStatType::RENDER_COMBINED); - abuse_constness->mGeomTime = FSTelemetry::RecordObjectTime::get(this,FSTelemetry::ObjStatType::RENDER_GEOMETRY); + abuse_constness->mRenderTime = FSPerfStats::RecordObjectTime::get(this,FSPerfStats::ObjStatType::RENDER_COMBINED); + abuse_constness->mGeomTime = FSPerfStats::RecordObjectTime::get(this,FSPerfStats::ObjStatType::RENDER_GEOMETRY); abuse_constness->mARTStale = false; abuse_constness->mARTCapped = true; abuse_constness->mLastARTUpdateFrame = LLFrameTimer::getFrameCount(); @@ -10500,8 +10502,6 @@ void LLVOAvatar::applyParsedAppearanceMessage(LLAppearanceMessageContents& conte updateMeshTextures(); updateMeshVisibility(); - markARTStale(); - } LLViewerTexture* LLVOAvatar::getBakedTexture(const U8 te) @@ -11682,6 +11682,7 @@ void LLVOAvatar::updateVisualComplexity() LL_DEBUGS("AvatarRender") << "avatar " << getID() << " appearance changed" << LL_ENDL; // Set the cache time to in the past so it's updated ASAP mVisualComplexityStale = true; + markARTStale(); } // Account for the complexity of a single top-level object associated diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp index 7ce1730b26..2141ec6caa 100644 --- a/indra/newview/llvovolume.cpp +++ b/indra/newview/llvovolume.cpp @@ -91,6 +91,7 @@ #include "rlvlocks.h" // [/RLVa:KB] #include "llviewernetwork.h" +#include "fsperfstats.h" // performance stats support const F32 FORCE_SIMPLE_RENDER_AREA = 512.f; const F32 FORCE_CULL_AREA = 8.f; @@ -6360,7 +6361,7 @@ static LLTrace::BlockTimerStatHandle FTM_REBUILD_MESH_FLUSH("Flush Mesh"); void LLVolumeGeometryManager::rebuildMesh(LLSpatialGroup* group) { llassert(group); - LL_RECORD_BLOCK_TIME(FTM_REBUILD_VOLUME_VB);// move out one scope (but are these even useful as dupes?) + // LL_RECORD_BLOCK_TIME(FTM_REBUILD_VOLUME_VB);// High volume remove (roughly 1000:1 ratio to inside the if statement) if (group && group->hasState(LLSpatialGroup::MESH_DIRTY) && !group->hasState(LLSpatialGroup::GEOM_DIRTY)) { // LL_RECORD_BLOCK_TIME(FTM_REBUILD_VOLUME_VB);// move out one scope (but are these even useful as dupes?) @@ -6382,6 +6383,19 @@ void LLVolumeGeometryManager::rebuildMesh(LLSpatialGroup* group) if (drawablep && !drawablep->isDead() && drawablep->isState(LLDrawable::REBUILD_ALL) && !drawablep->isState(LLDrawable::RIGGED) ) { LLVOVolume* vobj = drawablep->getVOVolume(); + LLVOVolume* rootAtt{}; + if(vobj->isAttachment()) + { + auto par = (LLVOVolume*)vobj->getParent(); + rootAtt = vobj; + while( par->isAttachment() ) + { + rootAtt = par; + par = (LLVOVolume*)par->getParent(); + } + LL_INFOS() << "recording time for ATT@" << rootAtt << " " << (rootAtt?rootAtt->getAttachmentItemName():"null") << LL_ENDL; + } + FSPerfStats::RecordAttachmentTime T(rootAtt?rootAtt->getAttachmentItemID().getCRC32():0, FSPerfStats::ObjStatType::RENDER_GEOMETRY); // avoid unfortunate sleep during trylock by static check //if(debugLoggingEnabled("AnimatedObjectsLinkset")) static auto debug_logging_on = debugLoggingEnabled("AnimatedObjectsLinkset"); From dddb3498964547f8291d72642311fba8e17305d4 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Sat, 2 Oct 2021 01:29:20 +0300 Subject: [PATCH 175/256] SL-16106 Fixed asset storage trying to request data on shutdown --- indra/newview/llviewerassetstorage.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/indra/newview/llviewerassetstorage.cpp b/indra/newview/llviewerassetstorage.cpp index c1b129750a..64d9ce62c5 100644 --- a/indra/newview/llviewerassetstorage.cpp +++ b/indra/newview/llviewerassetstorage.cpp @@ -520,6 +520,12 @@ void LLViewerAssetStorage::assetRequestCoro( boost::bind(&LLViewerAssetStorage::capsRecvForRegion, this, _1, capsRecv.getName())); llcoro::suspendUntilEventOn(capsRecv); + + if (LLApp::isExiting() || !gAssetStorage) + { + return; + } + LL_WARNS_ONCE("ViewerAsset") << "capsRecv got event" << LL_ENDL; LL_WARNS_ONCE("ViewerAsset") << "region " << gAgent.getRegion() << " mViewerAssetUrl " << mViewerAssetUrl << LL_ENDL; } From 241881309a568c2521ef773bf43544298ff1fd61 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Wed, 18 Aug 2021 20:44:12 +0300 Subject: [PATCH 176/256] SL-15462 Refactor voiceControlCoro() into a state machine #1 --- indra/newview/llvoicevivox.cpp | 237 ++++++++++++++++++++------------- indra/newview/llvoicevivox.h | 1 - 2 files changed, 148 insertions(+), 90 deletions(-) diff --git a/indra/newview/llvoicevivox.cpp b/indra/newview/llvoicevivox.cpp index e6da5c5939..a8d5ef627f 100644 --- a/indra/newview/llvoicevivox.cpp +++ b/indra/newview/llvoicevivox.cpp @@ -658,6 +658,22 @@ void LLVivoxVoiceClient::idle(void* user_data) // of a coroutine. // // + +typedef enum e_voice_control_coro_state +{ + VOICE_STATE_ERROR = -1, + VOICE_STATE_DONE = 0, + VOICE_STATE_TP_WAIT, // entry point + VOICE_STATE_START_DAEMON, + VOICE_STATE_PROVISION_ACCOUNT, + VOICE_STATE_START_SESSION, + VOICE_STATE_SESSION_RETRY, + VOICE_STATE_SESSION_ESTABLISHED, + VOICE_STATE_WAIT_FOR_CHANNEL, + VOICE_STATE_DISCONNECT, + VOICE_STATE_WAIT_FOR_EXIT, +} EVoiceControlCoroState; + void LLVivoxVoiceClient::voiceControlCoro() { LL_DEBUGS("Voice") << "starting" << LL_ENDL; @@ -666,114 +682,158 @@ void LLVivoxVoiceClient::voiceControlCoro() U32 retry = 0; - while (gAgent.getTeleportState() != LLAgent::TELEPORT_NONE && !sShuttingDown) - { - LL_DEBUGS("Voice") << "Suspending voiceControlCoro() momentarily for teleport. Tuning: " << mTuningMode << ". Relog: " << mRelogRequested << LL_ENDL; - llcoro::suspendUntilTimeout(1.0); - } - - if (sShuttingDown) - { - mIsCoroutineActive = false; - return; - } + EVoiceControlCoroState coro_state = VOICE_STATE_TP_WAIT; do { - bool success = startAndConnectSession(); - if (success) + if (sShuttingDown) { - // enable/disable the automatic VAD and explicitly set the initial values of - // the VAD variables ourselves when it is off - see SL-15072 for more details - // note: we set the other parameters too even if the auto VAD is on which is ok - unsigned int vad_auto = gSavedSettings.getU32("VivoxVadAuto"); - unsigned int vad_hangover = gSavedSettings.getU32("VivoxVadHangover"); - unsigned int vad_noise_floor = gSavedSettings.getU32("VivoxVadNoiseFloor"); - unsigned int vad_sensitivity = gSavedSettings.getU32("VivoxVadSensitivity"); - setupVADParams(vad_auto, vad_hangover, vad_noise_floor, vad_sensitivity); - - // watch for changes to the VAD settings via Debug Settings UI and act on them accordingly - gSavedSettings.getControl("VivoxVadAuto")->getSignal()->connect(boost::bind(&LLVivoxVoiceClient::onVADSettingsChange, this)); - gSavedSettings.getControl("VivoxVadHangover")->getSignal()->connect(boost::bind(&LLVivoxVoiceClient::onVADSettingsChange, this)); - gSavedSettings.getControl("VivoxVadNoiseFloor")->getSignal()->connect(boost::bind(&LLVivoxVoiceClient::onVADSettingsChange, this)); - gSavedSettings.getControl("VivoxVadSensitivity")->getSignal()->connect(boost::bind(&LLVivoxVoiceClient::onVADSettingsChange, this)); - - if (mTuningMode && !sShuttingDown) - { - performMicTuning(); - } - - if (!sShuttingDown) - { - waitForChannel(); // this doesn't normally return unless relog is needed or shutting down - } - - LL_DEBUGS("Voice") << "lost channel RelogRequested=" << mRelogRequested << LL_ENDL; - endAndDisconnectSession(); - retry = 0; + // Vivox singleton performed the exit, and no longer + // cares about state of coroutine, so just stop + return; } - - // if we hit this and mRelogRequested is true, that indicates - // that we attempted to relog into Vivox and were rejected. - // Rather than just quit out of voice, we will tear it down (above) - // and then reconstruct the voice connecion from scratch. - LL_DEBUGS("Voice") - << "disconnected" - << " RelogRequested=" << mRelogRequested - << LL_ENDL; - if (mRelogRequested && !sShuttingDown) + + switch (coro_state) { - if (!success) + case VOICE_STATE_TP_WAIT: + // starting point for voice + if (gAgent.getTeleportState() != LLAgent::TELEPORT_NONE) { - // We failed to connect, give it a bit time before retrying. - retry++; - F32 delay = llmin(5.f * (F32)retry, 60.f); - llcoro::suspendUntilTimeout(delay); - LL_INFOS("Voice") << "Voice failed to establish session after " << retry << " tries. Will attempt to reconnect." << LL_ENDL; + LL_DEBUGS("Voice") << "Suspending voiceControlCoro() momentarily for teleport. Tuning: " << mTuningMode << ". Relog: " << mRelogRequested << LL_ENDL; + llcoro::suspendUntilTimeout(1.0); } else { - LL_INFOS("Voice") << "will attempt to reconnect to voice" << LL_ENDL; + coro_state = VOICE_STATE_START_DAEMON; } + break; - while (isGatewayRunning() || (gAgent.getTeleportState() != LLAgent::TELEPORT_NONE && !sShuttingDown)) + case VOICE_STATE_START_DAEMON: + LL_DEBUGS("Voice") << "Launching daemon" << LL_ENDL; + LLVoiceVivoxStats::getInstance()->reset(); + if (startAndLaunchDaemon()) + { + coro_state = VOICE_STATE_PROVISION_ACCOUNT; + } + else + { + coro_state = VOICE_STATE_SESSION_RETRY; + } + break; + + case VOICE_STATE_PROVISION_ACCOUNT: + if (provisionVoiceAccount()) + { + coro_state = VOICE_STATE_START_SESSION; + } + else + { + coro_state = VOICE_STATE_SESSION_RETRY; + } + break; + + case VOICE_STATE_START_SESSION: + if (establishVoiceConnection()) + { + coro_state = VOICE_STATE_SESSION_ESTABLISHED; + } + else + { + coro_state = VOICE_STATE_SESSION_RETRY; + } + break; + + case VOICE_STATE_SESSION_RETRY: + giveUp(); // cleans sockets and session + if (mRelogRequested) + { + // We failed to connect, give it a bit time before retrying. + retry++; + F32 full_delay = llmin(5.f * (F32)retry, 60.f); + F32 current_delay = 0.f; + LL_INFOS("Voice") << "Voice failed to establish session after " << retry + << " tries. Will attempt to reconnect in " << full_delay + << " seconds" << LL_ENDL; + while (current_delay < full_delay && !sShuttingDown) + { + // Assuming that a second has passed is not accurate, + // but we don't need accurancy here, just to make sure + // that some time passed and not to outlive voice itself + current_delay++; + llcoro::suspendUntilTimeout(1.f); + } + coro_state = VOICE_STATE_WAIT_FOR_EXIT; + } + else + { + coro_state = VOICE_STATE_DONE; + } + break; + + case VOICE_STATE_SESSION_ESTABLISHED: + { + // enable/disable the automatic VAD and explicitly set the initial values of + // the VAD variables ourselves when it is off - see SL-15072 for more details + // note: we set the other parameters too even if the auto VAD is on which is ok + unsigned int vad_auto = gSavedSettings.getU32("VivoxVadAuto"); + unsigned int vad_hangover = gSavedSettings.getU32("VivoxVadHangover"); + unsigned int vad_noise_floor = gSavedSettings.getU32("VivoxVadNoiseFloor"); + unsigned int vad_sensitivity = gSavedSettings.getU32("VivoxVadSensitivity"); + setupVADParams(vad_auto, vad_hangover, vad_noise_floor, vad_sensitivity); + + // watch for changes to the VAD settings via Debug Settings UI and act on them accordingly + gSavedSettings.getControl("VivoxVadAuto")->getSignal()->connect(boost::bind(&LLVivoxVoiceClient::onVADSettingsChange, this)); + gSavedSettings.getControl("VivoxVadHangover")->getSignal()->connect(boost::bind(&LLVivoxVoiceClient::onVADSettingsChange, this)); + gSavedSettings.getControl("VivoxVadNoiseFloor")->getSignal()->connect(boost::bind(&LLVivoxVoiceClient::onVADSettingsChange, this)); + gSavedSettings.getControl("VivoxVadSensitivity")->getSignal()->connect(boost::bind(&LLVivoxVoiceClient::onVADSettingsChange, this)); + + if (mTuningMode) + { + performMicTuning(); + } + + coro_state = VOICE_STATE_WAIT_FOR_CHANNEL; + } + break; + + case VOICE_STATE_WAIT_FOR_CHANNEL: + waitForChannel(); + coro_state = VOICE_STATE_DISCONNECT; + break; + + case VOICE_STATE_DISCONNECT: + LL_DEBUGS("Voice") << "lost channel RelogRequested=" << mRelogRequested << LL_ENDL; + endAndDisconnectSession(); + retry = 0; // Connected without issues + coro_state = VOICE_STATE_WAIT_FOR_EXIT; + break; + + case VOICE_STATE_WAIT_FOR_EXIT: + if (isGatewayRunning()) { LL_INFOS("Voice") << "waiting for SLVoice to exit" << LL_ENDL; llcoro::suspendUntilTimeout(1.0); } + else if (mRelogRequested && mVoiceEnabled) + { + LL_INFOS("Voice") << "will attempt to reconnect to voice" << LL_ENDL; + coro_state = VOICE_STATE_TP_WAIT; + } + else + { + coro_state = VOICE_STATE_DONE; + } + break; + + case VOICE_STATE_DONE: + break; } - } - while (mVoiceEnabled && mRelogRequested && !sShuttingDown); + } while (coro_state > 0); + mIsCoroutineActive = false; LL_INFOS("Voice") << "exiting" << LL_ENDL; } -bool LLVivoxVoiceClient::startAndConnectSession() -{ - bool ok = false; - LL_DEBUGS("Voice") << LL_ENDL; - - LLVoiceVivoxStats::getInstance()->reset(); - - if (startAndLaunchDaemon()) - { - if (provisionVoiceAccount()) - { - if (establishVoiceConnection()) - { - ok = true; - } - } - } - - if (!ok) - { - giveUp(); - } - - return ok; -} - bool LLVivoxVoiceClient::endAndDisconnectSession() { LL_DEBUGS("Voice") << LL_ENDL; @@ -1047,7 +1107,7 @@ bool LLVivoxVoiceClient::provisionVoiceAccount() if (status == LLCore::HttpStatus(404)) { F32 timeout = pow(PROVISION_RETRY_TIMEOUT, static_cast(retryCount)); - LL_WARNS("Voice") << "Provision CAP 404. Retrying in " << timeout << " seconds." << LL_ENDL; + LL_WARNS("Voice") << "Provision CAP 404. Retrying in " << timeout << " seconds. Retries: " << (S32)retryCount << LL_ENDL; if (sShuttingDown) { return false; @@ -1798,7 +1858,6 @@ bool LLVivoxVoiceClient::waitForChannel() if (sShuttingDown) { - logoutOfVivox(false); return false; } diff --git a/indra/newview/llvoicevivox.h b/indra/newview/llvoicevivox.h index 75ff5429f3..4ee0545a72 100644 --- a/indra/newview/llvoicevivox.h +++ b/indra/newview/llvoicevivox.h @@ -627,7 +627,6 @@ private: //--- void voiceControlCoro(); - bool startAndConnectSession(); bool endAndDisconnectSession(); bool callbackEndDaemon(const LLSD& data); From 1e7fd6302aa39f1a011e2e4d711bca7a88a62076 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Wed, 18 Aug 2021 22:27:19 +0300 Subject: [PATCH 177/256] SL-15462 Refactor voiceControlCoro() into a state machine #2 --- indra/newview/llvoicevivox.cpp | 38 ++++++++++++++++++++++++++++++---- indra/newview/llvoicevivox.h | 1 + 2 files changed, 35 insertions(+), 4 deletions(-) diff --git a/indra/newview/llvoicevivox.cpp b/indra/newview/llvoicevivox.cpp index a8d5ef627f..4aa6f2c6b2 100644 --- a/indra/newview/llvoicevivox.cpp +++ b/indra/newview/llvoicevivox.cpp @@ -675,6 +675,30 @@ typedef enum e_voice_control_coro_state } EVoiceControlCoroState; void LLVivoxVoiceClient::voiceControlCoro() +{ + int state = 0; + try + { + // state is passed as a reference instead of being + // a member due to unresolved issues with coroutine + // surviving longer than LLVivoxVoiceClient + voiceControlStateMachine(state); + } + catch (const LLContinueError&) + { + LOG_UNHANDLED_EXCEPTION("LLVivoxVoiceClient"); + } + catch (...) + { + // Ideally for Windows need to log SEH exception instead or to set SEH + // handlers but bugsplat shows local variables for windows, which should + // be enough + LL_WARNS("Voice") << "voiceControlStateMachine crashed in state " << state << LL_ENDL; + throw; + } +} + +void LLVivoxVoiceClient::voiceControlStateMachine(S32 &coro_state) { LL_DEBUGS("Voice") << "starting" << LL_ENDL; mIsCoroutineActive = true; @@ -682,14 +706,15 @@ void LLVivoxVoiceClient::voiceControlCoro() U32 retry = 0; - EVoiceControlCoroState coro_state = VOICE_STATE_TP_WAIT; + coro_state = VOICE_STATE_TP_WAIT; do { if (sShuttingDown) { - // Vivox singleton performed the exit, and no longer - // cares about state of coroutine, so just stop + // Vivox singleton performed the exit, logged out, + // cleaned sockets, gateway and no longer cares + // about state of coroutine, so just stop return; } @@ -797,7 +822,7 @@ void LLVivoxVoiceClient::voiceControlCoro() break; case VOICE_STATE_WAIT_FOR_CHANNEL: - waitForChannel(); + waitForChannel(); // todo: split into more states like login/fonts coro_state = VOICE_STATE_DISCONNECT; break; @@ -1865,6 +1890,11 @@ bool LLVivoxVoiceClient::waitForChannel() { retrieveVoiceFonts(); + if (sShuttingDown) + { + return false; + } + // Request the set of available voice fonts. refreshVoiceEffectLists(false); } diff --git a/indra/newview/llvoicevivox.h b/indra/newview/llvoicevivox.h index 4ee0545a72..cf30a4e86a 100644 --- a/indra/newview/llvoicevivox.h +++ b/indra/newview/llvoicevivox.h @@ -626,6 +626,7 @@ private: // Coroutine support methods //--- void voiceControlCoro(); + void voiceControlStateMachine(S32 &coro_state); bool endAndDisconnectSession(); From 64f76f17ca0e5fd18aa4a0b165213271894393cb Mon Sep 17 00:00:00 2001 From: Andrey Lihatskiy Date: Thu, 14 Oct 2021 21:26:34 +0300 Subject: [PATCH 178/256] DRTVWR-545 Raised the viewer version to 6.5.0 --- indra/newview/VIEWER_VERSION.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/indra/newview/VIEWER_VERSION.txt b/indra/newview/VIEWER_VERSION.txt index f186cd8874..f22d756da3 100644 --- a/indra/newview/VIEWER_VERSION.txt +++ b/indra/newview/VIEWER_VERSION.txt @@ -1 +1 @@ -6.4.24 +6.5.0 From 3edc1406a0e4c2e58d0e5f288ee557405c6a7407 Mon Sep 17 00:00:00 2001 From: Nicky Date: Sat, 16 Oct 2021 07:37:58 -0400 Subject: [PATCH 179/256] OSX; Fixup manifest script after latest merge. --- indra/newview/viewer_manifest.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py index 4b1a3814a3..01974c4aba 100755 --- a/indra/newview/viewer_manifest.py +++ b/indra/newview/viewer_manifest.py @@ -1448,6 +1448,8 @@ class DarwinManifest(ViewerManifest): # in our bundled sub-apps. For each of these we'll create a # symlink from sub-app/Contents/Resources to the real .dylib. # Need to get the llcommon dll from any of the build directories as well. + libfile_parent = self.get_dst_prefix() + libfile = "libllcommon.dylib" dylibs = [] for libfile in ( "libapr-1.0.dylib", From 2935c125fef71547a3522a647e8f15aabb5f4461 Mon Sep 17 00:00:00 2001 From: Nicky Date: Sat, 16 Oct 2021 14:17:39 +0200 Subject: [PATCH 180/256] Linux; Update openssl. --- autobuild.xml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/autobuild.xml b/autobuild.xml index 944bf6f96f..20345e7787 100644 --- a/autobuild.xml +++ b/autobuild.xml @@ -656,9 +656,9 @@ archive hash - 51d9ce98279709854b0be5d0f450ba63 + 96dd770f246917589b776300a2d07f9e url - http://3p.firestormviewer.org/curl-7.54.1.180841943-linux64-180841943.tar.bz2 + http://3p.firestormviewer.org/curl-7.54.1.212891029-linux64-212891029.tar.bz2 name linux64 @@ -2968,9 +2968,9 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors archive hash - 7920fce93d9addf63a420d86f91c5749 + ea82e634334bccf088daf3d15eab07b7 url - http://3p.firestormviewer.org/openssl-1.0.2l.180841936-linux64-180841936.tar.bz2 + http://3p.firestormviewer.org/openssl-1.1.1l.212872015-linux64-212872015.tar.bz2 name linux64 From 0463537d0302a48a0ed5b039088a53e2d13840fa Mon Sep 17 00:00:00 2001 From: Nicky Date: Sat, 16 Oct 2021 14:18:01 +0200 Subject: [PATCH 181/256] Replace one leftover deprecated openssl call with the supported function. --- indra/newview/llsechandler_basic.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/indra/newview/llsechandler_basic.cpp b/indra/newview/llsechandler_basic.cpp index f43f23a516..5d79b53a55 100644 --- a/indra/newview/llsechandler_basic.cpp +++ b/indra/newview/llsechandler_basic.cpp @@ -355,7 +355,7 @@ LLSD cert_name_from_X509_NAME(X509_NAME* name) char buffer[32]; X509_NAME_ENTRY *entry = X509_NAME_get_entry(name, entry_index); - std::string name_value = std::string((const char*)ASN1_STRING_data(X509_NAME_ENTRY_get_data(entry)), + std::string name_value = std::string((const char*)ASN1_STRING_get0_data(X509_NAME_ENTRY_get_data(entry)), ASN1_STRING_length(X509_NAME_ENTRY_get_data(entry))); ASN1_OBJECT* name_obj = X509_NAME_ENTRY_get_object(entry); From 673725415afc240bebbdd3ca78016ed33860c8f4 Mon Sep 17 00:00:00 2001 From: Nicky Date: Sat, 16 Oct 2021 14:36:26 +0200 Subject: [PATCH 182/256] Linux; Remove crash logger. --- indra/newview/CMakeLists.txt | 2 +- indra/newview/viewer_manifest.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index 1581f45731..717176c35c 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -2562,7 +2562,7 @@ if (NOT ENABLE_MEDIA_PLUGINS) else (NOT ENABLE_MEDIA_PLUGINS) set(COPY_INPUT_DEPENDENCIES ${VIEWER_BINARY_NAME} - linux-crash-logger + #linux-crash-logger SLPlugin media_plugin_cef #media_plugin_gstreamer010 diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py index 01974c4aba..1a224a571a 100755 --- a/indra/newview/viewer_manifest.py +++ b/indra/newview/viewer_manifest.py @@ -1831,7 +1831,7 @@ class LinuxManifest(ViewerManifest): with self.prefix(dst="bin"): self.path("firestorm-bin","do-not-directly-run-firestorm-bin") - self.path("../linux_crash_logger/linux-crash-logger","linux-crash-logger.bin") + #self.path("../linux_crash_logger/linux-crash-logger","linux-crash-logger.bin") self.path2basename("../llplugin/slplugin", "SLPlugin") #this copies over the python wrapper script, associated utilities and required libraries, see SL-321, SL-322 and SL-323 # Remove VMP From cf74d0fa2358b979fdeec7d6b95bfcad0e03b671 Mon Sep 17 00:00:00 2001 From: Nicky Date: Sat, 16 Oct 2021 14:38:45 +0200 Subject: [PATCH 183/256] Fail early in case someone wants to compile with GCC >= 10. --- indra/cmake/00-Common.cmake | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/indra/cmake/00-Common.cmake b/indra/cmake/00-Common.cmake index 8e62e95bac..fc4c493152 100644 --- a/indra/cmake/00-Common.cmake +++ b/indra/cmake/00-Common.cmake @@ -165,6 +165,11 @@ endif (WINDOWS) if (LINUX) set(CMAKE_SKIP_RPATH TRUE) + + if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 10.0.0 ) + message( FATAL_ERROR "GCC greater 9.4.0 is not supported. Recompile boost for support of GCC 10.0.0 and up." ) + endif() + # # And another hack for FORTIFY_SOURCE. Some distributions (for example Gentoo) define FORTIFY_SOURCE by default. # Check if this is the case, if yes, do not define it again. From a336802ba3acca4f380a945752e7b6f69cd43f11 Mon Sep 17 00:00:00 2001 From: Nicky Date: Sat, 16 Oct 2021 18:49:05 +0200 Subject: [PATCH 184/256] FIRE-31221 workaround for newer glibc versions, patch from Lance Corrimal. --- indra/llcommon/llpreprocessor.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/indra/llcommon/llpreprocessor.h b/indra/llcommon/llpreprocessor.h index 26197cb692..95c9543751 100644 --- a/indra/llcommon/llpreprocessor.h +++ b/indra/llcommon/llpreprocessor.h @@ -40,6 +40,12 @@ #define LL_BIG_ENDIAN 1 #endif +// FIRE-31221 workaround for newer glibc versions, patch from Lance Corrimal +// Figure out GLIBC version - 2.34 needs an additional include as a build fix +#if (__GLIBC__*1000 + __GLIBC_MINOR__) >= 2034 +#include +#endif +// // Per-compiler switches From a8df27ccdd89e0469b1ad7e8b950a96cd399796b Mon Sep 17 00:00:00 2001 From: Nicky Dasmijn Date: Sat, 16 Oct 2021 21:44:17 +0200 Subject: [PATCH 185/256] FIRE-31248; Fixup older GCC vesions. --- indra/cmake/OpenSSL.cmake | 2 +- indra/llcrashlogger/llcrashlogger.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/indra/cmake/OpenSSL.cmake b/indra/cmake/OpenSSL.cmake index 32400f5e4e..f43ba7c26e 100644 --- a/indra/cmake/OpenSSL.cmake +++ b/indra/cmake/OpenSSL.cmake @@ -17,7 +17,7 @@ else (USESYSTEMLIBS) endif (USESYSTEMLIBS) if (LINUX) - set(CRYPTO_LIBRARIES crypto dl) + set(CRYPTO_LIBRARIES crypto dl pthread) elseif (DARWIN) set(CRYPTO_LIBRARIES crypto) endif (LINUX) diff --git a/indra/llcrashlogger/llcrashlogger.cpp b/indra/llcrashlogger/llcrashlogger.cpp index 9d3ad8b3b9..b7c6cae08a 100644 --- a/indra/llcrashlogger/llcrashlogger.cpp +++ b/indra/llcrashlogger/llcrashlogger.cpp @@ -785,7 +785,7 @@ void LLCrashLogger::init_curl() } CRYPTO_set_locking_callback(ssl_locking_callback); - CRYPTO_THREADID_set_callback(ssl_thread_id_callback); + (void)CRYPTO_THREADID_set_callback(ssl_thread_id_callback); } } From a7011655227fbeb417dbbb9631c6dff40093d5d5 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Mon, 18 Oct 2021 17:36:14 +0300 Subject: [PATCH 186/256] SL-16047 Strip unused includes --- indra/media_plugins/cef/CMakeLists.txt | 3 --- indra/media_plugins/cef/media_plugin_cef.cpp | 5 +---- 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/indra/media_plugins/cef/CMakeLists.txt b/indra/media_plugins/cef/CMakeLists.txt index ce6278963d..854ba55731 100644 --- a/indra/media_plugins/cef/CMakeLists.txt +++ b/indra/media_plugins/cef/CMakeLists.txt @@ -5,7 +5,6 @@ project(media_plugin_cef) include(Boost) include(00-Common) include(LLCommon) -include(LLImage) include(LLPlugin) include(LLMath) include(LLRender) @@ -13,7 +12,6 @@ include(LLWindow) include(Linking) include(PluginAPI) include(MediaPluginBase) -include(OpenGL) include(CEFPlugin) @@ -22,7 +20,6 @@ include_directories( ${MEDIA_PLUGIN_BASE_INCLUDE_DIRS} ${LLCOMMON_INCLUDE_DIRS} ${LLMATH_INCLUDE_DIRS} - ${LLIMAGE_INCLUDE_DIRS} ${LLRENDER_INCLUDE_DIRS} ${LLWINDOW_INCLUDE_DIRS} ${CEF_INCLUDE_DIR} diff --git a/indra/media_plugins/cef/media_plugin_cef.cpp b/indra/media_plugins/cef/media_plugin_cef.cpp index 8465285d2b..11dec63cd3 100644 --- a/indra/media_plugins/cef/media_plugin_cef.cpp +++ b/indra/media_plugins/cef/media_plugin_cef.cpp @@ -29,7 +29,7 @@ #include "linden_common.h" #include "indra_constants.h" // for indra keyboard codes -#include "llgl.h" +#include "llglheaders.h" // for GL_* constants #include "llsdutil.h" #include "llplugininstance.h" #include "llpluginmessage.h" @@ -37,9 +37,6 @@ #include "volume_catcher.h" #include "media_plugin_base.h" -#include -#include - #include "dullahan.h" //////////////////////////////////////////////////////////////////////////////// From d49684d093e71b936757d5b1918b552e49d79fe0 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Tue, 19 Oct 2021 20:42:01 +0300 Subject: [PATCH 187/256] SL-14977 Fix passing wrong codes to ToUnicodeEx --- indra/newview/llviewerwindow.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp index dab506d650..def0cbdb89 100644 --- a/indra/newview/llviewerwindow.cpp +++ b/indra/newview/llviewerwindow.cpp @@ -3332,7 +3332,8 @@ BOOL LLViewerWindow::handleKey(KEY key, MASK mask) // ToUnicodeEx changes buffer state on OS below Win10, which is undesirable, // but since we already did a TranslateMessage() in gatherInput(), this // should have no negative effect - int res = ToUnicodeEx(key, 0, keyboard_state, chars, char_count, 1 << 2 /*do not modify buffer flag*/, layout); + // ToUnicodeEx works with virtual key codes + int res = ToUnicodeEx(raw_key, 0, keyboard_state, chars, char_count, 1 << 2 /*do not modify buffer flag*/, layout); if (res == 1 && chars[0] >= 0x20) { // Let it fall through to character handler and get a WM_CHAR. From a4a7a765f1bbf2a8c4db39ebede09925fb85008a Mon Sep 17 00:00:00 2001 From: Beq Date: Thu, 21 Oct 2021 13:18:45 +0100 Subject: [PATCH 188/256] Major refactor and extension of perfdata All data now collated in a separate thread via lock free queue data for all "self" attachments collected including non-rigged known issues: some double counting exists * in non rigged alpha mask, maybe elsewhere --- indra/llcommon/blockingconcurrentqueue.h | 582 +++ indra/llcommon/concurrentqueue.h | 3742 +++++++++++++++++ indra/llcommon/fsperfstats.cpp | 10 +- indra/llcommon/fsperfstats.h | 433 +- indra/llcommon/fstelemetry.h | 6 +- indra/llcommon/lightweightsemaphore.h | 411 ++ indra/newview/llappviewer.cpp | 12 +- indra/newview/lldrawpool.cpp | 17 +- indra/newview/lldrawpoolalpha.cpp | 67 +- indra/newview/lldrawpoolavatar.cpp | 26 +- indra/newview/lldrawpoolbump.cpp | 30 +- indra/newview/lldrawpoolmaterials.cpp | 25 +- indra/newview/lldrawpoolsimple.cpp | 13 + indra/newview/lldynamictexture.cpp | 11 +- indra/newview/llface.cpp | 18 +- indra/newview/llfloaterperformance.cpp | 157 +- indra/newview/llspatialpartition.cpp | 3 + indra/newview/llviewerdisplay.cpp | 6 +- indra/newview/llviewerjointmesh.cpp | 14 +- indra/newview/llvieweroctree.cpp | 4 + indra/newview/llvoavatar.cpp | 24 +- indra/newview/llvovolume.cpp | 38 +- indra/newview/pipeline.cpp | 26 +- .../xui/en/panel_performance_complexity.xml | 6 +- .../default/xui/en/panel_performance_huds.xml | 3 +- .../xui/en/panel_performance_nearby.xml | 8 +- 26 files changed, 5270 insertions(+), 422 deletions(-) create mode 100644 indra/llcommon/blockingconcurrentqueue.h create mode 100644 indra/llcommon/concurrentqueue.h create mode 100644 indra/llcommon/lightweightsemaphore.h diff --git a/indra/llcommon/blockingconcurrentqueue.h b/indra/llcommon/blockingconcurrentqueue.h new file mode 100644 index 0000000000..66579b6caf --- /dev/null +++ b/indra/llcommon/blockingconcurrentqueue.h @@ -0,0 +1,582 @@ +// Provides an efficient blocking version of moodycamel::ConcurrentQueue. +// ©2015-2020 Cameron Desrochers. Distributed under the terms of the simplified +// BSD license, available at the top of concurrentqueue.h. +// Also dual-licensed under the Boost Software License (see LICENSE.md) +// Uses Jeff Preshing's semaphore implementation (under the terms of its +// separate zlib license, see lightweightsemaphore.h). + +#pragma once + +#include "concurrentqueue.h" +#include "lightweightsemaphore.h" + +#include +#include +#include +#include +#include + +namespace moodycamel +{ +// This is a blocking version of the queue. It has an almost identical interface to +// the normal non-blocking version, with the addition of various wait_dequeue() methods +// and the removal of producer-specific dequeue methods. +template +class BlockingConcurrentQueue +{ +private: + typedef ::moodycamel::ConcurrentQueue ConcurrentQueue; + typedef ::moodycamel::LightweightSemaphore LightweightSemaphore; + +public: + typedef typename ConcurrentQueue::producer_token_t producer_token_t; + typedef typename ConcurrentQueue::consumer_token_t consumer_token_t; + + typedef typename ConcurrentQueue::index_t index_t; + typedef typename ConcurrentQueue::size_t size_t; + typedef typename std::make_signed::type ssize_t; + + static const size_t BLOCK_SIZE = ConcurrentQueue::BLOCK_SIZE; + static const size_t EXPLICIT_BLOCK_EMPTY_COUNTER_THRESHOLD = ConcurrentQueue::EXPLICIT_BLOCK_EMPTY_COUNTER_THRESHOLD; + static const size_t EXPLICIT_INITIAL_INDEX_SIZE = ConcurrentQueue::EXPLICIT_INITIAL_INDEX_SIZE; + static const size_t IMPLICIT_INITIAL_INDEX_SIZE = ConcurrentQueue::IMPLICIT_INITIAL_INDEX_SIZE; + static const size_t INITIAL_IMPLICIT_PRODUCER_HASH_SIZE = ConcurrentQueue::INITIAL_IMPLICIT_PRODUCER_HASH_SIZE; + static const std::uint32_t EXPLICIT_CONSUMER_CONSUMPTION_QUOTA_BEFORE_ROTATE = ConcurrentQueue::EXPLICIT_CONSUMER_CONSUMPTION_QUOTA_BEFORE_ROTATE; + static const size_t MAX_SUBQUEUE_SIZE = ConcurrentQueue::MAX_SUBQUEUE_SIZE; + +public: + // Creates a queue with at least `capacity` element slots; note that the + // actual number of elements that can be inserted without additional memory + // allocation depends on the number of producers and the block size (e.g. if + // the block size is equal to `capacity`, only a single block will be allocated + // up-front, which means only a single producer will be able to enqueue elements + // without an extra allocation -- blocks aren't shared between producers). + // This method is not thread safe -- it is up to the user to ensure that the + // queue is fully constructed before it starts being used by other threads (this + // includes making the memory effects of construction visible, possibly with a + // memory barrier). + explicit BlockingConcurrentQueue(size_t capacity = 6 * BLOCK_SIZE) + : inner(capacity), sema(create(0, (int)Traits::MAX_SEMA_SPINS), &BlockingConcurrentQueue::template destroy) + { + assert(reinterpret_cast((BlockingConcurrentQueue*)1) == &((BlockingConcurrentQueue*)1)->inner && "BlockingConcurrentQueue must have ConcurrentQueue as its first member"); + if (!sema) { + MOODYCAMEL_THROW(std::bad_alloc()); + } + } + + BlockingConcurrentQueue(size_t minCapacity, size_t maxExplicitProducers, size_t maxImplicitProducers) + : inner(minCapacity, maxExplicitProducers, maxImplicitProducers), sema(create(0, (int)Traits::MAX_SEMA_SPINS), &BlockingConcurrentQueue::template destroy) + { + assert(reinterpret_cast((BlockingConcurrentQueue*)1) == &((BlockingConcurrentQueue*)1)->inner && "BlockingConcurrentQueue must have ConcurrentQueue as its first member"); + if (!sema) { + MOODYCAMEL_THROW(std::bad_alloc()); + } + } + + // Disable copying and copy assignment + BlockingConcurrentQueue(BlockingConcurrentQueue const&) MOODYCAMEL_DELETE_FUNCTION; + BlockingConcurrentQueue& operator=(BlockingConcurrentQueue const&) MOODYCAMEL_DELETE_FUNCTION; + + // Moving is supported, but note that it is *not* a thread-safe operation. + // Nobody can use the queue while it's being moved, and the memory effects + // of that move must be propagated to other threads before they can use it. + // Note: When a queue is moved, its tokens are still valid but can only be + // used with the destination queue (i.e. semantically they are moved along + // with the queue itself). + BlockingConcurrentQueue(BlockingConcurrentQueue&& other) MOODYCAMEL_NOEXCEPT + : inner(std::move(other.inner)), sema(std::move(other.sema)) + { } + + inline BlockingConcurrentQueue& operator=(BlockingConcurrentQueue&& other) MOODYCAMEL_NOEXCEPT + { + return swap_internal(other); + } + + // Swaps this queue's state with the other's. Not thread-safe. + // Swapping two queues does not invalidate their tokens, however + // the tokens that were created for one queue must be used with + // only the swapped queue (i.e. the tokens are tied to the + // queue's movable state, not the object itself). + inline void swap(BlockingConcurrentQueue& other) MOODYCAMEL_NOEXCEPT + { + swap_internal(other); + } + +private: + BlockingConcurrentQueue& swap_internal(BlockingConcurrentQueue& other) + { + if (this == &other) { + return *this; + } + + inner.swap(other.inner); + sema.swap(other.sema); + return *this; + } + +public: + // Enqueues a single item (by copying it). + // Allocates memory if required. Only fails if memory allocation fails (or implicit + // production is disabled because Traits::INITIAL_IMPLICIT_PRODUCER_HASH_SIZE is 0, + // or Traits::MAX_SUBQUEUE_SIZE has been defined and would be surpassed). + // Thread-safe. + inline bool enqueue(T const& item) + { + if ((details::likely)(inner.enqueue(item))) { + sema->signal(); + return true; + } + return false; + } + + // Enqueues a single item (by moving it, if possible). + // Allocates memory if required. Only fails if memory allocation fails (or implicit + // production is disabled because Traits::INITIAL_IMPLICIT_PRODUCER_HASH_SIZE is 0, + // or Traits::MAX_SUBQUEUE_SIZE has been defined and would be surpassed). + // Thread-safe. + inline bool enqueue(T&& item) + { + if ((details::likely)(inner.enqueue(std::move(item)))) { + sema->signal(); + return true; + } + return false; + } + + // Enqueues a single item (by copying it) using an explicit producer token. + // Allocates memory if required. Only fails if memory allocation fails (or + // Traits::MAX_SUBQUEUE_SIZE has been defined and would be surpassed). + // Thread-safe. + inline bool enqueue(producer_token_t const& token, T const& item) + { + if ((details::likely)(inner.enqueue(token, item))) { + sema->signal(); + return true; + } + return false; + } + + // Enqueues a single item (by moving it, if possible) using an explicit producer token. + // Allocates memory if required. Only fails if memory allocation fails (or + // Traits::MAX_SUBQUEUE_SIZE has been defined and would be surpassed). + // Thread-safe. + inline bool enqueue(producer_token_t const& token, T&& item) + { + if ((details::likely)(inner.enqueue(token, std::move(item)))) { + sema->signal(); + return true; + } + return false; + } + + // Enqueues several items. + // Allocates memory if required. Only fails if memory allocation fails (or + // implicit production is disabled because Traits::INITIAL_IMPLICIT_PRODUCER_HASH_SIZE + // is 0, or Traits::MAX_SUBQUEUE_SIZE has been defined and would be surpassed). + // Note: Use std::make_move_iterator if the elements should be moved instead of copied. + // Thread-safe. + template + inline bool enqueue_bulk(It itemFirst, size_t count) + { + if ((details::likely)(inner.enqueue_bulk(std::forward(itemFirst), count))) { + sema->signal((LightweightSemaphore::ssize_t)(ssize_t)count); + return true; + } + return false; + } + + // Enqueues several items using an explicit producer token. + // Allocates memory if required. Only fails if memory allocation fails + // (or Traits::MAX_SUBQUEUE_SIZE has been defined and would be surpassed). + // Note: Use std::make_move_iterator if the elements should be moved + // instead of copied. + // Thread-safe. + template + inline bool enqueue_bulk(producer_token_t const& token, It itemFirst, size_t count) + { + if ((details::likely)(inner.enqueue_bulk(token, std::forward(itemFirst), count))) { + sema->signal((LightweightSemaphore::ssize_t)(ssize_t)count); + return true; + } + return false; + } + + // Enqueues a single item (by copying it). + // Does not allocate memory. Fails if not enough room to enqueue (or implicit + // production is disabled because Traits::INITIAL_IMPLICIT_PRODUCER_HASH_SIZE + // is 0). + // Thread-safe. + inline bool try_enqueue(T const& item) + { + if (inner.try_enqueue(item)) { + sema->signal(); + return true; + } + return false; + } + + // Enqueues a single item (by moving it, if possible). + // Does not allocate memory (except for one-time implicit producer). + // Fails if not enough room to enqueue (or implicit production is + // disabled because Traits::INITIAL_IMPLICIT_PRODUCER_HASH_SIZE is 0). + // Thread-safe. + inline bool try_enqueue(T&& item) + { + if (inner.try_enqueue(std::move(item))) { + sema->signal(); + return true; + } + return false; + } + + // Enqueues a single item (by copying it) using an explicit producer token. + // Does not allocate memory. Fails if not enough room to enqueue. + // Thread-safe. + inline bool try_enqueue(producer_token_t const& token, T const& item) + { + if (inner.try_enqueue(token, item)) { + sema->signal(); + return true; + } + return false; + } + + // Enqueues a single item (by moving it, if possible) using an explicit producer token. + // Does not allocate memory. Fails if not enough room to enqueue. + // Thread-safe. + inline bool try_enqueue(producer_token_t const& token, T&& item) + { + if (inner.try_enqueue(token, std::move(item))) { + sema->signal(); + return true; + } + return false; + } + + // Enqueues several items. + // Does not allocate memory (except for one-time implicit producer). + // Fails if not enough room to enqueue (or implicit production is + // disabled because Traits::INITIAL_IMPLICIT_PRODUCER_HASH_SIZE is 0). + // Note: Use std::make_move_iterator if the elements should be moved + // instead of copied. + // Thread-safe. + template + inline bool try_enqueue_bulk(It itemFirst, size_t count) + { + if (inner.try_enqueue_bulk(std::forward(itemFirst), count)) { + sema->signal((LightweightSemaphore::ssize_t)(ssize_t)count); + return true; + } + return false; + } + + // Enqueues several items using an explicit producer token. + // Does not allocate memory. Fails if not enough room to enqueue. + // Note: Use std::make_move_iterator if the elements should be moved + // instead of copied. + // Thread-safe. + template + inline bool try_enqueue_bulk(producer_token_t const& token, It itemFirst, size_t count) + { + if (inner.try_enqueue_bulk(token, std::forward(itemFirst), count)) { + sema->signal((LightweightSemaphore::ssize_t)(ssize_t)count); + return true; + } + return false; + } + + + // Attempts to dequeue from the queue. + // Returns false if all producer streams appeared empty at the time they + // were checked (so, the queue is likely but not guaranteed to be empty). + // Never allocates. Thread-safe. + template + inline bool try_dequeue(U& item) + { + if (sema->tryWait()) { + while (!inner.try_dequeue(item)) { + continue; + } + return true; + } + return false; + } + + // Attempts to dequeue from the queue using an explicit consumer token. + // Returns false if all producer streams appeared empty at the time they + // were checked (so, the queue is likely but not guaranteed to be empty). + // Never allocates. Thread-safe. + template + inline bool try_dequeue(consumer_token_t& token, U& item) + { + if (sema->tryWait()) { + while (!inner.try_dequeue(token, item)) { + continue; + } + return true; + } + return false; + } + + // Attempts to dequeue several elements from the queue. + // Returns the number of items actually dequeued. + // Returns 0 if all producer streams appeared empty at the time they + // were checked (so, the queue is likely but not guaranteed to be empty). + // Never allocates. Thread-safe. + template + inline size_t try_dequeue_bulk(It itemFirst, size_t max) + { + size_t count = 0; + max = (size_t)sema->tryWaitMany((LightweightSemaphore::ssize_t)(ssize_t)max); + while (count != max) { + count += inner.template try_dequeue_bulk(itemFirst, max - count); + } + return count; + } + + // Attempts to dequeue several elements from the queue using an explicit consumer token. + // Returns the number of items actually dequeued. + // Returns 0 if all producer streams appeared empty at the time they + // were checked (so, the queue is likely but not guaranteed to be empty). + // Never allocates. Thread-safe. + template + inline size_t try_dequeue_bulk(consumer_token_t& token, It itemFirst, size_t max) + { + size_t count = 0; + max = (size_t)sema->tryWaitMany((LightweightSemaphore::ssize_t)(ssize_t)max); + while (count != max) { + count += inner.template try_dequeue_bulk(token, itemFirst, max - count); + } + return count; + } + + + + // Blocks the current thread until there's something to dequeue, then + // dequeues it. + // Never allocates. Thread-safe. + template + inline void wait_dequeue(U& item) + { + while (!sema->wait()) { + continue; + } + while (!inner.try_dequeue(item)) { + continue; + } + } + + // Blocks the current thread until either there's something to dequeue + // or the timeout (specified in microseconds) expires. Returns false + // without setting `item` if the timeout expires, otherwise assigns + // to `item` and returns true. + // Using a negative timeout indicates an indefinite timeout, + // and is thus functionally equivalent to calling wait_dequeue. + // Never allocates. Thread-safe. + template + inline bool wait_dequeue_timed(U& item, std::int64_t timeout_usecs) + { + if (!sema->wait(timeout_usecs)) { + return false; + } + while (!inner.try_dequeue(item)) { + continue; + } + return true; + } + + // Blocks the current thread until either there's something to dequeue + // or the timeout expires. Returns false without setting `item` if the + // timeout expires, otherwise assigns to `item` and returns true. + // Never allocates. Thread-safe. + template + inline bool wait_dequeue_timed(U& item, std::chrono::duration const& timeout) + { + return wait_dequeue_timed(item, std::chrono::duration_cast(timeout).count()); + } + + // Blocks the current thread until there's something to dequeue, then + // dequeues it using an explicit consumer token. + // Never allocates. Thread-safe. + template + inline void wait_dequeue(consumer_token_t& token, U& item) + { + while (!sema->wait()) { + continue; + } + while (!inner.try_dequeue(token, item)) { + continue; + } + } + + // Blocks the current thread until either there's something to dequeue + // or the timeout (specified in microseconds) expires. Returns false + // without setting `item` if the timeout expires, otherwise assigns + // to `item` and returns true. + // Using a negative timeout indicates an indefinite timeout, + // and is thus functionally equivalent to calling wait_dequeue. + // Never allocates. Thread-safe. + template + inline bool wait_dequeue_timed(consumer_token_t& token, U& item, std::int64_t timeout_usecs) + { + if (!sema->wait(timeout_usecs)) { + return false; + } + while (!inner.try_dequeue(token, item)) { + continue; + } + return true; + } + + // Blocks the current thread until either there's something to dequeue + // or the timeout expires. Returns false without setting `item` if the + // timeout expires, otherwise assigns to `item` and returns true. + // Never allocates. Thread-safe. + template + inline bool wait_dequeue_timed(consumer_token_t& token, U& item, std::chrono::duration const& timeout) + { + return wait_dequeue_timed(token, item, std::chrono::duration_cast(timeout).count()); + } + + // Attempts to dequeue several elements from the queue. + // Returns the number of items actually dequeued, which will + // always be at least one (this method blocks until the queue + // is non-empty) and at most max. + // Never allocates. Thread-safe. + template + inline size_t wait_dequeue_bulk(It itemFirst, size_t max) + { + size_t count = 0; + max = (size_t)sema->waitMany((LightweightSemaphore::ssize_t)(ssize_t)max); + while (count != max) { + count += inner.template try_dequeue_bulk(itemFirst, max - count); + } + return count; + } + + // Attempts to dequeue several elements from the queue. + // Returns the number of items actually dequeued, which can + // be 0 if the timeout expires while waiting for elements, + // and at most max. + // Using a negative timeout indicates an indefinite timeout, + // and is thus functionally equivalent to calling wait_dequeue_bulk. + // Never allocates. Thread-safe. + template + inline size_t wait_dequeue_bulk_timed(It itemFirst, size_t max, std::int64_t timeout_usecs) + { + size_t count = 0; + max = (size_t)sema->waitMany((LightweightSemaphore::ssize_t)(ssize_t)max, timeout_usecs); + while (count != max) { + count += inner.template try_dequeue_bulk(itemFirst, max - count); + } + return count; + } + + // Attempts to dequeue several elements from the queue. + // Returns the number of items actually dequeued, which can + // be 0 if the timeout expires while waiting for elements, + // and at most max. + // Never allocates. Thread-safe. + template + inline size_t wait_dequeue_bulk_timed(It itemFirst, size_t max, std::chrono::duration const& timeout) + { + return wait_dequeue_bulk_timed(itemFirst, max, std::chrono::duration_cast(timeout).count()); + } + + // Attempts to dequeue several elements from the queue using an explicit consumer token. + // Returns the number of items actually dequeued, which will + // always be at least one (this method blocks until the queue + // is non-empty) and at most max. + // Never allocates. Thread-safe. + template + inline size_t wait_dequeue_bulk(consumer_token_t& token, It itemFirst, size_t max) + { + size_t count = 0; + max = (size_t)sema->waitMany((LightweightSemaphore::ssize_t)(ssize_t)max); + while (count != max) { + count += inner.template try_dequeue_bulk(token, itemFirst, max - count); + } + return count; + } + + // Attempts to dequeue several elements from the queue using an explicit consumer token. + // Returns the number of items actually dequeued, which can + // be 0 if the timeout expires while waiting for elements, + // and at most max. + // Using a negative timeout indicates an indefinite timeout, + // and is thus functionally equivalent to calling wait_dequeue_bulk. + // Never allocates. Thread-safe. + template + inline size_t wait_dequeue_bulk_timed(consumer_token_t& token, It itemFirst, size_t max, std::int64_t timeout_usecs) + { + size_t count = 0; + max = (size_t)sema->waitMany((LightweightSemaphore::ssize_t)(ssize_t)max, timeout_usecs); + while (count != max) { + count += inner.template try_dequeue_bulk(token, itemFirst, max - count); + } + return count; + } + + // Attempts to dequeue several elements from the queue using an explicit consumer token. + // Returns the number of items actually dequeued, which can + // be 0 if the timeout expires while waiting for elements, + // and at most max. + // Never allocates. Thread-safe. + template + inline size_t wait_dequeue_bulk_timed(consumer_token_t& token, It itemFirst, size_t max, std::chrono::duration const& timeout) + { + return wait_dequeue_bulk_timed(token, itemFirst, max, std::chrono::duration_cast(timeout).count()); + } + + + // Returns an estimate of the total number of elements currently in the queue. This + // estimate is only accurate if the queue has completely stabilized before it is called + // (i.e. all enqueue and dequeue operations have completed and their memory effects are + // visible on the calling thread, and no further operations start while this method is + // being called). + // Thread-safe. + inline size_t size_approx() const + { + return (size_t)sema->availableApprox(); + } + + + // Returns true if the underlying atomic variables used by + // the queue are lock-free (they should be on most platforms). + // Thread-safe. + static bool is_lock_free() + { + return ConcurrentQueue::is_lock_free(); + } + + +private: + template + static inline U* create(A1&& a1, A2&& a2) + { + void* p = (Traits::malloc)(sizeof(U)); + return p != nullptr ? new (p) U(std::forward(a1), std::forward(a2)) : nullptr; + } + + template + static inline void destroy(U* p) + { + if (p != nullptr) { + p->~U(); + } + (Traits::free)(p); + } + +private: + ConcurrentQueue inner; + std::unique_ptr sema; +}; + + +template +inline void swap(BlockingConcurrentQueue& a, BlockingConcurrentQueue& b) MOODYCAMEL_NOEXCEPT +{ + a.swap(b); +} + +} // end namespace moodycamel diff --git a/indra/llcommon/concurrentqueue.h b/indra/llcommon/concurrentqueue.h new file mode 100644 index 0000000000..609ca4ab50 --- /dev/null +++ b/indra/llcommon/concurrentqueue.h @@ -0,0 +1,3742 @@ +// Provides a C++11 implementation of a multi-producer, multi-consumer lock-free queue. +// An overview, including benchmark results, is provided here: +// http://moodycamel.com/blog/2014/a-fast-general-purpose-lock-free-queue-for-c++ +// The full design is also described in excruciating detail at: +// http://moodycamel.com/blog/2014/detailed-design-of-a-lock-free-queue + +// Simplified BSD license: +// Copyright (c) 2013-2020, Cameron Desrochers. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// - Redistributions of source code must retain the above copyright notice, this list of +// conditions and the following disclaimer. +// - Redistributions in binary form must reproduce the above copyright notice, this list of +// conditions and the following disclaimer in the documentation and/or other materials +// provided with the distribution. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL +// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT +// OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR +// TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, +// EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Also dual-licensed under the Boost Software License (see LICENSE.md) + +#pragma once + +#if defined(__GNUC__) && !defined(__INTEL_COMPILER) +// Disable -Wconversion warnings (spuriously triggered when Traits::size_t and +// Traits::index_t are set to < 32 bits, causing integer promotion, causing warnings +// upon assigning any computed values) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wconversion" + +#ifdef MCDBGQ_USE_RELACY +#pragma GCC diagnostic ignored "-Wint-to-pointer-cast" +#endif +#endif + +#if defined(_MSC_VER) && (!defined(_HAS_CXX17) || !_HAS_CXX17) +// VS2019 with /W4 warns about constant conditional expressions but unless /std=c++17 or higher +// does not support `if constexpr`, so we have no choice but to simply disable the warning +#pragma warning(push) +#pragma warning(disable: 4127) // conditional expression is constant +#endif + +#if defined(__APPLE__) +#include "TargetConditionals.h" +#endif + +#ifdef MCDBGQ_USE_RELACY +#include "relacy/relacy_std.hpp" +#include "relacy_shims.h" +// We only use malloc/free anyway, and the delete macro messes up `= delete` method declarations. +// We'll override the default trait malloc ourselves without a macro. +#undef new +#undef delete +#undef malloc +#undef free +#else +#include // Requires C++11. Sorry VS2010. +#include +#endif +#include // for max_align_t +#include +#include +#include +#include +#include +#include +#include // for CHAR_BIT +#include +#include // partly for __WINPTHREADS_VERSION if on MinGW-w64 w/ POSIX threading + +// Platform-specific definitions of a numeric thread ID type and an invalid value +namespace moodycamel { namespace details { + template struct thread_id_converter { + typedef thread_id_t thread_id_numeric_size_t; + typedef thread_id_t thread_id_hash_t; + static thread_id_hash_t prehash(thread_id_t const& x) { return x; } + }; +} } +#if defined(MCDBGQ_USE_RELACY) +namespace moodycamel { namespace details { + typedef std::uint32_t thread_id_t; + static const thread_id_t invalid_thread_id = 0xFFFFFFFFU; + static const thread_id_t invalid_thread_id2 = 0xFFFFFFFEU; + static inline thread_id_t thread_id() { return rl::thread_index(); } +} } +#elif defined(_WIN32) || defined(__WINDOWS__) || defined(__WIN32__) +// No sense pulling in windows.h in a header, we'll manually declare the function +// we use and rely on backwards-compatibility for this not to break +extern "C" __declspec(dllimport) unsigned long __stdcall GetCurrentThreadId(void); +namespace moodycamel { namespace details { + static_assert(sizeof(unsigned long) == sizeof(std::uint32_t), "Expected size of unsigned long to be 32 bits on Windows"); + typedef std::uint32_t thread_id_t; + static const thread_id_t invalid_thread_id = 0; // See http://blogs.msdn.com/b/oldnewthing/archive/2004/02/23/78395.aspx + static const thread_id_t invalid_thread_id2 = 0xFFFFFFFFU; // Not technically guaranteed to be invalid, but is never used in practice. Note that all Win32 thread IDs are presently multiples of 4. + static inline thread_id_t thread_id() { return static_cast(::GetCurrentThreadId()); } +} } +#elif defined(__arm__) || defined(_M_ARM) || defined(__aarch64__) || (defined(__APPLE__) && TARGET_OS_IPHONE) || defined(MOODYCAMEL_NO_THREAD_LOCAL) +namespace moodycamel { namespace details { + static_assert(sizeof(std::thread::id) == 4 || sizeof(std::thread::id) == 8, "std::thread::id is expected to be either 4 or 8 bytes"); + + typedef std::thread::id thread_id_t; + static const thread_id_t invalid_thread_id; // Default ctor creates invalid ID + + // Note we don't define a invalid_thread_id2 since std::thread::id doesn't have one; it's + // only used if MOODYCAMEL_CPP11_THREAD_LOCAL_SUPPORTED is defined anyway, which it won't + // be. + static inline thread_id_t thread_id() { return std::this_thread::get_id(); } + + template struct thread_id_size { }; + template<> struct thread_id_size<4> { typedef std::uint32_t numeric_t; }; + template<> struct thread_id_size<8> { typedef std::uint64_t numeric_t; }; + + template<> struct thread_id_converter { + typedef thread_id_size::numeric_t thread_id_numeric_size_t; +#ifndef __APPLE__ + typedef std::size_t thread_id_hash_t; +#else + typedef thread_id_numeric_size_t thread_id_hash_t; +#endif + + static thread_id_hash_t prehash(thread_id_t const& x) + { +#ifndef __APPLE__ + return std::hash()(x); +#else + return *reinterpret_cast(&x); +#endif + } + }; +} } +#else +// Use a nice trick from this answer: http://stackoverflow.com/a/8438730/21475 +// In order to get a numeric thread ID in a platform-independent way, we use a thread-local +// static variable's address as a thread identifier :-) +#if defined(__GNUC__) || defined(__INTEL_COMPILER) +#define MOODYCAMEL_THREADLOCAL __thread +#elif defined(_MSC_VER) +#define MOODYCAMEL_THREADLOCAL __declspec(thread) +#else +// Assume C++11 compliant compiler +#define MOODYCAMEL_THREADLOCAL thread_local +#endif +namespace moodycamel { namespace details { + typedef std::uintptr_t thread_id_t; + static const thread_id_t invalid_thread_id = 0; // Address can't be nullptr + static const thread_id_t invalid_thread_id2 = 1; // Member accesses off a null pointer are also generally invalid. Plus it's not aligned. + inline thread_id_t thread_id() { static MOODYCAMEL_THREADLOCAL int x; return reinterpret_cast(&x); } +} } +#endif + +// Constexpr if +#ifndef MOODYCAMEL_CONSTEXPR_IF +#if (defined(_MSC_VER) && defined(_HAS_CXX17) && _HAS_CXX17) || __cplusplus > 201402L +#define MOODYCAMEL_CONSTEXPR_IF if constexpr +#define MOODYCAMEL_MAYBE_UNUSED [[maybe_unused]] +#else +#define MOODYCAMEL_CONSTEXPR_IF if +#define MOODYCAMEL_MAYBE_UNUSED +#endif +#endif + +// Exceptions +#ifndef MOODYCAMEL_EXCEPTIONS_ENABLED +#if (defined(_MSC_VER) && defined(_CPPUNWIND)) || (defined(__GNUC__) && defined(__EXCEPTIONS)) || (!defined(_MSC_VER) && !defined(__GNUC__)) +#define MOODYCAMEL_EXCEPTIONS_ENABLED +#endif +#endif +#ifdef MOODYCAMEL_EXCEPTIONS_ENABLED +#define MOODYCAMEL_TRY try +#define MOODYCAMEL_CATCH(...) catch(__VA_ARGS__) +#define MOODYCAMEL_RETHROW throw +#define MOODYCAMEL_THROW(expr) throw (expr) +#else +#define MOODYCAMEL_TRY MOODYCAMEL_CONSTEXPR_IF (true) +#define MOODYCAMEL_CATCH(...) else MOODYCAMEL_CONSTEXPR_IF (false) +#define MOODYCAMEL_RETHROW +#define MOODYCAMEL_THROW(expr) +#endif + +#ifndef MOODYCAMEL_NOEXCEPT +#if !defined(MOODYCAMEL_EXCEPTIONS_ENABLED) +#define MOODYCAMEL_NOEXCEPT +#define MOODYCAMEL_NOEXCEPT_CTOR(type, valueType, expr) true +#define MOODYCAMEL_NOEXCEPT_ASSIGN(type, valueType, expr) true +#elif defined(_MSC_VER) && defined(_NOEXCEPT) && _MSC_VER < 1800 +// VS2012's std::is_nothrow_[move_]constructible is broken and returns true when it shouldn't :-( +// We have to assume *all* non-trivial constructors may throw on VS2012! +#define MOODYCAMEL_NOEXCEPT _NOEXCEPT +#define MOODYCAMEL_NOEXCEPT_CTOR(type, valueType, expr) (std::is_rvalue_reference::value && std::is_move_constructible::value ? std::is_trivially_move_constructible::value : std::is_trivially_copy_constructible::value) +#define MOODYCAMEL_NOEXCEPT_ASSIGN(type, valueType, expr) ((std::is_rvalue_reference::value && std::is_move_assignable::value ? std::is_trivially_move_assignable::value || std::is_nothrow_move_assignable::value : std::is_trivially_copy_assignable::value || std::is_nothrow_copy_assignable::value) && MOODYCAMEL_NOEXCEPT_CTOR(type, valueType, expr)) +#elif defined(_MSC_VER) && defined(_NOEXCEPT) && _MSC_VER < 1900 +#define MOODYCAMEL_NOEXCEPT _NOEXCEPT +#define MOODYCAMEL_NOEXCEPT_CTOR(type, valueType, expr) (std::is_rvalue_reference::value && std::is_move_constructible::value ? std::is_trivially_move_constructible::value || std::is_nothrow_move_constructible::value : std::is_trivially_copy_constructible::value || std::is_nothrow_copy_constructible::value) +#define MOODYCAMEL_NOEXCEPT_ASSIGN(type, valueType, expr) ((std::is_rvalue_reference::value && std::is_move_assignable::value ? std::is_trivially_move_assignable::value || std::is_nothrow_move_assignable::value : std::is_trivially_copy_assignable::value || std::is_nothrow_copy_assignable::value) && MOODYCAMEL_NOEXCEPT_CTOR(type, valueType, expr)) +#else +#define MOODYCAMEL_NOEXCEPT noexcept +#define MOODYCAMEL_NOEXCEPT_CTOR(type, valueType, expr) noexcept(expr) +#define MOODYCAMEL_NOEXCEPT_ASSIGN(type, valueType, expr) noexcept(expr) +#endif +#endif + +#ifndef MOODYCAMEL_CPP11_THREAD_LOCAL_SUPPORTED +#ifdef MCDBGQ_USE_RELACY +#define MOODYCAMEL_CPP11_THREAD_LOCAL_SUPPORTED +#else +// VS2013 doesn't support `thread_local`, and MinGW-w64 w/ POSIX threading has a crippling bug: http://sourceforge.net/p/mingw-w64/bugs/445 +// g++ <=4.7 doesn't support thread_local either. +// Finally, iOS/ARM doesn't have support for it either, and g++/ARM allows it to compile but it's unconfirmed to actually work +#if (!defined(_MSC_VER) || _MSC_VER >= 1900) && (!defined(__MINGW32__) && !defined(__MINGW64__) || !defined(__WINPTHREADS_VERSION)) && (!defined(__GNUC__) || __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8)) && (!defined(__APPLE__) || !TARGET_OS_IPHONE) && !defined(__arm__) && !defined(_M_ARM) && !defined(__aarch64__) +// Assume `thread_local` is fully supported in all other C++11 compilers/platforms +//#define MOODYCAMEL_CPP11_THREAD_LOCAL_SUPPORTED // always disabled for now since several users report having problems with it on +#endif +#endif +#endif + +// VS2012 doesn't support deleted functions. +// In this case, we declare the function normally but don't define it. A link error will be generated if the function is called. +#ifndef MOODYCAMEL_DELETE_FUNCTION +#if defined(_MSC_VER) && _MSC_VER < 1800 +#define MOODYCAMEL_DELETE_FUNCTION +#else +#define MOODYCAMEL_DELETE_FUNCTION = delete +#endif +#endif + +namespace moodycamel { namespace details { +#ifndef MOODYCAMEL_ALIGNAS +// VS2013 doesn't support alignas or alignof, and align() requires a constant literal +#if defined(_MSC_VER) && _MSC_VER <= 1800 +#define MOODYCAMEL_ALIGNAS(alignment) __declspec(align(alignment)) +#define MOODYCAMEL_ALIGNOF(obj) __alignof(obj) +#define MOODYCAMEL_ALIGNED_TYPE_LIKE(T, obj) typename details::Vs2013Aligned::value, T>::type + template struct Vs2013Aligned { }; // default, unsupported alignment + template struct Vs2013Aligned<1, T> { typedef __declspec(align(1)) T type; }; + template struct Vs2013Aligned<2, T> { typedef __declspec(align(2)) T type; }; + template struct Vs2013Aligned<4, T> { typedef __declspec(align(4)) T type; }; + template struct Vs2013Aligned<8, T> { typedef __declspec(align(8)) T type; }; + template struct Vs2013Aligned<16, T> { typedef __declspec(align(16)) T type; }; + template struct Vs2013Aligned<32, T> { typedef __declspec(align(32)) T type; }; + template struct Vs2013Aligned<64, T> { typedef __declspec(align(64)) T type; }; + template struct Vs2013Aligned<128, T> { typedef __declspec(align(128)) T type; }; + template struct Vs2013Aligned<256, T> { typedef __declspec(align(256)) T type; }; +#else + template struct identity { typedef T type; }; +#define MOODYCAMEL_ALIGNAS(alignment) alignas(alignment) +#define MOODYCAMEL_ALIGNOF(obj) alignof(obj) +#define MOODYCAMEL_ALIGNED_TYPE_LIKE(T, obj) alignas(alignof(obj)) typename details::identity::type +#endif +#endif +} } + + +// TSAN can false report races in lock-free code. To enable TSAN to be used from projects that use this one, +// we can apply per-function compile-time suppression. +// See https://clang.llvm.org/docs/ThreadSanitizer.html#has-feature-thread-sanitizer +#define MOODYCAMEL_NO_TSAN +#if defined(__has_feature) + #if __has_feature(thread_sanitizer) + #undef MOODYCAMEL_NO_TSAN + #define MOODYCAMEL_NO_TSAN __attribute__((no_sanitize("thread"))) + #endif // TSAN +#endif // TSAN + +// Compiler-specific likely/unlikely hints +namespace moodycamel { namespace details { +#if defined(__GNUC__) + static inline bool (likely)(bool x) { return __builtin_expect((x), true); } + static inline bool (unlikely)(bool x) { return __builtin_expect((x), false); } +#else + static inline bool (likely)(bool x) { return x; } + static inline bool (unlikely)(bool x) { return x; } +#endif +} } + +#ifdef MOODYCAMEL_QUEUE_INTERNAL_DEBUG +#include "internal/concurrentqueue_internal_debug.h" +#endif + +namespace moodycamel { +namespace details { + template + struct const_numeric_max { + static_assert(std::is_integral::value, "const_numeric_max can only be used with integers"); + static const T value = std::numeric_limits::is_signed + ? (static_cast(1) << (sizeof(T) * CHAR_BIT - 1)) - static_cast(1) + : static_cast(-1); + }; + +#if defined(__GLIBCXX__) + typedef ::max_align_t std_max_align_t; // libstdc++ forgot to add it to std:: for a while +#else + typedef std::max_align_t std_max_align_t; // Others (e.g. MSVC) insist it can *only* be accessed via std:: +#endif + + // Some platforms have incorrectly set max_align_t to a type with <8 bytes alignment even while supporting + // 8-byte aligned scalar values (*cough* 32-bit iOS). Work around this with our own union. See issue #64. + typedef union { + std_max_align_t x; + long long y; + void* z; + } max_align_t; +} + +// Default traits for the ConcurrentQueue. To change some of the +// traits without re-implementing all of them, inherit from this +// struct and shadow the declarations you wish to be different; +// since the traits are used as a template type parameter, the +// shadowed declarations will be used where defined, and the defaults +// otherwise. +struct ConcurrentQueueDefaultTraits +{ + // General-purpose size type. std::size_t is strongly recommended. + typedef std::size_t size_t; + + // The type used for the enqueue and dequeue indices. Must be at least as + // large as size_t. Should be significantly larger than the number of elements + // you expect to hold at once, especially if you have a high turnover rate; + // for example, on 32-bit x86, if you expect to have over a hundred million + // elements or pump several million elements through your queue in a very + // short space of time, using a 32-bit type *may* trigger a race condition. + // A 64-bit int type is recommended in that case, and in practice will + // prevent a race condition no matter the usage of the queue. Note that + // whether the queue is lock-free with a 64-int type depends on the whether + // std::atomic is lock-free, which is platform-specific. + typedef std::size_t index_t; + + // Internally, all elements are enqueued and dequeued from multi-element + // blocks; this is the smallest controllable unit. If you expect few elements + // but many producers, a smaller block size should be favoured. For few producers + // and/or many elements, a larger block size is preferred. A sane default + // is provided. Must be a power of 2. + static const size_t BLOCK_SIZE = 32; + + // For explicit producers (i.e. when using a producer token), the block is + // checked for being empty by iterating through a list of flags, one per element. + // For large block sizes, this is too inefficient, and switching to an atomic + // counter-based approach is faster. The switch is made for block sizes strictly + // larger than this threshold. + static const size_t EXPLICIT_BLOCK_EMPTY_COUNTER_THRESHOLD = 32; + + // How many full blocks can be expected for a single explicit producer? This should + // reflect that number's maximum for optimal performance. Must be a power of 2. + static const size_t EXPLICIT_INITIAL_INDEX_SIZE = 32; + + // How many full blocks can be expected for a single implicit producer? This should + // reflect that number's maximum for optimal performance. Must be a power of 2. + static const size_t IMPLICIT_INITIAL_INDEX_SIZE = 32; + + // The initial size of the hash table mapping thread IDs to implicit producers. + // Note that the hash is resized every time it becomes half full. + // Must be a power of two, and either 0 or at least 1. If 0, implicit production + // (using the enqueue methods without an explicit producer token) is disabled. + static const size_t INITIAL_IMPLICIT_PRODUCER_HASH_SIZE = 32; + + // Controls the number of items that an explicit consumer (i.e. one with a token) + // must consume before it causes all consumers to rotate and move on to the next + // internal queue. + static const std::uint32_t EXPLICIT_CONSUMER_CONSUMPTION_QUOTA_BEFORE_ROTATE = 256; + + // The maximum number of elements (inclusive) that can be enqueued to a sub-queue. + // Enqueue operations that would cause this limit to be surpassed will fail. Note + // that this limit is enforced at the block level (for performance reasons), i.e. + // it's rounded up to the nearest block size. + static const size_t MAX_SUBQUEUE_SIZE = details::const_numeric_max::value; + + // The number of times to spin before sleeping when waiting on a semaphore. + // Recommended values are on the order of 1000-10000 unless the number of + // consumer threads exceeds the number of idle cores (in which case try 0-100). + // Only affects instances of the BlockingConcurrentQueue. + static const int MAX_SEMA_SPINS = 10000; + + +#ifndef MCDBGQ_USE_RELACY + // Memory allocation can be customized if needed. + // malloc should return nullptr on failure, and handle alignment like std::malloc. +#if defined(malloc) || defined(free) + // Gah, this is 2015, stop defining macros that break standard code already! + // Work around malloc/free being special macros: + static inline void* WORKAROUND_malloc(size_t size) { return malloc(size); } + static inline void WORKAROUND_free(void* ptr) { return free(ptr); } + static inline void* (malloc)(size_t size) { return WORKAROUND_malloc(size); } + static inline void (free)(void* ptr) { return WORKAROUND_free(ptr); } +#else + static inline void* malloc(size_t size) { return std::malloc(size); } + static inline void free(void* ptr) { return std::free(ptr); } +#endif +#else + // Debug versions when running under the Relacy race detector (ignore + // these in user code) + static inline void* malloc(size_t size) { return rl::rl_malloc(size, $); } + static inline void free(void* ptr) { return rl::rl_free(ptr, $); } +#endif +}; + + +// When producing or consuming many elements, the most efficient way is to: +// 1) Use one of the bulk-operation methods of the queue with a token +// 2) Failing that, use the bulk-operation methods without a token +// 3) Failing that, create a token and use that with the single-item methods +// 4) Failing that, use the single-parameter methods of the queue +// Having said that, don't create tokens willy-nilly -- ideally there should be +// a maximum of one token per thread (of each kind). +struct ProducerToken; +struct ConsumerToken; + +template class ConcurrentQueue; +template class BlockingConcurrentQueue; +class ConcurrentQueueTests; + + +namespace details +{ + struct ConcurrentQueueProducerTypelessBase + { + ConcurrentQueueProducerTypelessBase* next; + std::atomic inactive; + ProducerToken* token; + + ConcurrentQueueProducerTypelessBase() + : next(nullptr), inactive(false), token(nullptr) + { + } + }; + + template struct _hash_32_or_64 { + static inline std::uint32_t hash(std::uint32_t h) + { + // MurmurHash3 finalizer -- see https://code.google.com/p/smhasher/source/browse/trunk/MurmurHash3.cpp + // Since the thread ID is already unique, all we really want to do is propagate that + // uniqueness evenly across all the bits, so that we can use a subset of the bits while + // reducing collisions significantly + h ^= h >> 16; + h *= 0x85ebca6b; + h ^= h >> 13; + h *= 0xc2b2ae35; + return h ^ (h >> 16); + } + }; + template<> struct _hash_32_or_64<1> { + static inline std::uint64_t hash(std::uint64_t h) + { + h ^= h >> 33; + h *= 0xff51afd7ed558ccd; + h ^= h >> 33; + h *= 0xc4ceb9fe1a85ec53; + return h ^ (h >> 33); + } + }; + template struct hash_32_or_64 : public _hash_32_or_64<(size > 4)> { }; + + static inline size_t hash_thread_id(thread_id_t id) + { + static_assert(sizeof(thread_id_t) <= 8, "Expected a platform where thread IDs are at most 64-bit values"); + return static_cast(hash_32_or_64::thread_id_hash_t)>::hash( + thread_id_converter::prehash(id))); + } + + template + static inline bool circular_less_than(T a, T b) + { +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable: 4554) +#endif + static_assert(std::is_integral::value && !std::numeric_limits::is_signed, "circular_less_than is intended to be used only with unsigned integer types"); + return static_cast(a - b) > static_cast(static_cast(1) << static_cast(sizeof(T) * CHAR_BIT - 1)); +#ifdef _MSC_VER +#pragma warning(pop) +#endif + } + + template + static inline char* align_for(char* ptr) + { + const std::size_t alignment = std::alignment_of::value; + return ptr + (alignment - (reinterpret_cast(ptr) % alignment)) % alignment; + } + + template + static inline T ceil_to_pow_2(T x) + { + static_assert(std::is_integral::value && !std::numeric_limits::is_signed, "ceil_to_pow_2 is intended to be used only with unsigned integer types"); + + // Adapted from http://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2 + --x; + x |= x >> 1; + x |= x >> 2; + x |= x >> 4; + for (std::size_t i = 1; i < sizeof(T); i <<= 1) { + x |= x >> (i << 3); + } + ++x; + return x; + } + + template + static inline void swap_relaxed(std::atomic& left, std::atomic& right) + { + T temp = std::move(left.load(std::memory_order_relaxed)); + left.store(std::move(right.load(std::memory_order_relaxed)), std::memory_order_relaxed); + right.store(std::move(temp), std::memory_order_relaxed); + } + + template + static inline T const& nomove(T const& x) + { + return x; + } + + template + struct nomove_if + { + template + static inline T const& eval(T const& x) + { + return x; + } + }; + + template<> + struct nomove_if + { + template + static inline auto eval(U&& x) + -> decltype(std::forward(x)) + { + return std::forward(x); + } + }; + + template + static inline auto deref_noexcept(It& it) MOODYCAMEL_NOEXCEPT -> decltype(*it) + { + return *it; + } + +#if defined(__clang__) || !defined(__GNUC__) || __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8) + template struct is_trivially_destructible : std::is_trivially_destructible { }; +#else + template struct is_trivially_destructible : std::has_trivial_destructor { }; +#endif + +#ifdef MOODYCAMEL_CPP11_THREAD_LOCAL_SUPPORTED +#ifdef MCDBGQ_USE_RELACY + typedef RelacyThreadExitListener ThreadExitListener; + typedef RelacyThreadExitNotifier ThreadExitNotifier; +#else + struct ThreadExitListener + { + typedef void (*callback_t)(void*); + callback_t callback; + void* userData; + + ThreadExitListener* next; // reserved for use by the ThreadExitNotifier + }; + + + class ThreadExitNotifier + { + public: + static void subscribe(ThreadExitListener* listener) + { + auto& tlsInst = instance(); + listener->next = tlsInst.tail; + tlsInst.tail = listener; + } + + static void unsubscribe(ThreadExitListener* listener) + { + auto& tlsInst = instance(); + ThreadExitListener** prev = &tlsInst.tail; + for (auto ptr = tlsInst.tail; ptr != nullptr; ptr = ptr->next) { + if (ptr == listener) { + *prev = ptr->next; + break; + } + prev = &ptr->next; + } + } + + private: + ThreadExitNotifier() : tail(nullptr) { } + ThreadExitNotifier(ThreadExitNotifier const&) MOODYCAMEL_DELETE_FUNCTION; + ThreadExitNotifier& operator=(ThreadExitNotifier const&) MOODYCAMEL_DELETE_FUNCTION; + + ~ThreadExitNotifier() + { + // This thread is about to exit, let everyone know! + assert(this == &instance() && "If this assert fails, you likely have a buggy compiler! Change the preprocessor conditions such that MOODYCAMEL_CPP11_THREAD_LOCAL_SUPPORTED is no longer defined."); + for (auto ptr = tail; ptr != nullptr; ptr = ptr->next) { + ptr->callback(ptr->userData); + } + } + + // Thread-local + static inline ThreadExitNotifier& instance() + { + static thread_local ThreadExitNotifier notifier; + return notifier; + } + + private: + ThreadExitListener* tail; + }; +#endif +#endif + + template struct static_is_lock_free_num { enum { value = 0 }; }; + template<> struct static_is_lock_free_num { enum { value = ATOMIC_CHAR_LOCK_FREE }; }; + template<> struct static_is_lock_free_num { enum { value = ATOMIC_SHORT_LOCK_FREE }; }; + template<> struct static_is_lock_free_num { enum { value = ATOMIC_INT_LOCK_FREE }; }; + template<> struct static_is_lock_free_num { enum { value = ATOMIC_LONG_LOCK_FREE }; }; + template<> struct static_is_lock_free_num { enum { value = ATOMIC_LLONG_LOCK_FREE }; }; + template struct static_is_lock_free : static_is_lock_free_num::type> { }; + template<> struct static_is_lock_free { enum { value = ATOMIC_BOOL_LOCK_FREE }; }; + template struct static_is_lock_free { enum { value = ATOMIC_POINTER_LOCK_FREE }; }; +} + + +struct ProducerToken +{ + template + explicit ProducerToken(ConcurrentQueue& queue); + + template + explicit ProducerToken(BlockingConcurrentQueue& queue); + + ProducerToken(ProducerToken&& other) MOODYCAMEL_NOEXCEPT + : producer(other.producer) + { + other.producer = nullptr; + if (producer != nullptr) { + producer->token = this; + } + } + + inline ProducerToken& operator=(ProducerToken&& other) MOODYCAMEL_NOEXCEPT + { + swap(other); + return *this; + } + + void swap(ProducerToken& other) MOODYCAMEL_NOEXCEPT + { + std::swap(producer, other.producer); + if (producer != nullptr) { + producer->token = this; + } + if (other.producer != nullptr) { + other.producer->token = &other; + } + } + + // A token is always valid unless: + // 1) Memory allocation failed during construction + // 2) It was moved via the move constructor + // (Note: assignment does a swap, leaving both potentially valid) + // 3) The associated queue was destroyed + // Note that if valid() returns true, that only indicates + // that the token is valid for use with a specific queue, + // but not which one; that's up to the user to track. + inline bool valid() const { return producer != nullptr; } + + ~ProducerToken() + { + if (producer != nullptr) { + producer->token = nullptr; + producer->inactive.store(true, std::memory_order_release); + } + } + + // Disable copying and assignment + ProducerToken(ProducerToken const&) MOODYCAMEL_DELETE_FUNCTION; + ProducerToken& operator=(ProducerToken const&) MOODYCAMEL_DELETE_FUNCTION; + +private: + template friend class ConcurrentQueue; + friend class ConcurrentQueueTests; + +protected: + details::ConcurrentQueueProducerTypelessBase* producer; +}; + + +struct ConsumerToken +{ + template + explicit ConsumerToken(ConcurrentQueue& q); + + template + explicit ConsumerToken(BlockingConcurrentQueue& q); + + ConsumerToken(ConsumerToken&& other) MOODYCAMEL_NOEXCEPT + : initialOffset(other.initialOffset), lastKnownGlobalOffset(other.lastKnownGlobalOffset), itemsConsumedFromCurrent(other.itemsConsumedFromCurrent), currentProducer(other.currentProducer), desiredProducer(other.desiredProducer) + { + } + + inline ConsumerToken& operator=(ConsumerToken&& other) MOODYCAMEL_NOEXCEPT + { + swap(other); + return *this; + } + + void swap(ConsumerToken& other) MOODYCAMEL_NOEXCEPT + { + std::swap(initialOffset, other.initialOffset); + std::swap(lastKnownGlobalOffset, other.lastKnownGlobalOffset); + std::swap(itemsConsumedFromCurrent, other.itemsConsumedFromCurrent); + std::swap(currentProducer, other.currentProducer); + std::swap(desiredProducer, other.desiredProducer); + } + + // Disable copying and assignment + ConsumerToken(ConsumerToken const&) MOODYCAMEL_DELETE_FUNCTION; + ConsumerToken& operator=(ConsumerToken const&) MOODYCAMEL_DELETE_FUNCTION; + +private: + template friend class ConcurrentQueue; + friend class ConcurrentQueueTests; + +private: // but shared with ConcurrentQueue + std::uint32_t initialOffset; + std::uint32_t lastKnownGlobalOffset; + std::uint32_t itemsConsumedFromCurrent; + details::ConcurrentQueueProducerTypelessBase* currentProducer; + details::ConcurrentQueueProducerTypelessBase* desiredProducer; +}; + +// Need to forward-declare this swap because it's in a namespace. +// See http://stackoverflow.com/questions/4492062/why-does-a-c-friend-class-need-a-forward-declaration-only-in-other-namespaces +template +inline void swap(typename ConcurrentQueue::ImplicitProducerKVP& a, typename ConcurrentQueue::ImplicitProducerKVP& b) MOODYCAMEL_NOEXCEPT; + + +template +class ConcurrentQueue +{ +public: + typedef ::moodycamel::ProducerToken producer_token_t; + typedef ::moodycamel::ConsumerToken consumer_token_t; + + typedef typename Traits::index_t index_t; + typedef typename Traits::size_t size_t; + + static const size_t BLOCK_SIZE = static_cast(Traits::BLOCK_SIZE); + static const size_t EXPLICIT_BLOCK_EMPTY_COUNTER_THRESHOLD = static_cast(Traits::EXPLICIT_BLOCK_EMPTY_COUNTER_THRESHOLD); + static const size_t EXPLICIT_INITIAL_INDEX_SIZE = static_cast(Traits::EXPLICIT_INITIAL_INDEX_SIZE); + static const size_t IMPLICIT_INITIAL_INDEX_SIZE = static_cast(Traits::IMPLICIT_INITIAL_INDEX_SIZE); + static const size_t INITIAL_IMPLICIT_PRODUCER_HASH_SIZE = static_cast(Traits::INITIAL_IMPLICIT_PRODUCER_HASH_SIZE); + static const std::uint32_t EXPLICIT_CONSUMER_CONSUMPTION_QUOTA_BEFORE_ROTATE = static_cast(Traits::EXPLICIT_CONSUMER_CONSUMPTION_QUOTA_BEFORE_ROTATE); +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable: 4307) // + integral constant overflow (that's what the ternary expression is for!) +#pragma warning(disable: 4309) // static_cast: Truncation of constant value +#endif + static const size_t MAX_SUBQUEUE_SIZE = (details::const_numeric_max::value - static_cast(Traits::MAX_SUBQUEUE_SIZE) < BLOCK_SIZE) ? details::const_numeric_max::value : ((static_cast(Traits::MAX_SUBQUEUE_SIZE) + (BLOCK_SIZE - 1)) / BLOCK_SIZE * BLOCK_SIZE); +#ifdef _MSC_VER +#pragma warning(pop) +#endif + + static_assert(!std::numeric_limits::is_signed && std::is_integral::value, "Traits::size_t must be an unsigned integral type"); + static_assert(!std::numeric_limits::is_signed && std::is_integral::value, "Traits::index_t must be an unsigned integral type"); + static_assert(sizeof(index_t) >= sizeof(size_t), "Traits::index_t must be at least as wide as Traits::size_t"); + static_assert((BLOCK_SIZE > 1) && !(BLOCK_SIZE & (BLOCK_SIZE - 1)), "Traits::BLOCK_SIZE must be a power of 2 (and at least 2)"); + static_assert((EXPLICIT_BLOCK_EMPTY_COUNTER_THRESHOLD > 1) && !(EXPLICIT_BLOCK_EMPTY_COUNTER_THRESHOLD & (EXPLICIT_BLOCK_EMPTY_COUNTER_THRESHOLD - 1)), "Traits::EXPLICIT_BLOCK_EMPTY_COUNTER_THRESHOLD must be a power of 2 (and greater than 1)"); + static_assert((EXPLICIT_INITIAL_INDEX_SIZE > 1) && !(EXPLICIT_INITIAL_INDEX_SIZE & (EXPLICIT_INITIAL_INDEX_SIZE - 1)), "Traits::EXPLICIT_INITIAL_INDEX_SIZE must be a power of 2 (and greater than 1)"); + static_assert((IMPLICIT_INITIAL_INDEX_SIZE > 1) && !(IMPLICIT_INITIAL_INDEX_SIZE & (IMPLICIT_INITIAL_INDEX_SIZE - 1)), "Traits::IMPLICIT_INITIAL_INDEX_SIZE must be a power of 2 (and greater than 1)"); + static_assert((INITIAL_IMPLICIT_PRODUCER_HASH_SIZE == 0) || !(INITIAL_IMPLICIT_PRODUCER_HASH_SIZE & (INITIAL_IMPLICIT_PRODUCER_HASH_SIZE - 1)), "Traits::INITIAL_IMPLICIT_PRODUCER_HASH_SIZE must be a power of 2"); + static_assert(INITIAL_IMPLICIT_PRODUCER_HASH_SIZE == 0 || INITIAL_IMPLICIT_PRODUCER_HASH_SIZE >= 1, "Traits::INITIAL_IMPLICIT_PRODUCER_HASH_SIZE must be at least 1 (or 0 to disable implicit enqueueing)"); + +public: + // Creates a queue with at least `capacity` element slots; note that the + // actual number of elements that can be inserted without additional memory + // allocation depends on the number of producers and the block size (e.g. if + // the block size is equal to `capacity`, only a single block will be allocated + // up-front, which means only a single producer will be able to enqueue elements + // without an extra allocation -- blocks aren't shared between producers). + // This method is not thread safe -- it is up to the user to ensure that the + // queue is fully constructed before it starts being used by other threads (this + // includes making the memory effects of construction visible, possibly with a + // memory barrier). + explicit ConcurrentQueue(size_t capacity = 6 * BLOCK_SIZE) + : producerListTail(nullptr), + producerCount(0), + initialBlockPoolIndex(0), + nextExplicitConsumerId(0), + globalExplicitConsumerOffset(0) + { + implicitProducerHashResizeInProgress.clear(std::memory_order_relaxed); + populate_initial_implicit_producer_hash(); + populate_initial_block_list(capacity / BLOCK_SIZE + ((capacity & (BLOCK_SIZE - 1)) == 0 ? 0 : 1)); + +#ifdef MOODYCAMEL_QUEUE_INTERNAL_DEBUG + // Track all the producers using a fully-resolved typed list for + // each kind; this makes it possible to debug them starting from + // the root queue object (otherwise wacky casts are needed that + // don't compile in the debugger's expression evaluator). + explicitProducers.store(nullptr, std::memory_order_relaxed); + implicitProducers.store(nullptr, std::memory_order_relaxed); +#endif + } + + // Computes the correct amount of pre-allocated blocks for you based + // on the minimum number of elements you want available at any given + // time, and the maximum concurrent number of each type of producer. + ConcurrentQueue(size_t minCapacity, size_t maxExplicitProducers, size_t maxImplicitProducers) + : producerListTail(nullptr), + producerCount(0), + initialBlockPoolIndex(0), + nextExplicitConsumerId(0), + globalExplicitConsumerOffset(0) + { + implicitProducerHashResizeInProgress.clear(std::memory_order_relaxed); + populate_initial_implicit_producer_hash(); + size_t blocks = (((minCapacity + BLOCK_SIZE - 1) / BLOCK_SIZE) - 1) * (maxExplicitProducers + 1) + 2 * (maxExplicitProducers + maxImplicitProducers); + populate_initial_block_list(blocks); + +#ifdef MOODYCAMEL_QUEUE_INTERNAL_DEBUG + explicitProducers.store(nullptr, std::memory_order_relaxed); + implicitProducers.store(nullptr, std::memory_order_relaxed); +#endif + } + + // Note: The queue should not be accessed concurrently while it's + // being deleted. It's up to the user to synchronize this. + // This method is not thread safe. + ~ConcurrentQueue() + { + // Destroy producers + auto ptr = producerListTail.load(std::memory_order_relaxed); + while (ptr != nullptr) { + auto next = ptr->next_prod(); + if (ptr->token != nullptr) { + ptr->token->producer = nullptr; + } + destroy(ptr); + ptr = next; + } + + // Destroy implicit producer hash tables + MOODYCAMEL_CONSTEXPR_IF (INITIAL_IMPLICIT_PRODUCER_HASH_SIZE != 0) { + auto hash = implicitProducerHash.load(std::memory_order_relaxed); + while (hash != nullptr) { + auto prev = hash->prev; + if (prev != nullptr) { // The last hash is part of this object and was not allocated dynamically + for (size_t i = 0; i != hash->capacity; ++i) { + hash->entries[i].~ImplicitProducerKVP(); + } + hash->~ImplicitProducerHash(); + (Traits::free)(hash); + } + hash = prev; + } + } + + // Destroy global free list + auto block = freeList.head_unsafe(); + while (block != nullptr) { + auto next = block->freeListNext.load(std::memory_order_relaxed); + if (block->dynamicallyAllocated) { + destroy(block); + } + block = next; + } + + // Destroy initial free list + destroy_array(initialBlockPool, initialBlockPoolSize); + } + + // Disable copying and copy assignment + ConcurrentQueue(ConcurrentQueue const&) MOODYCAMEL_DELETE_FUNCTION; + ConcurrentQueue& operator=(ConcurrentQueue const&) MOODYCAMEL_DELETE_FUNCTION; + + // Moving is supported, but note that it is *not* a thread-safe operation. + // Nobody can use the queue while it's being moved, and the memory effects + // of that move must be propagated to other threads before they can use it. + // Note: When a queue is moved, its tokens are still valid but can only be + // used with the destination queue (i.e. semantically they are moved along + // with the queue itself). + ConcurrentQueue(ConcurrentQueue&& other) MOODYCAMEL_NOEXCEPT + : producerListTail(other.producerListTail.load(std::memory_order_relaxed)), + producerCount(other.producerCount.load(std::memory_order_relaxed)), + initialBlockPoolIndex(other.initialBlockPoolIndex.load(std::memory_order_relaxed)), + initialBlockPool(other.initialBlockPool), + initialBlockPoolSize(other.initialBlockPoolSize), + freeList(std::move(other.freeList)), + nextExplicitConsumerId(other.nextExplicitConsumerId.load(std::memory_order_relaxed)), + globalExplicitConsumerOffset(other.globalExplicitConsumerOffset.load(std::memory_order_relaxed)) + { + // Move the other one into this, and leave the other one as an empty queue + implicitProducerHashResizeInProgress.clear(std::memory_order_relaxed); + populate_initial_implicit_producer_hash(); + swap_implicit_producer_hashes(other); + + other.producerListTail.store(nullptr, std::memory_order_relaxed); + other.producerCount.store(0, std::memory_order_relaxed); + other.nextExplicitConsumerId.store(0, std::memory_order_relaxed); + other.globalExplicitConsumerOffset.store(0, std::memory_order_relaxed); + +#ifdef MOODYCAMEL_QUEUE_INTERNAL_DEBUG + explicitProducers.store(other.explicitProducers.load(std::memory_order_relaxed), std::memory_order_relaxed); + other.explicitProducers.store(nullptr, std::memory_order_relaxed); + implicitProducers.store(other.implicitProducers.load(std::memory_order_relaxed), std::memory_order_relaxed); + other.implicitProducers.store(nullptr, std::memory_order_relaxed); +#endif + + other.initialBlockPoolIndex.store(0, std::memory_order_relaxed); + other.initialBlockPoolSize = 0; + other.initialBlockPool = nullptr; + + reown_producers(); + } + + inline ConcurrentQueue& operator=(ConcurrentQueue&& other) MOODYCAMEL_NOEXCEPT + { + return swap_internal(other); + } + + // Swaps this queue's state with the other's. Not thread-safe. + // Swapping two queues does not invalidate their tokens, however + // the tokens that were created for one queue must be used with + // only the swapped queue (i.e. the tokens are tied to the + // queue's movable state, not the object itself). + inline void swap(ConcurrentQueue& other) MOODYCAMEL_NOEXCEPT + { + swap_internal(other); + } + +private: + ConcurrentQueue& swap_internal(ConcurrentQueue& other) + { + if (this == &other) { + return *this; + } + + details::swap_relaxed(producerListTail, other.producerListTail); + details::swap_relaxed(producerCount, other.producerCount); + details::swap_relaxed(initialBlockPoolIndex, other.initialBlockPoolIndex); + std::swap(initialBlockPool, other.initialBlockPool); + std::swap(initialBlockPoolSize, other.initialBlockPoolSize); + freeList.swap(other.freeList); + details::swap_relaxed(nextExplicitConsumerId, other.nextExplicitConsumerId); + details::swap_relaxed(globalExplicitConsumerOffset, other.globalExplicitConsumerOffset); + + swap_implicit_producer_hashes(other); + + reown_producers(); + other.reown_producers(); + +#ifdef MOODYCAMEL_QUEUE_INTERNAL_DEBUG + details::swap_relaxed(explicitProducers, other.explicitProducers); + details::swap_relaxed(implicitProducers, other.implicitProducers); +#endif + + return *this; + } + +public: + // Enqueues a single item (by copying it). + // Allocates memory if required. Only fails if memory allocation fails (or implicit + // production is disabled because Traits::INITIAL_IMPLICIT_PRODUCER_HASH_SIZE is 0, + // or Traits::MAX_SUBQUEUE_SIZE has been defined and would be surpassed). + // Thread-safe. + inline bool enqueue(T const& item) + { + MOODYCAMEL_CONSTEXPR_IF (INITIAL_IMPLICIT_PRODUCER_HASH_SIZE == 0) return false; + else return inner_enqueue(item); + } + + // Enqueues a single item (by moving it, if possible). + // Allocates memory if required. Only fails if memory allocation fails (or implicit + // production is disabled because Traits::INITIAL_IMPLICIT_PRODUCER_HASH_SIZE is 0, + // or Traits::MAX_SUBQUEUE_SIZE has been defined and would be surpassed). + // Thread-safe. + inline bool enqueue(T&& item) + { + MOODYCAMEL_CONSTEXPR_IF (INITIAL_IMPLICIT_PRODUCER_HASH_SIZE == 0) return false; + else return inner_enqueue(std::move(item)); + } + + // Enqueues a single item (by copying it) using an explicit producer token. + // Allocates memory if required. Only fails if memory allocation fails (or + // Traits::MAX_SUBQUEUE_SIZE has been defined and would be surpassed). + // Thread-safe. + inline bool enqueue(producer_token_t const& token, T const& item) + { + return inner_enqueue(token, item); + } + + // Enqueues a single item (by moving it, if possible) using an explicit producer token. + // Allocates memory if required. Only fails if memory allocation fails (or + // Traits::MAX_SUBQUEUE_SIZE has been defined and would be surpassed). + // Thread-safe. + inline bool enqueue(producer_token_t const& token, T&& item) + { + return inner_enqueue(token, std::move(item)); + } + + // Enqueues several items. + // Allocates memory if required. Only fails if memory allocation fails (or + // implicit production is disabled because Traits::INITIAL_IMPLICIT_PRODUCER_HASH_SIZE + // is 0, or Traits::MAX_SUBQUEUE_SIZE has been defined and would be surpassed). + // Note: Use std::make_move_iterator if the elements should be moved instead of copied. + // Thread-safe. + template + bool enqueue_bulk(It itemFirst, size_t count) + { + MOODYCAMEL_CONSTEXPR_IF (INITIAL_IMPLICIT_PRODUCER_HASH_SIZE == 0) return false; + else return inner_enqueue_bulk(itemFirst, count); + } + + // Enqueues several items using an explicit producer token. + // Allocates memory if required. Only fails if memory allocation fails + // (or Traits::MAX_SUBQUEUE_SIZE has been defined and would be surpassed). + // Note: Use std::make_move_iterator if the elements should be moved + // instead of copied. + // Thread-safe. + template + bool enqueue_bulk(producer_token_t const& token, It itemFirst, size_t count) + { + return inner_enqueue_bulk(token, itemFirst, count); + } + + // Enqueues a single item (by copying it). + // Does not allocate memory. Fails if not enough room to enqueue (or implicit + // production is disabled because Traits::INITIAL_IMPLICIT_PRODUCER_HASH_SIZE + // is 0). + // Thread-safe. + inline bool try_enqueue(T const& item) + { + MOODYCAMEL_CONSTEXPR_IF (INITIAL_IMPLICIT_PRODUCER_HASH_SIZE == 0) return false; + else return inner_enqueue(item); + } + + // Enqueues a single item (by moving it, if possible). + // Does not allocate memory (except for one-time implicit producer). + // Fails if not enough room to enqueue (or implicit production is + // disabled because Traits::INITIAL_IMPLICIT_PRODUCER_HASH_SIZE is 0). + // Thread-safe. + inline bool try_enqueue(T&& item) + { + MOODYCAMEL_CONSTEXPR_IF (INITIAL_IMPLICIT_PRODUCER_HASH_SIZE == 0) return false; + else return inner_enqueue(std::move(item)); + } + + // Enqueues a single item (by copying it) using an explicit producer token. + // Does not allocate memory. Fails if not enough room to enqueue. + // Thread-safe. + inline bool try_enqueue(producer_token_t const& token, T const& item) + { + return inner_enqueue(token, item); + } + + // Enqueues a single item (by moving it, if possible) using an explicit producer token. + // Does not allocate memory. Fails if not enough room to enqueue. + // Thread-safe. + inline bool try_enqueue(producer_token_t const& token, T&& item) + { + return inner_enqueue(token, std::move(item)); + } + + // Enqueues several items. + // Does not allocate memory (except for one-time implicit producer). + // Fails if not enough room to enqueue (or implicit production is + // disabled because Traits::INITIAL_IMPLICIT_PRODUCER_HASH_SIZE is 0). + // Note: Use std::make_move_iterator if the elements should be moved + // instead of copied. + // Thread-safe. + template + bool try_enqueue_bulk(It itemFirst, size_t count) + { + MOODYCAMEL_CONSTEXPR_IF (INITIAL_IMPLICIT_PRODUCER_HASH_SIZE == 0) return false; + else return inner_enqueue_bulk(itemFirst, count); + } + + // Enqueues several items using an explicit producer token. + // Does not allocate memory. Fails if not enough room to enqueue. + // Note: Use std::make_move_iterator if the elements should be moved + // instead of copied. + // Thread-safe. + template + bool try_enqueue_bulk(producer_token_t const& token, It itemFirst, size_t count) + { + return inner_enqueue_bulk(token, itemFirst, count); + } + + + + // Attempts to dequeue from the queue. + // Returns false if all producer streams appeared empty at the time they + // were checked (so, the queue is likely but not guaranteed to be empty). + // Never allocates. Thread-safe. + template + bool try_dequeue(U& item) + { + // Instead of simply trying each producer in turn (which could cause needless contention on the first + // producer), we score them heuristically. + size_t nonEmptyCount = 0; + ProducerBase* best = nullptr; + size_t bestSize = 0; + for (auto ptr = producerListTail.load(std::memory_order_acquire); nonEmptyCount < 3 && ptr != nullptr; ptr = ptr->next_prod()) { + auto size = ptr->size_approx(); + if (size > 0) { + if (size > bestSize) { + bestSize = size; + best = ptr; + } + ++nonEmptyCount; + } + } + + // If there was at least one non-empty queue but it appears empty at the time + // we try to dequeue from it, we need to make sure every queue's been tried + if (nonEmptyCount > 0) { + if ((details::likely)(best->dequeue(item))) { + return true; + } + for (auto ptr = producerListTail.load(std::memory_order_acquire); ptr != nullptr; ptr = ptr->next_prod()) { + if (ptr != best && ptr->dequeue(item)) { + return true; + } + } + } + return false; + } + + // Attempts to dequeue from the queue. + // Returns false if all producer streams appeared empty at the time they + // were checked (so, the queue is likely but not guaranteed to be empty). + // This differs from the try_dequeue(item) method in that this one does + // not attempt to reduce contention by interleaving the order that producer + // streams are dequeued from. So, using this method can reduce overall throughput + // under contention, but will give more predictable results in single-threaded + // consumer scenarios. This is mostly only useful for internal unit tests. + // Never allocates. Thread-safe. + template + bool try_dequeue_non_interleaved(U& item) + { + for (auto ptr = producerListTail.load(std::memory_order_acquire); ptr != nullptr; ptr = ptr->next_prod()) { + if (ptr->dequeue(item)) { + return true; + } + } + return false; + } + + // Attempts to dequeue from the queue using an explicit consumer token. + // Returns false if all producer streams appeared empty at the time they + // were checked (so, the queue is likely but not guaranteed to be empty). + // Never allocates. Thread-safe. + template + bool try_dequeue(consumer_token_t& token, U& item) + { + // The idea is roughly as follows: + // Every 256 items from one producer, make everyone rotate (increase the global offset) -> this means the highest efficiency consumer dictates the rotation speed of everyone else, more or less + // If you see that the global offset has changed, you must reset your consumption counter and move to your designated place + // If there's no items where you're supposed to be, keep moving until you find a producer with some items + // If the global offset has not changed but you've run out of items to consume, move over from your current position until you find an producer with something in it + + if (token.desiredProducer == nullptr || token.lastKnownGlobalOffset != globalExplicitConsumerOffset.load(std::memory_order_relaxed)) { + if (!update_current_producer_after_rotation(token)) { + return false; + } + } + + // If there was at least one non-empty queue but it appears empty at the time + // we try to dequeue from it, we need to make sure every queue's been tried + if (static_cast(token.currentProducer)->dequeue(item)) { + if (++token.itemsConsumedFromCurrent == EXPLICIT_CONSUMER_CONSUMPTION_QUOTA_BEFORE_ROTATE) { + globalExplicitConsumerOffset.fetch_add(1, std::memory_order_relaxed); + } + return true; + } + + auto tail = producerListTail.load(std::memory_order_acquire); + auto ptr = static_cast(token.currentProducer)->next_prod(); + if (ptr == nullptr) { + ptr = tail; + } + while (ptr != static_cast(token.currentProducer)) { + if (ptr->dequeue(item)) { + token.currentProducer = ptr; + token.itemsConsumedFromCurrent = 1; + return true; + } + ptr = ptr->next_prod(); + if (ptr == nullptr) { + ptr = tail; + } + } + return false; + } + + // Attempts to dequeue several elements from the queue. + // Returns the number of items actually dequeued. + // Returns 0 if all producer streams appeared empty at the time they + // were checked (so, the queue is likely but not guaranteed to be empty). + // Never allocates. Thread-safe. + template + size_t try_dequeue_bulk(It itemFirst, size_t max) + { + size_t count = 0; + for (auto ptr = producerListTail.load(std::memory_order_acquire); ptr != nullptr; ptr = ptr->next_prod()) { + count += ptr->dequeue_bulk(itemFirst, max - count); + if (count == max) { + break; + } + } + return count; + } + + // Attempts to dequeue several elements from the queue using an explicit consumer token. + // Returns the number of items actually dequeued. + // Returns 0 if all producer streams appeared empty at the time they + // were checked (so, the queue is likely but not guaranteed to be empty). + // Never allocates. Thread-safe. + template + size_t try_dequeue_bulk(consumer_token_t& token, It itemFirst, size_t max) + { + if (token.desiredProducer == nullptr || token.lastKnownGlobalOffset != globalExplicitConsumerOffset.load(std::memory_order_relaxed)) { + if (!update_current_producer_after_rotation(token)) { + return 0; + } + } + + size_t count = static_cast(token.currentProducer)->dequeue_bulk(itemFirst, max); + if (count == max) { + if ((token.itemsConsumedFromCurrent += static_cast(max)) >= EXPLICIT_CONSUMER_CONSUMPTION_QUOTA_BEFORE_ROTATE) { + globalExplicitConsumerOffset.fetch_add(1, std::memory_order_relaxed); + } + return max; + } + token.itemsConsumedFromCurrent += static_cast(count); + max -= count; + + auto tail = producerListTail.load(std::memory_order_acquire); + auto ptr = static_cast(token.currentProducer)->next_prod(); + if (ptr == nullptr) { + ptr = tail; + } + while (ptr != static_cast(token.currentProducer)) { + auto dequeued = ptr->dequeue_bulk(itemFirst, max); + count += dequeued; + if (dequeued != 0) { + token.currentProducer = ptr; + token.itemsConsumedFromCurrent = static_cast(dequeued); + } + if (dequeued == max) { + break; + } + max -= dequeued; + ptr = ptr->next_prod(); + if (ptr == nullptr) { + ptr = tail; + } + } + return count; + } + + + + // Attempts to dequeue from a specific producer's inner queue. + // If you happen to know which producer you want to dequeue from, this + // is significantly faster than using the general-case try_dequeue methods. + // Returns false if the producer's queue appeared empty at the time it + // was checked (so, the queue is likely but not guaranteed to be empty). + // Never allocates. Thread-safe. + template + inline bool try_dequeue_from_producer(producer_token_t const& producer, U& item) + { + return static_cast(producer.producer)->dequeue(item); + } + + // Attempts to dequeue several elements from a specific producer's inner queue. + // Returns the number of items actually dequeued. + // If you happen to know which producer you want to dequeue from, this + // is significantly faster than using the general-case try_dequeue methods. + // Returns 0 if the producer's queue appeared empty at the time it + // was checked (so, the queue is likely but not guaranteed to be empty). + // Never allocates. Thread-safe. + template + inline size_t try_dequeue_bulk_from_producer(producer_token_t const& producer, It itemFirst, size_t max) + { + return static_cast(producer.producer)->dequeue_bulk(itemFirst, max); + } + + + // Returns an estimate of the total number of elements currently in the queue. This + // estimate is only accurate if the queue has completely stabilized before it is called + // (i.e. all enqueue and dequeue operations have completed and their memory effects are + // visible on the calling thread, and no further operations start while this method is + // being called). + // Thread-safe. + size_t size_approx() const + { + size_t size = 0; + for (auto ptr = producerListTail.load(std::memory_order_acquire); ptr != nullptr; ptr = ptr->next_prod()) { + size += ptr->size_approx(); + } + return size; + } + + + // Returns true if the underlying atomic variables used by + // the queue are lock-free (they should be on most platforms). + // Thread-safe. + static bool is_lock_free() + { + return + details::static_is_lock_free::value == 2 && + details::static_is_lock_free::value == 2 && + details::static_is_lock_free::value == 2 && + details::static_is_lock_free::value == 2 && + details::static_is_lock_free::value == 2 && + details::static_is_lock_free::thread_id_numeric_size_t>::value == 2; + } + + +private: + friend struct ProducerToken; + friend struct ConsumerToken; + struct ExplicitProducer; + friend struct ExplicitProducer; + struct ImplicitProducer; + friend struct ImplicitProducer; + friend class ConcurrentQueueTests; + + enum AllocationMode { CanAlloc, CannotAlloc }; + + + /////////////////////////////// + // Queue methods + /////////////////////////////// + + template + inline bool inner_enqueue(producer_token_t const& token, U&& element) + { + return static_cast(token.producer)->ConcurrentQueue::ExplicitProducer::template enqueue(std::forward(element)); + } + + template + inline bool inner_enqueue(U&& element) + { + auto producer = get_or_add_implicit_producer(); + return producer == nullptr ? false : producer->ConcurrentQueue::ImplicitProducer::template enqueue(std::forward(element)); + } + + template + inline bool inner_enqueue_bulk(producer_token_t const& token, It itemFirst, size_t count) + { + return static_cast(token.producer)->ConcurrentQueue::ExplicitProducer::template enqueue_bulk(itemFirst, count); + } + + template + inline bool inner_enqueue_bulk(It itemFirst, size_t count) + { + auto producer = get_or_add_implicit_producer(); + return producer == nullptr ? false : producer->ConcurrentQueue::ImplicitProducer::template enqueue_bulk(itemFirst, count); + } + + inline bool update_current_producer_after_rotation(consumer_token_t& token) + { + // Ah, there's been a rotation, figure out where we should be! + auto tail = producerListTail.load(std::memory_order_acquire); + if (token.desiredProducer == nullptr && tail == nullptr) { + return false; + } + auto prodCount = producerCount.load(std::memory_order_relaxed); + auto globalOffset = globalExplicitConsumerOffset.load(std::memory_order_relaxed); + if ((details::unlikely)(token.desiredProducer == nullptr)) { + // Aha, first time we're dequeueing anything. + // Figure out our local position + // Note: offset is from start, not end, but we're traversing from end -- subtract from count first + std::uint32_t offset = prodCount - 1 - (token.initialOffset % prodCount); + token.desiredProducer = tail; + for (std::uint32_t i = 0; i != offset; ++i) { + token.desiredProducer = static_cast(token.desiredProducer)->next_prod(); + if (token.desiredProducer == nullptr) { + token.desiredProducer = tail; + } + } + } + + std::uint32_t delta = globalOffset - token.lastKnownGlobalOffset; + if (delta >= prodCount) { + delta = delta % prodCount; + } + for (std::uint32_t i = 0; i != delta; ++i) { + token.desiredProducer = static_cast(token.desiredProducer)->next_prod(); + if (token.desiredProducer == nullptr) { + token.desiredProducer = tail; + } + } + + token.lastKnownGlobalOffset = globalOffset; + token.currentProducer = token.desiredProducer; + token.itemsConsumedFromCurrent = 0; + return true; + } + + + /////////////////////////// + // Free list + /////////////////////////// + + template + struct FreeListNode + { + FreeListNode() : freeListRefs(0), freeListNext(nullptr) { } + + std::atomic freeListRefs; + std::atomic freeListNext; + }; + + // A simple CAS-based lock-free free list. Not the fastest thing in the world under heavy contention, but + // simple and correct (assuming nodes are never freed until after the free list is destroyed), and fairly + // speedy under low contention. + template // N must inherit FreeListNode or have the same fields (and initialization of them) + struct FreeList + { + FreeList() : freeListHead(nullptr) { } + FreeList(FreeList&& other) : freeListHead(other.freeListHead.load(std::memory_order_relaxed)) { other.freeListHead.store(nullptr, std::memory_order_relaxed); } + void swap(FreeList& other) { details::swap_relaxed(freeListHead, other.freeListHead); } + + FreeList(FreeList const&) MOODYCAMEL_DELETE_FUNCTION; + FreeList& operator=(FreeList const&) MOODYCAMEL_DELETE_FUNCTION; + + inline void add(N* node) + { +#ifdef MCDBGQ_NOLOCKFREE_FREELIST + debug::DebugLock lock(mutex); +#endif + // We know that the should-be-on-freelist bit is 0 at this point, so it's safe to + // set it using a fetch_add + if (node->freeListRefs.fetch_add(SHOULD_BE_ON_FREELIST, std::memory_order_acq_rel) == 0) { + // Oh look! We were the last ones referencing this node, and we know + // we want to add it to the free list, so let's do it! + add_knowing_refcount_is_zero(node); + } + } + + inline N* try_get() + { +#ifdef MCDBGQ_NOLOCKFREE_FREELIST + debug::DebugLock lock(mutex); +#endif + auto head = freeListHead.load(std::memory_order_acquire); + while (head != nullptr) { + auto prevHead = head; + auto refs = head->freeListRefs.load(std::memory_order_relaxed); + if ((refs & REFS_MASK) == 0 || !head->freeListRefs.compare_exchange_strong(refs, refs + 1, std::memory_order_acquire, std::memory_order_relaxed)) { + head = freeListHead.load(std::memory_order_acquire); + continue; + } + + // Good, reference count has been incremented (it wasn't at zero), which means we can read the + // next and not worry about it changing between now and the time we do the CAS + auto next = head->freeListNext.load(std::memory_order_relaxed); + if (freeListHead.compare_exchange_strong(head, next, std::memory_order_acquire, std::memory_order_relaxed)) { + // Yay, got the node. This means it was on the list, which means shouldBeOnFreeList must be false no + // matter the refcount (because nobody else knows it's been taken off yet, it can't have been put back on). + assert((head->freeListRefs.load(std::memory_order_relaxed) & SHOULD_BE_ON_FREELIST) == 0); + + // Decrease refcount twice, once for our ref, and once for the list's ref + head->freeListRefs.fetch_sub(2, std::memory_order_release); + return head; + } + + // OK, the head must have changed on us, but we still need to decrease the refcount we increased. + // Note that we don't need to release any memory effects, but we do need to ensure that the reference + // count decrement happens-after the CAS on the head. + refs = prevHead->freeListRefs.fetch_sub(1, std::memory_order_acq_rel); + if (refs == SHOULD_BE_ON_FREELIST + 1) { + add_knowing_refcount_is_zero(prevHead); + } + } + + return nullptr; + } + + // Useful for traversing the list when there's no contention (e.g. to destroy remaining nodes) + N* head_unsafe() const { return freeListHead.load(std::memory_order_relaxed); } + + private: + inline void add_knowing_refcount_is_zero(N* node) + { + // Since the refcount is zero, and nobody can increase it once it's zero (except us, and we run + // only one copy of this method per node at a time, i.e. the single thread case), then we know + // we can safely change the next pointer of the node; however, once the refcount is back above + // zero, then other threads could increase it (happens under heavy contention, when the refcount + // goes to zero in between a load and a refcount increment of a node in try_get, then back up to + // something non-zero, then the refcount increment is done by the other thread) -- so, if the CAS + // to add the node to the actual list fails, decrease the refcount and leave the add operation to + // the next thread who puts the refcount back at zero (which could be us, hence the loop). + auto head = freeListHead.load(std::memory_order_relaxed); + while (true) { + node->freeListNext.store(head, std::memory_order_relaxed); + node->freeListRefs.store(1, std::memory_order_release); + if (!freeListHead.compare_exchange_strong(head, node, std::memory_order_release, std::memory_order_relaxed)) { + // Hmm, the add failed, but we can only try again when the refcount goes back to zero + if (node->freeListRefs.fetch_add(SHOULD_BE_ON_FREELIST - 1, std::memory_order_release) == 1) { + continue; + } + } + return; + } + } + + private: + // Implemented like a stack, but where node order doesn't matter (nodes are inserted out of order under contention) + std::atomic freeListHead; + + static const std::uint32_t REFS_MASK = 0x7FFFFFFF; + static const std::uint32_t SHOULD_BE_ON_FREELIST = 0x80000000; + +#ifdef MCDBGQ_NOLOCKFREE_FREELIST + debug::DebugMutex mutex; +#endif + }; + + + /////////////////////////// + // Block + /////////////////////////// + + enum InnerQueueContext { implicit_context = 0, explicit_context = 1 }; + + struct Block + { + Block() + : next(nullptr), elementsCompletelyDequeued(0), freeListRefs(0), freeListNext(nullptr), shouldBeOnFreeList(false), dynamicallyAllocated(true) + { +#ifdef MCDBGQ_TRACKMEM + owner = nullptr; +#endif + } + + template + inline bool is_empty() const + { + MOODYCAMEL_CONSTEXPR_IF (context == explicit_context && BLOCK_SIZE <= EXPLICIT_BLOCK_EMPTY_COUNTER_THRESHOLD) { + // Check flags + for (size_t i = 0; i < BLOCK_SIZE; ++i) { + if (!emptyFlags[i].load(std::memory_order_relaxed)) { + return false; + } + } + + // Aha, empty; make sure we have all other memory effects that happened before the empty flags were set + std::atomic_thread_fence(std::memory_order_acquire); + return true; + } + else { + // Check counter + if (elementsCompletelyDequeued.load(std::memory_order_relaxed) == BLOCK_SIZE) { + std::atomic_thread_fence(std::memory_order_acquire); + return true; + } + assert(elementsCompletelyDequeued.load(std::memory_order_relaxed) <= BLOCK_SIZE); + return false; + } + } + + // Returns true if the block is now empty (does not apply in explicit context) + template + inline bool set_empty(MOODYCAMEL_MAYBE_UNUSED index_t i) + { + MOODYCAMEL_CONSTEXPR_IF (context == explicit_context && BLOCK_SIZE <= EXPLICIT_BLOCK_EMPTY_COUNTER_THRESHOLD) { + // Set flag + assert(!emptyFlags[BLOCK_SIZE - 1 - static_cast(i & static_cast(BLOCK_SIZE - 1))].load(std::memory_order_relaxed)); + emptyFlags[BLOCK_SIZE - 1 - static_cast(i & static_cast(BLOCK_SIZE - 1))].store(true, std::memory_order_release); + return false; + } + else { + // Increment counter + auto prevVal = elementsCompletelyDequeued.fetch_add(1, std::memory_order_release); + assert(prevVal < BLOCK_SIZE); + return prevVal == BLOCK_SIZE - 1; + } + } + + // Sets multiple contiguous item statuses to 'empty' (assumes no wrapping and count > 0). + // Returns true if the block is now empty (does not apply in explicit context). + template + inline bool set_many_empty(MOODYCAMEL_MAYBE_UNUSED index_t i, size_t count) + { + MOODYCAMEL_CONSTEXPR_IF (context == explicit_context && BLOCK_SIZE <= EXPLICIT_BLOCK_EMPTY_COUNTER_THRESHOLD) { + // Set flags + std::atomic_thread_fence(std::memory_order_release); + i = BLOCK_SIZE - 1 - static_cast(i & static_cast(BLOCK_SIZE - 1)) - count + 1; + for (size_t j = 0; j != count; ++j) { + assert(!emptyFlags[i + j].load(std::memory_order_relaxed)); + emptyFlags[i + j].store(true, std::memory_order_relaxed); + } + return false; + } + else { + // Increment counter + auto prevVal = elementsCompletelyDequeued.fetch_add(count, std::memory_order_release); + assert(prevVal + count <= BLOCK_SIZE); + return prevVal + count == BLOCK_SIZE; + } + } + + template + inline void set_all_empty() + { + MOODYCAMEL_CONSTEXPR_IF (context == explicit_context && BLOCK_SIZE <= EXPLICIT_BLOCK_EMPTY_COUNTER_THRESHOLD) { + // Set all flags + for (size_t i = 0; i != BLOCK_SIZE; ++i) { + emptyFlags[i].store(true, std::memory_order_relaxed); + } + } + else { + // Reset counter + elementsCompletelyDequeued.store(BLOCK_SIZE, std::memory_order_relaxed); + } + } + + template + inline void reset_empty() + { + MOODYCAMEL_CONSTEXPR_IF (context == explicit_context && BLOCK_SIZE <= EXPLICIT_BLOCK_EMPTY_COUNTER_THRESHOLD) { + // Reset flags + for (size_t i = 0; i != BLOCK_SIZE; ++i) { + emptyFlags[i].store(false, std::memory_order_relaxed); + } + } + else { + // Reset counter + elementsCompletelyDequeued.store(0, std::memory_order_relaxed); + } + } + + inline T* operator[](index_t idx) MOODYCAMEL_NOEXCEPT { return static_cast(static_cast(elements)) + static_cast(idx & static_cast(BLOCK_SIZE - 1)); } + inline T const* operator[](index_t idx) const MOODYCAMEL_NOEXCEPT { return static_cast(static_cast(elements)) + static_cast(idx & static_cast(BLOCK_SIZE - 1)); } + + private: + static_assert(std::alignment_of::value <= sizeof(T), "The queue does not support types with an alignment greater than their size at this time"); + MOODYCAMEL_ALIGNED_TYPE_LIKE(char[sizeof(T) * BLOCK_SIZE], T) elements; + public: + Block* next; + std::atomic elementsCompletelyDequeued; + std::atomic emptyFlags[BLOCK_SIZE <= EXPLICIT_BLOCK_EMPTY_COUNTER_THRESHOLD ? BLOCK_SIZE : 1]; + public: + std::atomic freeListRefs; + std::atomic freeListNext; + std::atomic shouldBeOnFreeList; + bool dynamicallyAllocated; // Perhaps a better name for this would be 'isNotPartOfInitialBlockPool' + +#ifdef MCDBGQ_TRACKMEM + void* owner; +#endif + }; + static_assert(std::alignment_of::value >= std::alignment_of::value, "Internal error: Blocks must be at least as aligned as the type they are wrapping"); + + +#ifdef MCDBGQ_TRACKMEM +public: + struct MemStats; +private: +#endif + + /////////////////////////// + // Producer base + /////////////////////////// + + struct ProducerBase : public details::ConcurrentQueueProducerTypelessBase + { + ProducerBase(ConcurrentQueue* parent_, bool isExplicit_) : + tailIndex(0), + headIndex(0), + dequeueOptimisticCount(0), + dequeueOvercommit(0), + tailBlock(nullptr), + isExplicit(isExplicit_), + parent(parent_) + { + } + + virtual ~ProducerBase() { } + + template + inline bool dequeue(U& element) + { + if (isExplicit) { + return static_cast(this)->dequeue(element); + } + else { + return static_cast(this)->dequeue(element); + } + } + + template + inline size_t dequeue_bulk(It& itemFirst, size_t max) + { + if (isExplicit) { + return static_cast(this)->dequeue_bulk(itemFirst, max); + } + else { + return static_cast(this)->dequeue_bulk(itemFirst, max); + } + } + + inline ProducerBase* next_prod() const { return static_cast(next); } + + inline size_t size_approx() const + { + auto tail = tailIndex.load(std::memory_order_relaxed); + auto head = headIndex.load(std::memory_order_relaxed); + return details::circular_less_than(head, tail) ? static_cast(tail - head) : 0; + } + + inline index_t getTail() const { return tailIndex.load(std::memory_order_relaxed); } + protected: + std::atomic tailIndex; // Where to enqueue to next + std::atomic headIndex; // Where to dequeue from next + + std::atomic dequeueOptimisticCount; + std::atomic dequeueOvercommit; + + Block* tailBlock; + + public: + bool isExplicit; + ConcurrentQueue* parent; + + protected: +#ifdef MCDBGQ_TRACKMEM + friend struct MemStats; +#endif + }; + + + /////////////////////////// + // Explicit queue + /////////////////////////// + + struct ExplicitProducer : public ProducerBase + { + explicit ExplicitProducer(ConcurrentQueue* parent_) : + ProducerBase(parent_, true), + blockIndex(nullptr), + pr_blockIndexSlotsUsed(0), + pr_blockIndexSize(EXPLICIT_INITIAL_INDEX_SIZE >> 1), + pr_blockIndexFront(0), + pr_blockIndexEntries(nullptr), + pr_blockIndexRaw(nullptr) + { + size_t poolBasedIndexSize = details::ceil_to_pow_2(parent_->initialBlockPoolSize) >> 1; + if (poolBasedIndexSize > pr_blockIndexSize) { + pr_blockIndexSize = poolBasedIndexSize; + } + + new_block_index(0); // This creates an index with double the number of current entries, i.e. EXPLICIT_INITIAL_INDEX_SIZE + } + + ~ExplicitProducer() + { + // Destruct any elements not yet dequeued. + // Since we're in the destructor, we can assume all elements + // are either completely dequeued or completely not (no halfways). + if (this->tailBlock != nullptr) { // Note this means there must be a block index too + // First find the block that's partially dequeued, if any + Block* halfDequeuedBlock = nullptr; + if ((this->headIndex.load(std::memory_order_relaxed) & static_cast(BLOCK_SIZE - 1)) != 0) { + // The head's not on a block boundary, meaning a block somewhere is partially dequeued + // (or the head block is the tail block and was fully dequeued, but the head/tail are still not on a boundary) + size_t i = (pr_blockIndexFront - pr_blockIndexSlotsUsed) & (pr_blockIndexSize - 1); + while (details::circular_less_than(pr_blockIndexEntries[i].base + BLOCK_SIZE, this->headIndex.load(std::memory_order_relaxed))) { + i = (i + 1) & (pr_blockIndexSize - 1); + } + assert(details::circular_less_than(pr_blockIndexEntries[i].base, this->headIndex.load(std::memory_order_relaxed))); + halfDequeuedBlock = pr_blockIndexEntries[i].block; + } + + // Start at the head block (note the first line in the loop gives us the head from the tail on the first iteration) + auto block = this->tailBlock; + do { + block = block->next; + if (block->ConcurrentQueue::Block::template is_empty()) { + continue; + } + + size_t i = 0; // Offset into block + if (block == halfDequeuedBlock) { + i = static_cast(this->headIndex.load(std::memory_order_relaxed) & static_cast(BLOCK_SIZE - 1)); + } + + // Walk through all the items in the block; if this is the tail block, we need to stop when we reach the tail index + auto lastValidIndex = (this->tailIndex.load(std::memory_order_relaxed) & static_cast(BLOCK_SIZE - 1)) == 0 ? BLOCK_SIZE : static_cast(this->tailIndex.load(std::memory_order_relaxed) & static_cast(BLOCK_SIZE - 1)); + while (i != BLOCK_SIZE && (block != this->tailBlock || i != lastValidIndex)) { + (*block)[i++]->~T(); + } + } while (block != this->tailBlock); + } + + // Destroy all blocks that we own + if (this->tailBlock != nullptr) { + auto block = this->tailBlock; + do { + auto nextBlock = block->next; + if (block->dynamicallyAllocated) { + destroy(block); + } + else { + this->parent->add_block_to_free_list(block); + } + block = nextBlock; + } while (block != this->tailBlock); + } + + // Destroy the block indices + auto header = static_cast(pr_blockIndexRaw); + while (header != nullptr) { + auto prev = static_cast(header->prev); + header->~BlockIndexHeader(); + (Traits::free)(header); + header = prev; + } + } + + template + inline bool enqueue(U&& element) + { + index_t currentTailIndex = this->tailIndex.load(std::memory_order_relaxed); + index_t newTailIndex = 1 + currentTailIndex; + if ((currentTailIndex & static_cast(BLOCK_SIZE - 1)) == 0) { + // We reached the end of a block, start a new one + auto startBlock = this->tailBlock; + auto originalBlockIndexSlotsUsed = pr_blockIndexSlotsUsed; + if (this->tailBlock != nullptr && this->tailBlock->next->ConcurrentQueue::Block::template is_empty()) { + // We can re-use the block ahead of us, it's empty! + this->tailBlock = this->tailBlock->next; + this->tailBlock->ConcurrentQueue::Block::template reset_empty(); + + // We'll put the block on the block index (guaranteed to be room since we're conceptually removing the + // last block from it first -- except instead of removing then adding, we can just overwrite). + // Note that there must be a valid block index here, since even if allocation failed in the ctor, + // it would have been re-attempted when adding the first block to the queue; since there is such + // a block, a block index must have been successfully allocated. + } + else { + // Whatever head value we see here is >= the last value we saw here (relatively), + // and <= its current value. Since we have the most recent tail, the head must be + // <= to it. + auto head = this->headIndex.load(std::memory_order_relaxed); + assert(!details::circular_less_than(currentTailIndex, head)); + if (!details::circular_less_than(head, currentTailIndex + BLOCK_SIZE) + || (MAX_SUBQUEUE_SIZE != details::const_numeric_max::value && (MAX_SUBQUEUE_SIZE == 0 || MAX_SUBQUEUE_SIZE - BLOCK_SIZE < currentTailIndex - head))) { + // We can't enqueue in another block because there's not enough leeway -- the + // tail could surpass the head by the time the block fills up! (Or we'll exceed + // the size limit, if the second part of the condition was true.) + return false; + } + // We're going to need a new block; check that the block index has room + if (pr_blockIndexRaw == nullptr || pr_blockIndexSlotsUsed == pr_blockIndexSize) { + // Hmm, the circular block index is already full -- we'll need + // to allocate a new index. Note pr_blockIndexRaw can only be nullptr if + // the initial allocation failed in the constructor. + + MOODYCAMEL_CONSTEXPR_IF (allocMode == CannotAlloc) { + return false; + } + else if (!new_block_index(pr_blockIndexSlotsUsed)) { + return false; + } + } + + // Insert a new block in the circular linked list + auto newBlock = this->parent->ConcurrentQueue::template requisition_block(); + if (newBlock == nullptr) { + return false; + } +#ifdef MCDBGQ_TRACKMEM + newBlock->owner = this; +#endif + newBlock->ConcurrentQueue::Block::template reset_empty(); + if (this->tailBlock == nullptr) { + newBlock->next = newBlock; + } + else { + newBlock->next = this->tailBlock->next; + this->tailBlock->next = newBlock; + } + this->tailBlock = newBlock; + ++pr_blockIndexSlotsUsed; + } + + MOODYCAMEL_CONSTEXPR_IF (!MOODYCAMEL_NOEXCEPT_CTOR(T, U, new (static_cast(nullptr)) T(std::forward(element)))) { + // The constructor may throw. We want the element not to appear in the queue in + // that case (without corrupting the queue): + MOODYCAMEL_TRY { + new ((*this->tailBlock)[currentTailIndex]) T(std::forward(element)); + } + MOODYCAMEL_CATCH (...) { + // Revert change to the current block, but leave the new block available + // for next time + pr_blockIndexSlotsUsed = originalBlockIndexSlotsUsed; + this->tailBlock = startBlock == nullptr ? this->tailBlock : startBlock; + MOODYCAMEL_RETHROW; + } + } + else { + (void)startBlock; + (void)originalBlockIndexSlotsUsed; + } + + // Add block to block index + auto& entry = blockIndex.load(std::memory_order_relaxed)->entries[pr_blockIndexFront]; + entry.base = currentTailIndex; + entry.block = this->tailBlock; + blockIndex.load(std::memory_order_relaxed)->front.store(pr_blockIndexFront, std::memory_order_release); + pr_blockIndexFront = (pr_blockIndexFront + 1) & (pr_blockIndexSize - 1); + + MOODYCAMEL_CONSTEXPR_IF (!MOODYCAMEL_NOEXCEPT_CTOR(T, U, new (static_cast(nullptr)) T(std::forward(element)))) { + this->tailIndex.store(newTailIndex, std::memory_order_release); + return true; + } + } + + // Enqueue + new ((*this->tailBlock)[currentTailIndex]) T(std::forward(element)); + + this->tailIndex.store(newTailIndex, std::memory_order_release); + return true; + } + + template + bool dequeue(U& element) + { + auto tail = this->tailIndex.load(std::memory_order_relaxed); + auto overcommit = this->dequeueOvercommit.load(std::memory_order_relaxed); + if (details::circular_less_than(this->dequeueOptimisticCount.load(std::memory_order_relaxed) - overcommit, tail)) { + // Might be something to dequeue, let's give it a try + + // Note that this if is purely for performance purposes in the common case when the queue is + // empty and the values are eventually consistent -- we may enter here spuriously. + + // Note that whatever the values of overcommit and tail are, they are not going to change (unless we + // change them) and must be the same value at this point (inside the if) as when the if condition was + // evaluated. + + // We insert an acquire fence here to synchronize-with the release upon incrementing dequeueOvercommit below. + // This ensures that whatever the value we got loaded into overcommit, the load of dequeueOptisticCount in + // the fetch_add below will result in a value at least as recent as that (and therefore at least as large). + // Note that I believe a compiler (signal) fence here would be sufficient due to the nature of fetch_add (all + // read-modify-write operations are guaranteed to work on the latest value in the modification order), but + // unfortunately that can't be shown to be correct using only the C++11 standard. + // See http://stackoverflow.com/questions/18223161/what-are-the-c11-memory-ordering-guarantees-in-this-corner-case + std::atomic_thread_fence(std::memory_order_acquire); + + // Increment optimistic counter, then check if it went over the boundary + auto myDequeueCount = this->dequeueOptimisticCount.fetch_add(1, std::memory_order_relaxed); + + // Note that since dequeueOvercommit must be <= dequeueOptimisticCount (because dequeueOvercommit is only ever + // incremented after dequeueOptimisticCount -- this is enforced in the `else` block below), and since we now + // have a version of dequeueOptimisticCount that is at least as recent as overcommit (due to the release upon + // incrementing dequeueOvercommit and the acquire above that synchronizes with it), overcommit <= myDequeueCount. + // However, we can't assert this since both dequeueOptimisticCount and dequeueOvercommit may (independently) + // overflow; in such a case, though, the logic still holds since the difference between the two is maintained. + + // Note that we reload tail here in case it changed; it will be the same value as before or greater, since + // this load is sequenced after (happens after) the earlier load above. This is supported by read-read + // coherency (as defined in the standard), explained here: http://en.cppreference.com/w/cpp/atomic/memory_order + tail = this->tailIndex.load(std::memory_order_acquire); + if ((details::likely)(details::circular_less_than(myDequeueCount - overcommit, tail))) { + // Guaranteed to be at least one element to dequeue! + + // Get the index. Note that since there's guaranteed to be at least one element, this + // will never exceed tail. We need to do an acquire-release fence here since it's possible + // that whatever condition got us to this point was for an earlier enqueued element (that + // we already see the memory effects for), but that by the time we increment somebody else + // has incremented it, and we need to see the memory effects for *that* element, which is + // in such a case is necessarily visible on the thread that incremented it in the first + // place with the more current condition (they must have acquired a tail that is at least + // as recent). + auto index = this->headIndex.fetch_add(1, std::memory_order_acq_rel); + + + // Determine which block the element is in + + auto localBlockIndex = blockIndex.load(std::memory_order_acquire); + auto localBlockIndexHead = localBlockIndex->front.load(std::memory_order_acquire); + + // We need to be careful here about subtracting and dividing because of index wrap-around. + // When an index wraps, we need to preserve the sign of the offset when dividing it by the + // block size (in order to get a correct signed block count offset in all cases): + auto headBase = localBlockIndex->entries[localBlockIndexHead].base; + auto blockBaseIndex = index & ~static_cast(BLOCK_SIZE - 1); + auto offset = static_cast(static_cast::type>(blockBaseIndex - headBase) / BLOCK_SIZE); + auto block = localBlockIndex->entries[(localBlockIndexHead + offset) & (localBlockIndex->size - 1)].block; + + // Dequeue + auto& el = *((*block)[index]); + if (!MOODYCAMEL_NOEXCEPT_ASSIGN(T, T&&, element = std::move(el))) { + // Make sure the element is still fully dequeued and destroyed even if the assignment + // throws + struct Guard { + Block* block; + index_t index; + + ~Guard() + { + (*block)[index]->~T(); + block->ConcurrentQueue::Block::template set_empty(index); + } + } guard = { block, index }; + + element = std::move(el); // NOLINT + } + else { + element = std::move(el); // NOLINT + el.~T(); // NOLINT + block->ConcurrentQueue::Block::template set_empty(index); + } + + return true; + } + else { + // Wasn't anything to dequeue after all; make the effective dequeue count eventually consistent + this->dequeueOvercommit.fetch_add(1, std::memory_order_release); // Release so that the fetch_add on dequeueOptimisticCount is guaranteed to happen before this write + } + } + + return false; + } + + template + bool MOODYCAMEL_NO_TSAN enqueue_bulk(It itemFirst, size_t count) + { + // First, we need to make sure we have enough room to enqueue all of the elements; + // this means pre-allocating blocks and putting them in the block index (but only if + // all the allocations succeeded). + index_t startTailIndex = this->tailIndex.load(std::memory_order_relaxed); + auto startBlock = this->tailBlock; + auto originalBlockIndexFront = pr_blockIndexFront; + auto originalBlockIndexSlotsUsed = pr_blockIndexSlotsUsed; + + Block* firstAllocatedBlock = nullptr; + + // Figure out how many blocks we'll need to allocate, and do so + size_t blockBaseDiff = ((startTailIndex + count - 1) & ~static_cast(BLOCK_SIZE - 1)) - ((startTailIndex - 1) & ~static_cast(BLOCK_SIZE - 1)); + index_t currentTailIndex = (startTailIndex - 1) & ~static_cast(BLOCK_SIZE - 1); + if (blockBaseDiff > 0) { + // Allocate as many blocks as possible from ahead + while (blockBaseDiff > 0 && this->tailBlock != nullptr && this->tailBlock->next != firstAllocatedBlock && this->tailBlock->next->ConcurrentQueue::Block::template is_empty()) { + blockBaseDiff -= static_cast(BLOCK_SIZE); + currentTailIndex += static_cast(BLOCK_SIZE); + + this->tailBlock = this->tailBlock->next; + firstAllocatedBlock = firstAllocatedBlock == nullptr ? this->tailBlock : firstAllocatedBlock; + + auto& entry = blockIndex.load(std::memory_order_relaxed)->entries[pr_blockIndexFront]; + entry.base = currentTailIndex; + entry.block = this->tailBlock; + pr_blockIndexFront = (pr_blockIndexFront + 1) & (pr_blockIndexSize - 1); + } + + // Now allocate as many blocks as necessary from the block pool + while (blockBaseDiff > 0) { + blockBaseDiff -= static_cast(BLOCK_SIZE); + currentTailIndex += static_cast(BLOCK_SIZE); + + auto head = this->headIndex.load(std::memory_order_relaxed); + assert(!details::circular_less_than(currentTailIndex, head)); + bool full = !details::circular_less_than(head, currentTailIndex + BLOCK_SIZE) || (MAX_SUBQUEUE_SIZE != details::const_numeric_max::value && (MAX_SUBQUEUE_SIZE == 0 || MAX_SUBQUEUE_SIZE - BLOCK_SIZE < currentTailIndex - head)); + if (pr_blockIndexRaw == nullptr || pr_blockIndexSlotsUsed == pr_blockIndexSize || full) { + MOODYCAMEL_CONSTEXPR_IF (allocMode == CannotAlloc) { + // Failed to allocate, undo changes (but keep injected blocks) + pr_blockIndexFront = originalBlockIndexFront; + pr_blockIndexSlotsUsed = originalBlockIndexSlotsUsed; + this->tailBlock = startBlock == nullptr ? firstAllocatedBlock : startBlock; + return false; + } + else if (full || !new_block_index(originalBlockIndexSlotsUsed)) { + // Failed to allocate, undo changes (but keep injected blocks) + pr_blockIndexFront = originalBlockIndexFront; + pr_blockIndexSlotsUsed = originalBlockIndexSlotsUsed; + this->tailBlock = startBlock == nullptr ? firstAllocatedBlock : startBlock; + return false; + } + + // pr_blockIndexFront is updated inside new_block_index, so we need to + // update our fallback value too (since we keep the new index even if we + // later fail) + originalBlockIndexFront = originalBlockIndexSlotsUsed; + } + + // Insert a new block in the circular linked list + auto newBlock = this->parent->ConcurrentQueue::template requisition_block(); + if (newBlock == nullptr) { + pr_blockIndexFront = originalBlockIndexFront; + pr_blockIndexSlotsUsed = originalBlockIndexSlotsUsed; + this->tailBlock = startBlock == nullptr ? firstAllocatedBlock : startBlock; + return false; + } + +#ifdef MCDBGQ_TRACKMEM + newBlock->owner = this; +#endif + newBlock->ConcurrentQueue::Block::template set_all_empty(); + if (this->tailBlock == nullptr) { + newBlock->next = newBlock; + } + else { + newBlock->next = this->tailBlock->next; + this->tailBlock->next = newBlock; + } + this->tailBlock = newBlock; + firstAllocatedBlock = firstAllocatedBlock == nullptr ? this->tailBlock : firstAllocatedBlock; + + ++pr_blockIndexSlotsUsed; + + auto& entry = blockIndex.load(std::memory_order_relaxed)->entries[pr_blockIndexFront]; + entry.base = currentTailIndex; + entry.block = this->tailBlock; + pr_blockIndexFront = (pr_blockIndexFront + 1) & (pr_blockIndexSize - 1); + } + + // Excellent, all allocations succeeded. Reset each block's emptiness before we fill them up, and + // publish the new block index front + auto block = firstAllocatedBlock; + while (true) { + block->ConcurrentQueue::Block::template reset_empty(); + if (block == this->tailBlock) { + break; + } + block = block->next; + } + + MOODYCAMEL_CONSTEXPR_IF (MOODYCAMEL_NOEXCEPT_CTOR(T, decltype(*itemFirst), new (static_cast(nullptr)) T(details::deref_noexcept(itemFirst)))) { + blockIndex.load(std::memory_order_relaxed)->front.store((pr_blockIndexFront - 1) & (pr_blockIndexSize - 1), std::memory_order_release); + } + } + + // Enqueue, one block at a time + index_t newTailIndex = startTailIndex + static_cast(count); + currentTailIndex = startTailIndex; + auto endBlock = this->tailBlock; + this->tailBlock = startBlock; + assert((startTailIndex & static_cast(BLOCK_SIZE - 1)) != 0 || firstAllocatedBlock != nullptr || count == 0); + if ((startTailIndex & static_cast(BLOCK_SIZE - 1)) == 0 && firstAllocatedBlock != nullptr) { + this->tailBlock = firstAllocatedBlock; + } + while (true) { + index_t stopIndex = (currentTailIndex & ~static_cast(BLOCK_SIZE - 1)) + static_cast(BLOCK_SIZE); + if (details::circular_less_than(newTailIndex, stopIndex)) { + stopIndex = newTailIndex; + } + MOODYCAMEL_CONSTEXPR_IF (MOODYCAMEL_NOEXCEPT_CTOR(T, decltype(*itemFirst), new (static_cast(nullptr)) T(details::deref_noexcept(itemFirst)))) { + while (currentTailIndex != stopIndex) { + new ((*this->tailBlock)[currentTailIndex++]) T(*itemFirst++); + } + } + else { + MOODYCAMEL_TRY { + while (currentTailIndex != stopIndex) { + // Must use copy constructor even if move constructor is available + // because we may have to revert if there's an exception. + // Sorry about the horrible templated next line, but it was the only way + // to disable moving *at compile time*, which is important because a type + // may only define a (noexcept) move constructor, and so calls to the + // cctor will not compile, even if they are in an if branch that will never + // be executed + new ((*this->tailBlock)[currentTailIndex]) T(details::nomove_if(nullptr)) T(details::deref_noexcept(itemFirst)))>::eval(*itemFirst)); + ++currentTailIndex; + ++itemFirst; + } + } + MOODYCAMEL_CATCH (...) { + // Oh dear, an exception's been thrown -- destroy the elements that + // were enqueued so far and revert the entire bulk operation (we'll keep + // any allocated blocks in our linked list for later, though). + auto constructedStopIndex = currentTailIndex; + auto lastBlockEnqueued = this->tailBlock; + + pr_blockIndexFront = originalBlockIndexFront; + pr_blockIndexSlotsUsed = originalBlockIndexSlotsUsed; + this->tailBlock = startBlock == nullptr ? firstAllocatedBlock : startBlock; + + if (!details::is_trivially_destructible::value) { + auto block = startBlock; + if ((startTailIndex & static_cast(BLOCK_SIZE - 1)) == 0) { + block = firstAllocatedBlock; + } + currentTailIndex = startTailIndex; + while (true) { + stopIndex = (currentTailIndex & ~static_cast(BLOCK_SIZE - 1)) + static_cast(BLOCK_SIZE); + if (details::circular_less_than(constructedStopIndex, stopIndex)) { + stopIndex = constructedStopIndex; + } + while (currentTailIndex != stopIndex) { + (*block)[currentTailIndex++]->~T(); + } + if (block == lastBlockEnqueued) { + break; + } + block = block->next; + } + } + MOODYCAMEL_RETHROW; + } + } + + if (this->tailBlock == endBlock) { + assert(currentTailIndex == newTailIndex); + break; + } + this->tailBlock = this->tailBlock->next; + } + + MOODYCAMEL_CONSTEXPR_IF (!MOODYCAMEL_NOEXCEPT_CTOR(T, decltype(*itemFirst), new (static_cast(nullptr)) T(details::deref_noexcept(itemFirst)))) { + if (firstAllocatedBlock != nullptr) + blockIndex.load(std::memory_order_relaxed)->front.store((pr_blockIndexFront - 1) & (pr_blockIndexSize - 1), std::memory_order_release); + } + + this->tailIndex.store(newTailIndex, std::memory_order_release); + return true; + } + + template + size_t dequeue_bulk(It& itemFirst, size_t max) + { + auto tail = this->tailIndex.load(std::memory_order_relaxed); + auto overcommit = this->dequeueOvercommit.load(std::memory_order_relaxed); + auto desiredCount = static_cast(tail - (this->dequeueOptimisticCount.load(std::memory_order_relaxed) - overcommit)); + if (details::circular_less_than(0, desiredCount)) { + desiredCount = desiredCount < max ? desiredCount : max; + std::atomic_thread_fence(std::memory_order_acquire); + + auto myDequeueCount = this->dequeueOptimisticCount.fetch_add(desiredCount, std::memory_order_relaxed); + + tail = this->tailIndex.load(std::memory_order_acquire); + auto actualCount = static_cast(tail - (myDequeueCount - overcommit)); + if (details::circular_less_than(0, actualCount)) { + actualCount = desiredCount < actualCount ? desiredCount : actualCount; + if (actualCount < desiredCount) { + this->dequeueOvercommit.fetch_add(desiredCount - actualCount, std::memory_order_release); + } + + // Get the first index. Note that since there's guaranteed to be at least actualCount elements, this + // will never exceed tail. + auto firstIndex = this->headIndex.fetch_add(actualCount, std::memory_order_acq_rel); + + // Determine which block the first element is in + auto localBlockIndex = blockIndex.load(std::memory_order_acquire); + auto localBlockIndexHead = localBlockIndex->front.load(std::memory_order_acquire); + + auto headBase = localBlockIndex->entries[localBlockIndexHead].base; + auto firstBlockBaseIndex = firstIndex & ~static_cast(BLOCK_SIZE - 1); + auto offset = static_cast(static_cast::type>(firstBlockBaseIndex - headBase) / BLOCK_SIZE); + auto indexIndex = (localBlockIndexHead + offset) & (localBlockIndex->size - 1); + + // Iterate the blocks and dequeue + auto index = firstIndex; + do { + auto firstIndexInBlock = index; + index_t endIndex = (index & ~static_cast(BLOCK_SIZE - 1)) + static_cast(BLOCK_SIZE); + endIndex = details::circular_less_than(firstIndex + static_cast(actualCount), endIndex) ? firstIndex + static_cast(actualCount) : endIndex; + auto block = localBlockIndex->entries[indexIndex].block; + if (MOODYCAMEL_NOEXCEPT_ASSIGN(T, T&&, details::deref_noexcept(itemFirst) = std::move((*(*block)[index])))) { + while (index != endIndex) { + auto& el = *((*block)[index]); + *itemFirst++ = std::move(el); + el.~T(); + ++index; + } + } + else { + MOODYCAMEL_TRY { + while (index != endIndex) { + auto& el = *((*block)[index]); + *itemFirst = std::move(el); + ++itemFirst; + el.~T(); + ++index; + } + } + MOODYCAMEL_CATCH (...) { + // It's too late to revert the dequeue, but we can make sure that all + // the dequeued objects are properly destroyed and the block index + // (and empty count) are properly updated before we propagate the exception + do { + block = localBlockIndex->entries[indexIndex].block; + while (index != endIndex) { + (*block)[index++]->~T(); + } + block->ConcurrentQueue::Block::template set_many_empty(firstIndexInBlock, static_cast(endIndex - firstIndexInBlock)); + indexIndex = (indexIndex + 1) & (localBlockIndex->size - 1); + + firstIndexInBlock = index; + endIndex = (index & ~static_cast(BLOCK_SIZE - 1)) + static_cast(BLOCK_SIZE); + endIndex = details::circular_less_than(firstIndex + static_cast(actualCount), endIndex) ? firstIndex + static_cast(actualCount) : endIndex; + } while (index != firstIndex + actualCount); + + MOODYCAMEL_RETHROW; + } + } + block->ConcurrentQueue::Block::template set_many_empty(firstIndexInBlock, static_cast(endIndex - firstIndexInBlock)); + indexIndex = (indexIndex + 1) & (localBlockIndex->size - 1); + } while (index != firstIndex + actualCount); + + return actualCount; + } + else { + // Wasn't anything to dequeue after all; make the effective dequeue count eventually consistent + this->dequeueOvercommit.fetch_add(desiredCount, std::memory_order_release); + } + } + + return 0; + } + + private: + struct BlockIndexEntry + { + index_t base; + Block* block; + }; + + struct BlockIndexHeader + { + size_t size; + std::atomic front; // Current slot (not next, like pr_blockIndexFront) + BlockIndexEntry* entries; + void* prev; + }; + + + bool new_block_index(size_t numberOfFilledSlotsToExpose) + { + auto prevBlockSizeMask = pr_blockIndexSize - 1; + + // Create the new block + pr_blockIndexSize <<= 1; + auto newRawPtr = static_cast((Traits::malloc)(sizeof(BlockIndexHeader) + std::alignment_of::value - 1 + sizeof(BlockIndexEntry) * pr_blockIndexSize)); + if (newRawPtr == nullptr) { + pr_blockIndexSize >>= 1; // Reset to allow graceful retry + return false; + } + + auto newBlockIndexEntries = reinterpret_cast(details::align_for(newRawPtr + sizeof(BlockIndexHeader))); + + // Copy in all the old indices, if any + size_t j = 0; + if (pr_blockIndexSlotsUsed != 0) { + auto i = (pr_blockIndexFront - pr_blockIndexSlotsUsed) & prevBlockSizeMask; + do { + newBlockIndexEntries[j++] = pr_blockIndexEntries[i]; + i = (i + 1) & prevBlockSizeMask; + } while (i != pr_blockIndexFront); + } + + // Update everything + auto header = new (newRawPtr) BlockIndexHeader; + header->size = pr_blockIndexSize; + header->front.store(numberOfFilledSlotsToExpose - 1, std::memory_order_relaxed); + header->entries = newBlockIndexEntries; + header->prev = pr_blockIndexRaw; // we link the new block to the old one so we can free it later + + pr_blockIndexFront = j; + pr_blockIndexEntries = newBlockIndexEntries; + pr_blockIndexRaw = newRawPtr; + blockIndex.store(header, std::memory_order_release); + + return true; + } + + private: + std::atomic blockIndex; + + // To be used by producer only -- consumer must use the ones in referenced by blockIndex + size_t pr_blockIndexSlotsUsed; + size_t pr_blockIndexSize; + size_t pr_blockIndexFront; // Next slot (not current) + BlockIndexEntry* pr_blockIndexEntries; + void* pr_blockIndexRaw; + +#ifdef MOODYCAMEL_QUEUE_INTERNAL_DEBUG + public: + ExplicitProducer* nextExplicitProducer; + private: +#endif + +#ifdef MCDBGQ_TRACKMEM + friend struct MemStats; +#endif + }; + + + ////////////////////////////////// + // Implicit queue + ////////////////////////////////// + + struct ImplicitProducer : public ProducerBase + { + ImplicitProducer(ConcurrentQueue* parent_) : + ProducerBase(parent_, false), + nextBlockIndexCapacity(IMPLICIT_INITIAL_INDEX_SIZE), + blockIndex(nullptr) + { + new_block_index(); + } + + ~ImplicitProducer() + { + // Note that since we're in the destructor we can assume that all enqueue/dequeue operations + // completed already; this means that all undequeued elements are placed contiguously across + // contiguous blocks, and that only the first and last remaining blocks can be only partially + // empty (all other remaining blocks must be completely full). + +#ifdef MOODYCAMEL_CPP11_THREAD_LOCAL_SUPPORTED + // Unregister ourselves for thread termination notification + if (!this->inactive.load(std::memory_order_relaxed)) { + details::ThreadExitNotifier::unsubscribe(&threadExitListener); + } +#endif + + // Destroy all remaining elements! + auto tail = this->tailIndex.load(std::memory_order_relaxed); + auto index = this->headIndex.load(std::memory_order_relaxed); + Block* block = nullptr; + assert(index == tail || details::circular_less_than(index, tail)); + bool forceFreeLastBlock = index != tail; // If we enter the loop, then the last (tail) block will not be freed + while (index != tail) { + if ((index & static_cast(BLOCK_SIZE - 1)) == 0 || block == nullptr) { + if (block != nullptr) { + // Free the old block + this->parent->add_block_to_free_list(block); + } + + block = get_block_index_entry_for_index(index)->value.load(std::memory_order_relaxed); + } + + ((*block)[index])->~T(); + ++index; + } + // Even if the queue is empty, there's still one block that's not on the free list + // (unless the head index reached the end of it, in which case the tail will be poised + // to create a new block). + if (this->tailBlock != nullptr && (forceFreeLastBlock || (tail & static_cast(BLOCK_SIZE - 1)) != 0)) { + this->parent->add_block_to_free_list(this->tailBlock); + } + + // Destroy block index + auto localBlockIndex = blockIndex.load(std::memory_order_relaxed); + if (localBlockIndex != nullptr) { + for (size_t i = 0; i != localBlockIndex->capacity; ++i) { + localBlockIndex->index[i]->~BlockIndexEntry(); + } + do { + auto prev = localBlockIndex->prev; + localBlockIndex->~BlockIndexHeader(); + (Traits::free)(localBlockIndex); + localBlockIndex = prev; + } while (localBlockIndex != nullptr); + } + } + + template + inline bool enqueue(U&& element) + { + index_t currentTailIndex = this->tailIndex.load(std::memory_order_relaxed); + index_t newTailIndex = 1 + currentTailIndex; + if ((currentTailIndex & static_cast(BLOCK_SIZE - 1)) == 0) { + // We reached the end of a block, start a new one + auto head = this->headIndex.load(std::memory_order_relaxed); + assert(!details::circular_less_than(currentTailIndex, head)); + if (!details::circular_less_than(head, currentTailIndex + BLOCK_SIZE) || (MAX_SUBQUEUE_SIZE != details::const_numeric_max::value && (MAX_SUBQUEUE_SIZE == 0 || MAX_SUBQUEUE_SIZE - BLOCK_SIZE < currentTailIndex - head))) { + return false; + } +#ifdef MCDBGQ_NOLOCKFREE_IMPLICITPRODBLOCKINDEX + debug::DebugLock lock(mutex); +#endif + // Find out where we'll be inserting this block in the block index + BlockIndexEntry* idxEntry; + if (!insert_block_index_entry(idxEntry, currentTailIndex)) { + return false; + } + + // Get ahold of a new block + auto newBlock = this->parent->ConcurrentQueue::template requisition_block(); + if (newBlock == nullptr) { + rewind_block_index_tail(); + idxEntry->value.store(nullptr, std::memory_order_relaxed); + return false; + } +#ifdef MCDBGQ_TRACKMEM + newBlock->owner = this; +#endif + newBlock->ConcurrentQueue::Block::template reset_empty(); + + MOODYCAMEL_CONSTEXPR_IF (!MOODYCAMEL_NOEXCEPT_CTOR(T, U, new (static_cast(nullptr)) T(std::forward(element)))) { + // May throw, try to insert now before we publish the fact that we have this new block + MOODYCAMEL_TRY { + new ((*newBlock)[currentTailIndex]) T(std::forward(element)); + } + MOODYCAMEL_CATCH (...) { + rewind_block_index_tail(); + idxEntry->value.store(nullptr, std::memory_order_relaxed); + this->parent->add_block_to_free_list(newBlock); + MOODYCAMEL_RETHROW; + } + } + + // Insert the new block into the index + idxEntry->value.store(newBlock, std::memory_order_relaxed); + + this->tailBlock = newBlock; + + MOODYCAMEL_CONSTEXPR_IF (!MOODYCAMEL_NOEXCEPT_CTOR(T, U, new (static_cast(nullptr)) T(std::forward(element)))) { + this->tailIndex.store(newTailIndex, std::memory_order_release); + return true; + } + } + + // Enqueue + new ((*this->tailBlock)[currentTailIndex]) T(std::forward(element)); + + this->tailIndex.store(newTailIndex, std::memory_order_release); + return true; + } + + template + bool dequeue(U& element) + { + // See ExplicitProducer::dequeue for rationale and explanation + index_t tail = this->tailIndex.load(std::memory_order_relaxed); + index_t overcommit = this->dequeueOvercommit.load(std::memory_order_relaxed); + if (details::circular_less_than(this->dequeueOptimisticCount.load(std::memory_order_relaxed) - overcommit, tail)) { + std::atomic_thread_fence(std::memory_order_acquire); + + index_t myDequeueCount = this->dequeueOptimisticCount.fetch_add(1, std::memory_order_relaxed); + tail = this->tailIndex.load(std::memory_order_acquire); + if ((details::likely)(details::circular_less_than(myDequeueCount - overcommit, tail))) { + index_t index = this->headIndex.fetch_add(1, std::memory_order_acq_rel); + + // Determine which block the element is in + auto entry = get_block_index_entry_for_index(index); + + // Dequeue + auto block = entry->value.load(std::memory_order_relaxed); + auto& el = *((*block)[index]); + + if (!MOODYCAMEL_NOEXCEPT_ASSIGN(T, T&&, element = std::move(el))) { +#ifdef MCDBGQ_NOLOCKFREE_IMPLICITPRODBLOCKINDEX + // Note: Acquiring the mutex with every dequeue instead of only when a block + // is released is very sub-optimal, but it is, after all, purely debug code. + debug::DebugLock lock(producer->mutex); +#endif + struct Guard { + Block* block; + index_t index; + BlockIndexEntry* entry; + ConcurrentQueue* parent; + + ~Guard() + { + (*block)[index]->~T(); + if (block->ConcurrentQueue::Block::template set_empty(index)) { + entry->value.store(nullptr, std::memory_order_relaxed); + parent->add_block_to_free_list(block); + } + } + } guard = { block, index, entry, this->parent }; + + element = std::move(el); // NOLINT + } + else { + element = std::move(el); // NOLINT + el.~T(); // NOLINT + + if (block->ConcurrentQueue::Block::template set_empty(index)) { + { +#ifdef MCDBGQ_NOLOCKFREE_IMPLICITPRODBLOCKINDEX + debug::DebugLock lock(mutex); +#endif + // Add the block back into the global free pool (and remove from block index) + entry->value.store(nullptr, std::memory_order_relaxed); + } + this->parent->add_block_to_free_list(block); // releases the above store + } + } + + return true; + } + else { + this->dequeueOvercommit.fetch_add(1, std::memory_order_release); + } + } + + return false; + } + +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable: 4706) // assignment within conditional expression +#endif + template + bool enqueue_bulk(It itemFirst, size_t count) + { + // First, we need to make sure we have enough room to enqueue all of the elements; + // this means pre-allocating blocks and putting them in the block index (but only if + // all the allocations succeeded). + + // Note that the tailBlock we start off with may not be owned by us any more; + // this happens if it was filled up exactly to the top (setting tailIndex to + // the first index of the next block which is not yet allocated), then dequeued + // completely (putting it on the free list) before we enqueue again. + + index_t startTailIndex = this->tailIndex.load(std::memory_order_relaxed); + auto startBlock = this->tailBlock; + Block* firstAllocatedBlock = nullptr; + auto endBlock = this->tailBlock; + + // Figure out how many blocks we'll need to allocate, and do so + size_t blockBaseDiff = ((startTailIndex + count - 1) & ~static_cast(BLOCK_SIZE - 1)) - ((startTailIndex - 1) & ~static_cast(BLOCK_SIZE - 1)); + index_t currentTailIndex = (startTailIndex - 1) & ~static_cast(BLOCK_SIZE - 1); + if (blockBaseDiff > 0) { +#ifdef MCDBGQ_NOLOCKFREE_IMPLICITPRODBLOCKINDEX + debug::DebugLock lock(mutex); +#endif + do { + blockBaseDiff -= static_cast(BLOCK_SIZE); + currentTailIndex += static_cast(BLOCK_SIZE); + + // Find out where we'll be inserting this block in the block index + BlockIndexEntry* idxEntry = nullptr; // initialization here unnecessary but compiler can't always tell + Block* newBlock; + bool indexInserted = false; + auto head = this->headIndex.load(std::memory_order_relaxed); + assert(!details::circular_less_than(currentTailIndex, head)); + bool full = !details::circular_less_than(head, currentTailIndex + BLOCK_SIZE) || (MAX_SUBQUEUE_SIZE != details::const_numeric_max::value && (MAX_SUBQUEUE_SIZE == 0 || MAX_SUBQUEUE_SIZE - BLOCK_SIZE < currentTailIndex - head)); + + if (full || !(indexInserted = insert_block_index_entry(idxEntry, currentTailIndex)) || (newBlock = this->parent->ConcurrentQueue::template requisition_block()) == nullptr) { + // Index allocation or block allocation failed; revert any other allocations + // and index insertions done so far for this operation + if (indexInserted) { + rewind_block_index_tail(); + idxEntry->value.store(nullptr, std::memory_order_relaxed); + } + currentTailIndex = (startTailIndex - 1) & ~static_cast(BLOCK_SIZE - 1); + for (auto block = firstAllocatedBlock; block != nullptr; block = block->next) { + currentTailIndex += static_cast(BLOCK_SIZE); + idxEntry = get_block_index_entry_for_index(currentTailIndex); + idxEntry->value.store(nullptr, std::memory_order_relaxed); + rewind_block_index_tail(); + } + this->parent->add_blocks_to_free_list(firstAllocatedBlock); + this->tailBlock = startBlock; + + return false; + } + +#ifdef MCDBGQ_TRACKMEM + newBlock->owner = this; +#endif + newBlock->ConcurrentQueue::Block::template reset_empty(); + newBlock->next = nullptr; + + // Insert the new block into the index + idxEntry->value.store(newBlock, std::memory_order_relaxed); + + // Store the chain of blocks so that we can undo if later allocations fail, + // and so that we can find the blocks when we do the actual enqueueing + if ((startTailIndex & static_cast(BLOCK_SIZE - 1)) != 0 || firstAllocatedBlock != nullptr) { + assert(this->tailBlock != nullptr); + this->tailBlock->next = newBlock; + } + this->tailBlock = newBlock; + endBlock = newBlock; + firstAllocatedBlock = firstAllocatedBlock == nullptr ? newBlock : firstAllocatedBlock; + } while (blockBaseDiff > 0); + } + + // Enqueue, one block at a time + index_t newTailIndex = startTailIndex + static_cast(count); + currentTailIndex = startTailIndex; + this->tailBlock = startBlock; + assert((startTailIndex & static_cast(BLOCK_SIZE - 1)) != 0 || firstAllocatedBlock != nullptr || count == 0); + if ((startTailIndex & static_cast(BLOCK_SIZE - 1)) == 0 && firstAllocatedBlock != nullptr) { + this->tailBlock = firstAllocatedBlock; + } + while (true) { + index_t stopIndex = (currentTailIndex & ~static_cast(BLOCK_SIZE - 1)) + static_cast(BLOCK_SIZE); + if (details::circular_less_than(newTailIndex, stopIndex)) { + stopIndex = newTailIndex; + } + MOODYCAMEL_CONSTEXPR_IF (MOODYCAMEL_NOEXCEPT_CTOR(T, decltype(*itemFirst), new (static_cast(nullptr)) T(details::deref_noexcept(itemFirst)))) { + while (currentTailIndex != stopIndex) { + new ((*this->tailBlock)[currentTailIndex++]) T(*itemFirst++); + } + } + else { + MOODYCAMEL_TRY { + while (currentTailIndex != stopIndex) { + new ((*this->tailBlock)[currentTailIndex]) T(details::nomove_if(nullptr)) T(details::deref_noexcept(itemFirst)))>::eval(*itemFirst)); + ++currentTailIndex; + ++itemFirst; + } + } + MOODYCAMEL_CATCH (...) { + auto constructedStopIndex = currentTailIndex; + auto lastBlockEnqueued = this->tailBlock; + + if (!details::is_trivially_destructible::value) { + auto block = startBlock; + if ((startTailIndex & static_cast(BLOCK_SIZE - 1)) == 0) { + block = firstAllocatedBlock; + } + currentTailIndex = startTailIndex; + while (true) { + stopIndex = (currentTailIndex & ~static_cast(BLOCK_SIZE - 1)) + static_cast(BLOCK_SIZE); + if (details::circular_less_than(constructedStopIndex, stopIndex)) { + stopIndex = constructedStopIndex; + } + while (currentTailIndex != stopIndex) { + (*block)[currentTailIndex++]->~T(); + } + if (block == lastBlockEnqueued) { + break; + } + block = block->next; + } + } + + currentTailIndex = (startTailIndex - 1) & ~static_cast(BLOCK_SIZE - 1); + for (auto block = firstAllocatedBlock; block != nullptr; block = block->next) { + currentTailIndex += static_cast(BLOCK_SIZE); + auto idxEntry = get_block_index_entry_for_index(currentTailIndex); + idxEntry->value.store(nullptr, std::memory_order_relaxed); + rewind_block_index_tail(); + } + this->parent->add_blocks_to_free_list(firstAllocatedBlock); + this->tailBlock = startBlock; + MOODYCAMEL_RETHROW; + } + } + + if (this->tailBlock == endBlock) { + assert(currentTailIndex == newTailIndex); + break; + } + this->tailBlock = this->tailBlock->next; + } + this->tailIndex.store(newTailIndex, std::memory_order_release); + return true; + } +#ifdef _MSC_VER +#pragma warning(pop) +#endif + + template + size_t dequeue_bulk(It& itemFirst, size_t max) + { + auto tail = this->tailIndex.load(std::memory_order_relaxed); + auto overcommit = this->dequeueOvercommit.load(std::memory_order_relaxed); + auto desiredCount = static_cast(tail - (this->dequeueOptimisticCount.load(std::memory_order_relaxed) - overcommit)); + if (details::circular_less_than(0, desiredCount)) { + desiredCount = desiredCount < max ? desiredCount : max; + std::atomic_thread_fence(std::memory_order_acquire); + + auto myDequeueCount = this->dequeueOptimisticCount.fetch_add(desiredCount, std::memory_order_relaxed); + + tail = this->tailIndex.load(std::memory_order_acquire); + auto actualCount = static_cast(tail - (myDequeueCount - overcommit)); + if (details::circular_less_than(0, actualCount)) { + actualCount = desiredCount < actualCount ? desiredCount : actualCount; + if (actualCount < desiredCount) { + this->dequeueOvercommit.fetch_add(desiredCount - actualCount, std::memory_order_release); + } + + // Get the first index. Note that since there's guaranteed to be at least actualCount elements, this + // will never exceed tail. + auto firstIndex = this->headIndex.fetch_add(actualCount, std::memory_order_acq_rel); + + // Iterate the blocks and dequeue + auto index = firstIndex; + BlockIndexHeader* localBlockIndex; + auto indexIndex = get_block_index_index_for_index(index, localBlockIndex); + do { + auto blockStartIndex = index; + index_t endIndex = (index & ~static_cast(BLOCK_SIZE - 1)) + static_cast(BLOCK_SIZE); + endIndex = details::circular_less_than(firstIndex + static_cast(actualCount), endIndex) ? firstIndex + static_cast(actualCount) : endIndex; + + auto entry = localBlockIndex->index[indexIndex]; + auto block = entry->value.load(std::memory_order_relaxed); + if (MOODYCAMEL_NOEXCEPT_ASSIGN(T, T&&, details::deref_noexcept(itemFirst) = std::move((*(*block)[index])))) { + while (index != endIndex) { + auto& el = *((*block)[index]); + *itemFirst++ = std::move(el); + el.~T(); + ++index; + } + } + else { + MOODYCAMEL_TRY { + while (index != endIndex) { + auto& el = *((*block)[index]); + *itemFirst = std::move(el); + ++itemFirst; + el.~T(); + ++index; + } + } + MOODYCAMEL_CATCH (...) { + do { + entry = localBlockIndex->index[indexIndex]; + block = entry->value.load(std::memory_order_relaxed); + while (index != endIndex) { + (*block)[index++]->~T(); + } + + if (block->ConcurrentQueue::Block::template set_many_empty(blockStartIndex, static_cast(endIndex - blockStartIndex))) { +#ifdef MCDBGQ_NOLOCKFREE_IMPLICITPRODBLOCKINDEX + debug::DebugLock lock(mutex); +#endif + entry->value.store(nullptr, std::memory_order_relaxed); + this->parent->add_block_to_free_list(block); + } + indexIndex = (indexIndex + 1) & (localBlockIndex->capacity - 1); + + blockStartIndex = index; + endIndex = (index & ~static_cast(BLOCK_SIZE - 1)) + static_cast(BLOCK_SIZE); + endIndex = details::circular_less_than(firstIndex + static_cast(actualCount), endIndex) ? firstIndex + static_cast(actualCount) : endIndex; + } while (index != firstIndex + actualCount); + + MOODYCAMEL_RETHROW; + } + } + if (block->ConcurrentQueue::Block::template set_many_empty(blockStartIndex, static_cast(endIndex - blockStartIndex))) { + { +#ifdef MCDBGQ_NOLOCKFREE_IMPLICITPRODBLOCKINDEX + debug::DebugLock lock(mutex); +#endif + // Note that the set_many_empty above did a release, meaning that anybody who acquires the block + // we're about to free can use it safely since our writes (and reads!) will have happened-before then. + entry->value.store(nullptr, std::memory_order_relaxed); + } + this->parent->add_block_to_free_list(block); // releases the above store + } + indexIndex = (indexIndex + 1) & (localBlockIndex->capacity - 1); + } while (index != firstIndex + actualCount); + + return actualCount; + } + else { + this->dequeueOvercommit.fetch_add(desiredCount, std::memory_order_release); + } + } + + return 0; + } + + private: + // The block size must be > 1, so any number with the low bit set is an invalid block base index + static const index_t INVALID_BLOCK_BASE = 1; + + struct BlockIndexEntry + { + std::atomic key; + std::atomic value; + }; + + struct BlockIndexHeader + { + size_t capacity; + std::atomic tail; + BlockIndexEntry* entries; + BlockIndexEntry** index; + BlockIndexHeader* prev; + }; + + template + inline bool insert_block_index_entry(BlockIndexEntry*& idxEntry, index_t blockStartIndex) + { + auto localBlockIndex = blockIndex.load(std::memory_order_relaxed); // We're the only writer thread, relaxed is OK + if (localBlockIndex == nullptr) { + return false; // this can happen if new_block_index failed in the constructor + } + size_t newTail = (localBlockIndex->tail.load(std::memory_order_relaxed) + 1) & (localBlockIndex->capacity - 1); + idxEntry = localBlockIndex->index[newTail]; + if (idxEntry->key.load(std::memory_order_relaxed) == INVALID_BLOCK_BASE || + idxEntry->value.load(std::memory_order_relaxed) == nullptr) { + + idxEntry->key.store(blockStartIndex, std::memory_order_relaxed); + localBlockIndex->tail.store(newTail, std::memory_order_release); + return true; + } + + // No room in the old block index, try to allocate another one! + MOODYCAMEL_CONSTEXPR_IF (allocMode == CannotAlloc) { + return false; + } + else if (!new_block_index()) { + return false; + } + localBlockIndex = blockIndex.load(std::memory_order_relaxed); + newTail = (localBlockIndex->tail.load(std::memory_order_relaxed) + 1) & (localBlockIndex->capacity - 1); + idxEntry = localBlockIndex->index[newTail]; + assert(idxEntry->key.load(std::memory_order_relaxed) == INVALID_BLOCK_BASE); + idxEntry->key.store(blockStartIndex, std::memory_order_relaxed); + localBlockIndex->tail.store(newTail, std::memory_order_release); + return true; + } + + inline void rewind_block_index_tail() + { + auto localBlockIndex = blockIndex.load(std::memory_order_relaxed); + localBlockIndex->tail.store((localBlockIndex->tail.load(std::memory_order_relaxed) - 1) & (localBlockIndex->capacity - 1), std::memory_order_relaxed); + } + + inline BlockIndexEntry* get_block_index_entry_for_index(index_t index) const + { + BlockIndexHeader* localBlockIndex; + auto idx = get_block_index_index_for_index(index, localBlockIndex); + return localBlockIndex->index[idx]; + } + + inline size_t get_block_index_index_for_index(index_t index, BlockIndexHeader*& localBlockIndex) const + { +#ifdef MCDBGQ_NOLOCKFREE_IMPLICITPRODBLOCKINDEX + debug::DebugLock lock(mutex); +#endif + index &= ~static_cast(BLOCK_SIZE - 1); + localBlockIndex = blockIndex.load(std::memory_order_acquire); + auto tail = localBlockIndex->tail.load(std::memory_order_acquire); + auto tailBase = localBlockIndex->index[tail]->key.load(std::memory_order_relaxed); + assert(tailBase != INVALID_BLOCK_BASE); + // Note: Must use division instead of shift because the index may wrap around, causing a negative + // offset, whose negativity we want to preserve + auto offset = static_cast(static_cast::type>(index - tailBase) / BLOCK_SIZE); + size_t idx = (tail + offset) & (localBlockIndex->capacity - 1); + assert(localBlockIndex->index[idx]->key.load(std::memory_order_relaxed) == index && localBlockIndex->index[idx]->value.load(std::memory_order_relaxed) != nullptr); + return idx; + } + + bool new_block_index() + { + auto prev = blockIndex.load(std::memory_order_relaxed); + size_t prevCapacity = prev == nullptr ? 0 : prev->capacity; + auto entryCount = prev == nullptr ? nextBlockIndexCapacity : prevCapacity; + auto raw = static_cast((Traits::malloc)( + sizeof(BlockIndexHeader) + + std::alignment_of::value - 1 + sizeof(BlockIndexEntry) * entryCount + + std::alignment_of::value - 1 + sizeof(BlockIndexEntry*) * nextBlockIndexCapacity)); + if (raw == nullptr) { + return false; + } + + auto header = new (raw) BlockIndexHeader; + auto entries = reinterpret_cast(details::align_for(raw + sizeof(BlockIndexHeader))); + auto index = reinterpret_cast(details::align_for(reinterpret_cast(entries) + sizeof(BlockIndexEntry) * entryCount)); + if (prev != nullptr) { + auto prevTail = prev->tail.load(std::memory_order_relaxed); + auto prevPos = prevTail; + size_t i = 0; + do { + prevPos = (prevPos + 1) & (prev->capacity - 1); + index[i++] = prev->index[prevPos]; + } while (prevPos != prevTail); + assert(i == prevCapacity); + } + for (size_t i = 0; i != entryCount; ++i) { + new (entries + i) BlockIndexEntry; + entries[i].key.store(INVALID_BLOCK_BASE, std::memory_order_relaxed); + index[prevCapacity + i] = entries + i; + } + header->prev = prev; + header->entries = entries; + header->index = index; + header->capacity = nextBlockIndexCapacity; + header->tail.store((prevCapacity - 1) & (nextBlockIndexCapacity - 1), std::memory_order_relaxed); + + blockIndex.store(header, std::memory_order_release); + + nextBlockIndexCapacity <<= 1; + + return true; + } + + private: + size_t nextBlockIndexCapacity; + std::atomic blockIndex; + +#ifdef MOODYCAMEL_CPP11_THREAD_LOCAL_SUPPORTED + public: + details::ThreadExitListener threadExitListener; + private: +#endif + +#ifdef MOODYCAMEL_QUEUE_INTERNAL_DEBUG + public: + ImplicitProducer* nextImplicitProducer; + private: +#endif + +#ifdef MCDBGQ_NOLOCKFREE_IMPLICITPRODBLOCKINDEX + mutable debug::DebugMutex mutex; +#endif +#ifdef MCDBGQ_TRACKMEM + friend struct MemStats; +#endif + }; + + + ////////////////////////////////// + // Block pool manipulation + ////////////////////////////////// + + void populate_initial_block_list(size_t blockCount) + { + initialBlockPoolSize = blockCount; + if (initialBlockPoolSize == 0) { + initialBlockPool = nullptr; + return; + } + + initialBlockPool = create_array(blockCount); + if (initialBlockPool == nullptr) { + initialBlockPoolSize = 0; + } + for (size_t i = 0; i < initialBlockPoolSize; ++i) { + initialBlockPool[i].dynamicallyAllocated = false; + } + } + + inline Block* try_get_block_from_initial_pool() + { + if (initialBlockPoolIndex.load(std::memory_order_relaxed) >= initialBlockPoolSize) { + return nullptr; + } + + auto index = initialBlockPoolIndex.fetch_add(1, std::memory_order_relaxed); + + return index < initialBlockPoolSize ? (initialBlockPool + index) : nullptr; + } + + inline void add_block_to_free_list(Block* block) + { +#ifdef MCDBGQ_TRACKMEM + block->owner = nullptr; +#endif + freeList.add(block); + } + + inline void add_blocks_to_free_list(Block* block) + { + while (block != nullptr) { + auto next = block->next; + add_block_to_free_list(block); + block = next; + } + } + + inline Block* try_get_block_from_free_list() + { + return freeList.try_get(); + } + + // Gets a free block from one of the memory pools, or allocates a new one (if applicable) + template + Block* requisition_block() + { + auto block = try_get_block_from_initial_pool(); + if (block != nullptr) { + return block; + } + + block = try_get_block_from_free_list(); + if (block != nullptr) { + return block; + } + + MOODYCAMEL_CONSTEXPR_IF (canAlloc == CanAlloc) { + return create(); + } + else { + return nullptr; + } + } + + +#ifdef MCDBGQ_TRACKMEM + public: + struct MemStats { + size_t allocatedBlocks; + size_t usedBlocks; + size_t freeBlocks; + size_t ownedBlocksExplicit; + size_t ownedBlocksImplicit; + size_t implicitProducers; + size_t explicitProducers; + size_t elementsEnqueued; + size_t blockClassBytes; + size_t queueClassBytes; + size_t implicitBlockIndexBytes; + size_t explicitBlockIndexBytes; + + friend class ConcurrentQueue; + + private: + static MemStats getFor(ConcurrentQueue* q) + { + MemStats stats = { 0 }; + + stats.elementsEnqueued = q->size_approx(); + + auto block = q->freeList.head_unsafe(); + while (block != nullptr) { + ++stats.allocatedBlocks; + ++stats.freeBlocks; + block = block->freeListNext.load(std::memory_order_relaxed); + } + + for (auto ptr = q->producerListTail.load(std::memory_order_acquire); ptr != nullptr; ptr = ptr->next_prod()) { + bool implicit = dynamic_cast(ptr) != nullptr; + stats.implicitProducers += implicit ? 1 : 0; + stats.explicitProducers += implicit ? 0 : 1; + + if (implicit) { + auto prod = static_cast(ptr); + stats.queueClassBytes += sizeof(ImplicitProducer); + auto head = prod->headIndex.load(std::memory_order_relaxed); + auto tail = prod->tailIndex.load(std::memory_order_relaxed); + auto hash = prod->blockIndex.load(std::memory_order_relaxed); + if (hash != nullptr) { + for (size_t i = 0; i != hash->capacity; ++i) { + if (hash->index[i]->key.load(std::memory_order_relaxed) != ImplicitProducer::INVALID_BLOCK_BASE && hash->index[i]->value.load(std::memory_order_relaxed) != nullptr) { + ++stats.allocatedBlocks; + ++stats.ownedBlocksImplicit; + } + } + stats.implicitBlockIndexBytes += hash->capacity * sizeof(typename ImplicitProducer::BlockIndexEntry); + for (; hash != nullptr; hash = hash->prev) { + stats.implicitBlockIndexBytes += sizeof(typename ImplicitProducer::BlockIndexHeader) + hash->capacity * sizeof(typename ImplicitProducer::BlockIndexEntry*); + } + } + for (; details::circular_less_than(head, tail); head += BLOCK_SIZE) { + //auto block = prod->get_block_index_entry_for_index(head); + ++stats.usedBlocks; + } + } + else { + auto prod = static_cast(ptr); + stats.queueClassBytes += sizeof(ExplicitProducer); + auto tailBlock = prod->tailBlock; + bool wasNonEmpty = false; + if (tailBlock != nullptr) { + auto block = tailBlock; + do { + ++stats.allocatedBlocks; + if (!block->ConcurrentQueue::Block::template is_empty() || wasNonEmpty) { + ++stats.usedBlocks; + wasNonEmpty = wasNonEmpty || block != tailBlock; + } + ++stats.ownedBlocksExplicit; + block = block->next; + } while (block != tailBlock); + } + auto index = prod->blockIndex.load(std::memory_order_relaxed); + while (index != nullptr) { + stats.explicitBlockIndexBytes += sizeof(typename ExplicitProducer::BlockIndexHeader) + index->size * sizeof(typename ExplicitProducer::BlockIndexEntry); + index = static_cast(index->prev); + } + } + } + + auto freeOnInitialPool = q->initialBlockPoolIndex.load(std::memory_order_relaxed) >= q->initialBlockPoolSize ? 0 : q->initialBlockPoolSize - q->initialBlockPoolIndex.load(std::memory_order_relaxed); + stats.allocatedBlocks += freeOnInitialPool; + stats.freeBlocks += freeOnInitialPool; + + stats.blockClassBytes = sizeof(Block) * stats.allocatedBlocks; + stats.queueClassBytes += sizeof(ConcurrentQueue); + + return stats; + } + }; + + // For debugging only. Not thread-safe. + MemStats getMemStats() + { + return MemStats::getFor(this); + } + private: + friend struct MemStats; +#endif + + + ////////////////////////////////// + // Producer list manipulation + ////////////////////////////////// + + ProducerBase* recycle_or_create_producer(bool isExplicit) + { + bool recycled; + return recycle_or_create_producer(isExplicit, recycled); + } + + ProducerBase* recycle_or_create_producer(bool isExplicit, bool& recycled) + { +#ifdef MCDBGQ_NOLOCKFREE_IMPLICITPRODHASH + debug::DebugLock lock(implicitProdMutex); +#endif + // Try to re-use one first + for (auto ptr = producerListTail.load(std::memory_order_acquire); ptr != nullptr; ptr = ptr->next_prod()) { + if (ptr->inactive.load(std::memory_order_relaxed) && ptr->isExplicit == isExplicit) { + bool expected = true; + if (ptr->inactive.compare_exchange_strong(expected, /* desired */ false, std::memory_order_acquire, std::memory_order_relaxed)) { + // We caught one! It's been marked as activated, the caller can have it + recycled = true; + return ptr; + } + } + } + + recycled = false; + return add_producer(isExplicit ? static_cast(create(this)) : create(this)); + } + + ProducerBase* add_producer(ProducerBase* producer) + { + // Handle failed memory allocation + if (producer == nullptr) { + return nullptr; + } + + producerCount.fetch_add(1, std::memory_order_relaxed); + + // Add it to the lock-free list + auto prevTail = producerListTail.load(std::memory_order_relaxed); + do { + producer->next = prevTail; + } while (!producerListTail.compare_exchange_weak(prevTail, producer, std::memory_order_release, std::memory_order_relaxed)); + +#ifdef MOODYCAMEL_QUEUE_INTERNAL_DEBUG + if (producer->isExplicit) { + auto prevTailExplicit = explicitProducers.load(std::memory_order_relaxed); + do { + static_cast(producer)->nextExplicitProducer = prevTailExplicit; + } while (!explicitProducers.compare_exchange_weak(prevTailExplicit, static_cast(producer), std::memory_order_release, std::memory_order_relaxed)); + } + else { + auto prevTailImplicit = implicitProducers.load(std::memory_order_relaxed); + do { + static_cast(producer)->nextImplicitProducer = prevTailImplicit; + } while (!implicitProducers.compare_exchange_weak(prevTailImplicit, static_cast(producer), std::memory_order_release, std::memory_order_relaxed)); + } +#endif + + return producer; + } + + void reown_producers() + { + // After another instance is moved-into/swapped-with this one, all the + // producers we stole still think their parents are the other queue. + // So fix them up! + for (auto ptr = producerListTail.load(std::memory_order_relaxed); ptr != nullptr; ptr = ptr->next_prod()) { + ptr->parent = this; + } + } + + + ////////////////////////////////// + // Implicit producer hash + ////////////////////////////////// + + struct ImplicitProducerKVP + { + std::atomic key; + ImplicitProducer* value; // No need for atomicity since it's only read by the thread that sets it in the first place + + ImplicitProducerKVP() : value(nullptr) { } + + ImplicitProducerKVP(ImplicitProducerKVP&& other) MOODYCAMEL_NOEXCEPT + { + key.store(other.key.load(std::memory_order_relaxed), std::memory_order_relaxed); + value = other.value; + } + + inline ImplicitProducerKVP& operator=(ImplicitProducerKVP&& other) MOODYCAMEL_NOEXCEPT + { + swap(other); + return *this; + } + + inline void swap(ImplicitProducerKVP& other) MOODYCAMEL_NOEXCEPT + { + if (this != &other) { + details::swap_relaxed(key, other.key); + std::swap(value, other.value); + } + } + }; + + template + friend void moodycamel::swap(typename ConcurrentQueue::ImplicitProducerKVP&, typename ConcurrentQueue::ImplicitProducerKVP&) MOODYCAMEL_NOEXCEPT; + + struct ImplicitProducerHash + { + size_t capacity; + ImplicitProducerKVP* entries; + ImplicitProducerHash* prev; + }; + + inline void populate_initial_implicit_producer_hash() + { + MOODYCAMEL_CONSTEXPR_IF (INITIAL_IMPLICIT_PRODUCER_HASH_SIZE == 0) { + return; + } + else { + implicitProducerHashCount.store(0, std::memory_order_relaxed); + auto hash = &initialImplicitProducerHash; + hash->capacity = INITIAL_IMPLICIT_PRODUCER_HASH_SIZE; + hash->entries = &initialImplicitProducerHashEntries[0]; + for (size_t i = 0; i != INITIAL_IMPLICIT_PRODUCER_HASH_SIZE; ++i) { + initialImplicitProducerHashEntries[i].key.store(details::invalid_thread_id, std::memory_order_relaxed); + } + hash->prev = nullptr; + implicitProducerHash.store(hash, std::memory_order_relaxed); + } + } + + void swap_implicit_producer_hashes(ConcurrentQueue& other) + { + MOODYCAMEL_CONSTEXPR_IF (INITIAL_IMPLICIT_PRODUCER_HASH_SIZE == 0) { + return; + } + else { + // Swap (assumes our implicit producer hash is initialized) + initialImplicitProducerHashEntries.swap(other.initialImplicitProducerHashEntries); + initialImplicitProducerHash.entries = &initialImplicitProducerHashEntries[0]; + other.initialImplicitProducerHash.entries = &other.initialImplicitProducerHashEntries[0]; + + details::swap_relaxed(implicitProducerHashCount, other.implicitProducerHashCount); + + details::swap_relaxed(implicitProducerHash, other.implicitProducerHash); + if (implicitProducerHash.load(std::memory_order_relaxed) == &other.initialImplicitProducerHash) { + implicitProducerHash.store(&initialImplicitProducerHash, std::memory_order_relaxed); + } + else { + ImplicitProducerHash* hash; + for (hash = implicitProducerHash.load(std::memory_order_relaxed); hash->prev != &other.initialImplicitProducerHash; hash = hash->prev) { + continue; + } + hash->prev = &initialImplicitProducerHash; + } + if (other.implicitProducerHash.load(std::memory_order_relaxed) == &initialImplicitProducerHash) { + other.implicitProducerHash.store(&other.initialImplicitProducerHash, std::memory_order_relaxed); + } + else { + ImplicitProducerHash* hash; + for (hash = other.implicitProducerHash.load(std::memory_order_relaxed); hash->prev != &initialImplicitProducerHash; hash = hash->prev) { + continue; + } + hash->prev = &other.initialImplicitProducerHash; + } + } + } + + // Only fails (returns nullptr) if memory allocation fails + ImplicitProducer* get_or_add_implicit_producer() + { + // Note that since the data is essentially thread-local (key is thread ID), + // there's a reduced need for fences (memory ordering is already consistent + // for any individual thread), except for the current table itself. + + // Start by looking for the thread ID in the current and all previous hash tables. + // If it's not found, it must not be in there yet, since this same thread would + // have added it previously to one of the tables that we traversed. + + // Code and algorithm adapted from http://preshing.com/20130605/the-worlds-simplest-lock-free-hash-table + +#ifdef MCDBGQ_NOLOCKFREE_IMPLICITPRODHASH + debug::DebugLock lock(implicitProdMutex); +#endif + + auto id = details::thread_id(); + auto hashedId = details::hash_thread_id(id); + + auto mainHash = implicitProducerHash.load(std::memory_order_acquire); + assert(mainHash != nullptr); // silence clang-tidy and MSVC warnings (hash cannot be null) + for (auto hash = mainHash; hash != nullptr; hash = hash->prev) { + // Look for the id in this hash + auto index = hashedId; + while (true) { // Not an infinite loop because at least one slot is free in the hash table + index &= hash->capacity - 1; + + auto probedKey = hash->entries[index].key.load(std::memory_order_relaxed); + if (probedKey == id) { + // Found it! If we had to search several hashes deep, though, we should lazily add it + // to the current main hash table to avoid the extended search next time. + // Note there's guaranteed to be room in the current hash table since every subsequent + // table implicitly reserves space for all previous tables (there's only one + // implicitProducerHashCount). + auto value = hash->entries[index].value; + if (hash != mainHash) { + index = hashedId; + while (true) { + index &= mainHash->capacity - 1; + probedKey = mainHash->entries[index].key.load(std::memory_order_relaxed); + auto empty = details::invalid_thread_id; +#ifdef MOODYCAMEL_CPP11_THREAD_LOCAL_SUPPORTED + auto reusable = details::invalid_thread_id2; + if ((probedKey == empty && mainHash->entries[index].key.compare_exchange_strong(empty, id, std::memory_order_relaxed, std::memory_order_relaxed)) || + (probedKey == reusable && mainHash->entries[index].key.compare_exchange_strong(reusable, id, std::memory_order_acquire, std::memory_order_acquire))) { +#else + if ((probedKey == empty && mainHash->entries[index].key.compare_exchange_strong(empty, id, std::memory_order_relaxed, std::memory_order_relaxed))) { +#endif + mainHash->entries[index].value = value; + break; + } + ++index; + } + } + + return value; + } + if (probedKey == details::invalid_thread_id) { + break; // Not in this hash table + } + ++index; + } + } + + // Insert! + auto newCount = 1 + implicitProducerHashCount.fetch_add(1, std::memory_order_relaxed); + while (true) { + // NOLINTNEXTLINE(clang-analyzer-core.NullDereference) + if (newCount >= (mainHash->capacity >> 1) && !implicitProducerHashResizeInProgress.test_and_set(std::memory_order_acquire)) { + // We've acquired the resize lock, try to allocate a bigger hash table. + // Note the acquire fence synchronizes with the release fence at the end of this block, and hence when + // we reload implicitProducerHash it must be the most recent version (it only gets changed within this + // locked block). + mainHash = implicitProducerHash.load(std::memory_order_acquire); + if (newCount >= (mainHash->capacity >> 1)) { + auto newCapacity = mainHash->capacity << 1; + while (newCount >= (newCapacity >> 1)) { + newCapacity <<= 1; + } + auto raw = static_cast((Traits::malloc)(sizeof(ImplicitProducerHash) + std::alignment_of::value - 1 + sizeof(ImplicitProducerKVP) * newCapacity)); + if (raw == nullptr) { + // Allocation failed + implicitProducerHashCount.fetch_sub(1, std::memory_order_relaxed); + implicitProducerHashResizeInProgress.clear(std::memory_order_relaxed); + return nullptr; + } + + auto newHash = new (raw) ImplicitProducerHash; + newHash->capacity = static_cast(newCapacity); + newHash->entries = reinterpret_cast(details::align_for(raw + sizeof(ImplicitProducerHash))); + for (size_t i = 0; i != newCapacity; ++i) { + new (newHash->entries + i) ImplicitProducerKVP; + newHash->entries[i].key.store(details::invalid_thread_id, std::memory_order_relaxed); + } + newHash->prev = mainHash; + implicitProducerHash.store(newHash, std::memory_order_release); + implicitProducerHashResizeInProgress.clear(std::memory_order_release); + mainHash = newHash; + } + else { + implicitProducerHashResizeInProgress.clear(std::memory_order_release); + } + } + + // If it's < three-quarters full, add to the old one anyway so that we don't have to wait for the next table + // to finish being allocated by another thread (and if we just finished allocating above, the condition will + // always be true) + if (newCount < (mainHash->capacity >> 1) + (mainHash->capacity >> 2)) { + bool recycled; + auto producer = static_cast(recycle_or_create_producer(false, recycled)); + if (producer == nullptr) { + implicitProducerHashCount.fetch_sub(1, std::memory_order_relaxed); + return nullptr; + } + if (recycled) { + implicitProducerHashCount.fetch_sub(1, std::memory_order_relaxed); + } + +#ifdef MOODYCAMEL_CPP11_THREAD_LOCAL_SUPPORTED + producer->threadExitListener.callback = &ConcurrentQueue::implicit_producer_thread_exited_callback; + producer->threadExitListener.userData = producer; + details::ThreadExitNotifier::subscribe(&producer->threadExitListener); +#endif + + auto index = hashedId; + while (true) { + index &= mainHash->capacity - 1; + auto probedKey = mainHash->entries[index].key.load(std::memory_order_relaxed); + + auto empty = details::invalid_thread_id; +#ifdef MOODYCAMEL_CPP11_THREAD_LOCAL_SUPPORTED + auto reusable = details::invalid_thread_id2; + if ((probedKey == empty && mainHash->entries[index].key.compare_exchange_strong(empty, id, std::memory_order_relaxed, std::memory_order_relaxed)) || + (probedKey == reusable && mainHash->entries[index].key.compare_exchange_strong(reusable, id, std::memory_order_acquire, std::memory_order_acquire))) { +#else + if ((probedKey == empty && mainHash->entries[index].key.compare_exchange_strong(empty, id, std::memory_order_relaxed, std::memory_order_relaxed))) { +#endif + mainHash->entries[index].value = producer; + break; + } + ++index; + } + return producer; + } + + // Hmm, the old hash is quite full and somebody else is busy allocating a new one. + // We need to wait for the allocating thread to finish (if it succeeds, we add, if not, + // we try to allocate ourselves). + mainHash = implicitProducerHash.load(std::memory_order_acquire); + } + } + +#ifdef MOODYCAMEL_CPP11_THREAD_LOCAL_SUPPORTED + void implicit_producer_thread_exited(ImplicitProducer* producer) + { + // Remove from thread exit listeners + details::ThreadExitNotifier::unsubscribe(&producer->threadExitListener); + + // Remove from hash +#ifdef MCDBGQ_NOLOCKFREE_IMPLICITPRODHASH + debug::DebugLock lock(implicitProdMutex); +#endif + auto hash = implicitProducerHash.load(std::memory_order_acquire); + assert(hash != nullptr); // The thread exit listener is only registered if we were added to a hash in the first place + auto id = details::thread_id(); + auto hashedId = details::hash_thread_id(id); + details::thread_id_t probedKey; + + // We need to traverse all the hashes just in case other threads aren't on the current one yet and are + // trying to add an entry thinking there's a free slot (because they reused a producer) + for (; hash != nullptr; hash = hash->prev) { + auto index = hashedId; + do { + index &= hash->capacity - 1; + probedKey = hash->entries[index].key.load(std::memory_order_relaxed); + if (probedKey == id) { + hash->entries[index].key.store(details::invalid_thread_id2, std::memory_order_release); + break; + } + ++index; + } while (probedKey != details::invalid_thread_id); // Can happen if the hash has changed but we weren't put back in it yet, or if we weren't added to this hash in the first place + } + + // Mark the queue as being recyclable + producer->inactive.store(true, std::memory_order_release); + } + + static void implicit_producer_thread_exited_callback(void* userData) + { + auto producer = static_cast(userData); + auto queue = producer->parent; + queue->implicit_producer_thread_exited(producer); + } +#endif + + ////////////////////////////////// + // Utility functions + ////////////////////////////////// + + template + static inline void* aligned_malloc(size_t size) + { + MOODYCAMEL_CONSTEXPR_IF (std::alignment_of::value <= std::alignment_of::value) + return (Traits::malloc)(size); + else { + size_t alignment = std::alignment_of::value; + void* raw = (Traits::malloc)(size + alignment - 1 + sizeof(void*)); + if (!raw) + return nullptr; + char* ptr = details::align_for(reinterpret_cast(raw) + sizeof(void*)); + *(reinterpret_cast(ptr) - 1) = raw; + return ptr; + } + } + + template + static inline void aligned_free(void* ptr) + { + MOODYCAMEL_CONSTEXPR_IF (std::alignment_of::value <= std::alignment_of::value) + return (Traits::free)(ptr); + else + (Traits::free)(ptr ? *(reinterpret_cast(ptr) - 1) : nullptr); + } + + template + static inline U* create_array(size_t count) + { + assert(count > 0); + U* p = static_cast(aligned_malloc(sizeof(U) * count)); + if (p == nullptr) + return nullptr; + + for (size_t i = 0; i != count; ++i) + new (p + i) U(); + return p; + } + + template + static inline void destroy_array(U* p, size_t count) + { + if (p != nullptr) { + assert(count > 0); + for (size_t i = count; i != 0; ) + (p + --i)->~U(); + } + aligned_free(p); + } + + template + static inline U* create() + { + void* p = aligned_malloc(sizeof(U)); + return p != nullptr ? new (p) U : nullptr; + } + + template + static inline U* create(A1&& a1) + { + void* p = aligned_malloc(sizeof(U)); + return p != nullptr ? new (p) U(std::forward(a1)) : nullptr; + } + + template + static inline void destroy(U* p) + { + if (p != nullptr) + p->~U(); + aligned_free(p); + } + +private: + std::atomic producerListTail; + std::atomic producerCount; + + std::atomic initialBlockPoolIndex; + Block* initialBlockPool; + size_t initialBlockPoolSize; + +#ifndef MCDBGQ_USEDEBUGFREELIST + FreeList freeList; +#else + debug::DebugFreeList freeList; +#endif + + std::atomic implicitProducerHash; + std::atomic implicitProducerHashCount; // Number of slots logically used + ImplicitProducerHash initialImplicitProducerHash; + std::array initialImplicitProducerHashEntries; + std::atomic_flag implicitProducerHashResizeInProgress; + + std::atomic nextExplicitConsumerId; + std::atomic globalExplicitConsumerOffset; + +#ifdef MCDBGQ_NOLOCKFREE_IMPLICITPRODHASH + debug::DebugMutex implicitProdMutex; +#endif + +#ifdef MOODYCAMEL_QUEUE_INTERNAL_DEBUG + std::atomic explicitProducers; + std::atomic implicitProducers; +#endif +}; + + +template +ProducerToken::ProducerToken(ConcurrentQueue& queue) + : producer(queue.recycle_or_create_producer(true)) +{ + if (producer != nullptr) { + producer->token = this; + } +} + +template +ProducerToken::ProducerToken(BlockingConcurrentQueue& queue) + : producer(reinterpret_cast*>(&queue)->recycle_or_create_producer(true)) +{ + if (producer != nullptr) { + producer->token = this; + } +} + +template +ConsumerToken::ConsumerToken(ConcurrentQueue& queue) + : itemsConsumedFromCurrent(0), currentProducer(nullptr), desiredProducer(nullptr) +{ + initialOffset = queue.nextExplicitConsumerId.fetch_add(1, std::memory_order_release); + lastKnownGlobalOffset = static_cast(-1); +} + +template +ConsumerToken::ConsumerToken(BlockingConcurrentQueue& queue) + : itemsConsumedFromCurrent(0), currentProducer(nullptr), desiredProducer(nullptr) +{ + initialOffset = reinterpret_cast*>(&queue)->nextExplicitConsumerId.fetch_add(1, std::memory_order_release); + lastKnownGlobalOffset = static_cast(-1); +} + +template +inline void swap(ConcurrentQueue& a, ConcurrentQueue& b) MOODYCAMEL_NOEXCEPT +{ + a.swap(b); +} + +inline void swap(ProducerToken& a, ProducerToken& b) MOODYCAMEL_NOEXCEPT +{ + a.swap(b); +} + +inline void swap(ConsumerToken& a, ConsumerToken& b) MOODYCAMEL_NOEXCEPT +{ + a.swap(b); +} + +template +inline void swap(typename ConcurrentQueue::ImplicitProducerKVP& a, typename ConcurrentQueue::ImplicitProducerKVP& b) MOODYCAMEL_NOEXCEPT +{ + a.swap(b); +} + +} + +#if defined(_MSC_VER) && (!defined(_HAS_CXX17) || !_HAS_CXX17) +#pragma warning(pop) +#endif + +#if defined(__GNUC__) && !defined(__INTEL_COMPILER) +#pragma GCC diagnostic pop +#endif diff --git a/indra/llcommon/fsperfstats.cpp b/indra/llcommon/fsperfstats.cpp index f428b83d9f..ac2d5f2de3 100644 --- a/indra/llcommon/fsperfstats.cpp +++ b/indra/llcommon/fsperfstats.cpp @@ -27,10 +27,10 @@ #include "fsperfstats.h" namespace FSPerfStats { - int RecordSceneTime::writeBuffer{0}; - - bool RecordSceneTime::collectionEnabled{true}; - - std::array< typename RecordSceneTime::StatsArray, 2 > RecordSceneTime::stats{ {} }; + std::atomic StatsRecorder::writeBuffer{0}; + bool StatsRecorder::collectionEnabled{true}; + std::array StatsRecorder::statsDoubleBuffer{ {} }; + std::array StatsRecorder::max{ {} }; + std::array StatsRecorder::sum{ {} }; } \ No newline at end of file diff --git a/indra/llcommon/fsperfstats.h b/indra/llcommon/fsperfstats.h index cab3679dcd..c55aeb6333 100644 --- a/indra/llcommon/fsperfstats.h +++ b/indra/llcommon/fsperfstats.h @@ -28,19 +28,28 @@ * $/LicenseInfo$ */ +#include #include #include #include +#include "lluuid.h" +#include "lltimer.h" +#include "blockingconcurrentqueue.h" +#include "llapp.h" +#include "fstelemetry.h" +extern LLUUID gAgentID; namespace FSPerfStats { - enum class ObjStatType_t{ - RENDER_GEOMETRY=0, - RENDER_SHADOWS, - RENDER_COMBINED, - STATS_COUNT + + enum class ObjType_t{ + OT_GENERAL=0, // Also Unknown. Used for n/a type stats such as scenery + OT_AVATAR, + OT_ATTACHMENT, + OT_HUD, + OT_COUNT }; - enum class SceneStatType_t{ + enum class StatType_t{ RENDER_GEOMETRY=0, RENDER_SHADOWS, RENDER_HUDS, @@ -57,243 +66,251 @@ namespace FSPerfStats STATS_COUNT }; - using ObjStatType = ObjStatType_t; - using SceneStatType = SceneStatType_t; + struct StatsRecord + { + StatType_t statType; + ObjType_t objType; + LLUUID objID; + uint64_t time; + }; - class RecordSceneTime - { - using StatsEnum = SceneStatType; - using StatsArray = std::array(StatsEnum::STATS_COUNT)>; - // using StatsBlock = std::unordered_map; - - static int writeBuffer; - static std::array stats; - static bool collectionEnabled; - - RecordSceneTime(const RecordSceneTime&) = delete; - RecordSceneTime() = delete; - - const StatsEnum type; - std::chrono::steady_clock::time_point start; + class StatsRecorder{ + using Queue = moodycamel::BlockingConcurrentQueue; public: - - static inline void enable(){collectionEnabled=true;}; - static inline void disable(){collectionEnabled=false;}; - static inline bool enabled(){return(collectionEnabled);}; - - RecordSceneTime(SceneStatType type):start{std::chrono::steady_clock::now()}, type{type} {} - - ~RecordSceneTime() - { - auto val = std::chrono::duration(std::chrono::steady_clock::now() - start).count(); - stats[writeBuffer][static_cast(type)] += val; - }; - - static inline void toggleBuffer() + static inline StatsRecorder& getInstance() { - if(enabled()) - { - // stats[writeBuffer][static_cast(SceneStatType::RENDER_FPS)] = LLTrace::get_frame_recording().getPeriodMeanPerSec(LLStatViewer::FPS,3); // last 3 Frames - writeBuffer = (writeBuffer+1)%2; - }; // not we are relying on atomic updates here. The risk is low and would cause minor errors in the stats display. - - auto& statsArray = stats[writeBuffer]; - std::fill_n(statsArray.begin() ,static_cast(SceneStatType::STATS_COUNT),0); + static StatsRecorder instance; + // volatile int dummy{}; + return instance; } - static inline int getReadBufferIndex(){return (writeBuffer+1)%2;}; - static inline StatsArray getCurrentStatsBuffer(){ return stats[getReadBufferIndex()];} - static inline uint64_t get(StatsEnum type){return stats[getReadBufferIndex()][static_cast(type)];} - }; - - template - class RecordObjectTime - { - using StatsEnum = ObjStatType; - using StatsArray = std::array(StatsEnum::STATS_COUNT)>; - using StatsBlock = std::unordered_map; - static int writeBuffer; - static std::array stats; + static inline void send(const StatsRecord& u){StatsRecorder::getInstance().q.enqueue(u);}; + static inline void endFrame(){StatsRecorder::getInstance().q.enqueue(StatsRecord{});}; - static std::array max; - static std::array sum; + static inline void enable() { collectionEnabled=true; }; + static inline void disable() { collectionEnabled=false; }; + static inline bool enabled() { return(collectionEnabled); }; + + static inline int getReadBufferIndex() { return (writeBuffer ^ 1); }; + // static inline const StatsTypeMatrix& getCurrentStatsMatrix(){ return statsDoubleBuffer[getReadBufferIndex()];} + static inline uint64_t get(ObjType_t otype, LLUUID id, StatType_t type) + { + return statsDoubleBuffer[getReadBufferIndex()][static_cast(otype)][id][static_cast(type)]; + } + static inline uint64_t getSceneStat(StatType_t type) + { + static const LLUUID null_id{}; + return statsDoubleBuffer[getReadBufferIndex()][static_cast(ObjType_t::OT_GENERAL)][null_id][static_cast(type)]; + } + + static inline uint64_t getSum(ObjType_t otype, StatType_t type) + { + return sum[getReadBufferIndex()][static_cast(otype)][static_cast(type)]; + } + static inline uint64_t getMax(ObjType_t otype, StatType_t type) + { + return max[getReadBufferIndex()][static_cast(otype)][static_cast(type)]; + } + private: + StatsRecorder():q(100),t(&StatsRecorder::run) + { + // create a queue + // create a thread to consume from the queue + t.detach(); + } + +// StatsArray is a uint64_t for each possible statistic type. + using StatsArray = std::array(FSPerfStats::StatType_t::STATS_COUNT)>; + using StatsMap = std::unordered_map; + using StatsTypeMatrix = std::array(FSPerfStats::ObjType_t::OT_COUNT)>; + using StatsSummaryArray = std::array(FSPerfStats::ObjType_t::OT_COUNT)>; + + static std::atomic writeBuffer; + static std::array statsDoubleBuffer; + static std::array max; + static std::array sum; static bool collectionEnabled; - RecordObjectTime(const RecordObjectTime&) = delete; - RecordObjectTime() = delete; - const T key; - const StatsEnum type; - std::chrono::steady_clock::time_point start; - public: - static inline void enable(){collectionEnabled=true;}; - static inline void disable(){collectionEnabled=false;}; - static inline bool enabled(){return(collectionEnabled);}; - - RecordObjectTime(T key, ObjStatType type):start{std::chrono::steady_clock::now()}, key{key}, type{type} {} - - ~RecordObjectTime() - { - using ST = StatsEnum; + void processUpdate(const StatsRecord& upd) + { + FSZone; + using ST = StatType_t; // Note: nullptr is used as the key for global stats constexpr auto period{500}; - auto val = std::chrono::duration(std::chrono::steady_clock::now() - start).count(); - if(key) + if(upd.statType == StatType_t::RENDER_GEOMETRY && upd.objType == ObjType_t::OT_GENERAL && upd.objID == LLUUID{} && upd.time == 0) { - stats[writeBuffer][key][static_cast(type)] += val; - stats[writeBuffer][key][static_cast(ST::RENDER_COMBINED)] += val; - if(max[writeBuffer][static_cast(type)] < stats[writeBuffer][key][static_cast(type)]) - { - max[writeBuffer][static_cast(type)] = stats[writeBuffer][key][static_cast(type)]; - } - if(max[writeBuffer][static_cast(ST::RENDER_COMBINED)] < stats[writeBuffer][key][static_cast(ST::RENDER_COMBINED)]) - { - max[writeBuffer][static_cast(ST::RENDER_COMBINED)] = stats[writeBuffer][key][static_cast(ST::RENDER_COMBINED)]; - } - sum[writeBuffer][static_cast(type)] += val; - sum[writeBuffer][static_cast(ST::RENDER_COMBINED)] += val; + toggleBuffer(); + return; } - }; + + StatsMap& stm {statsDoubleBuffer[writeBuffer][static_cast(upd.objType)]}; + auto& key{upd.objID}; + auto val {upd.time}; + auto type {upd.statType}; + FSZoneText(key.asString().c_str(), 36); + FSZoneValue(val); + auto& thisAsset = stm[key]; + thisAsset[static_cast(type)] += val; + thisAsset[static_cast(ST::RENDER_COMBINED)] += val; + FSZoneValue(thisAsset[static_cast(type)]); + sum[writeBuffer][static_cast(upd.objType)][static_cast(type)] += val; + sum[writeBuffer][static_cast(upd.objType)][static_cast(ST::RENDER_COMBINED)] += val; + FSZoneValue(static_cast(upd.objType)); + FSZoneValue(statsDoubleBuffer[writeBuffer][static_cast(upd.objType)][key][static_cast(ST::RENDER_COMBINED)]); + if(max[writeBuffer][static_cast(upd.objType)][static_cast(type)] < stm[key][static_cast(type)]) + { + max[writeBuffer][static_cast(upd.objType)][static_cast(type)] = stm[key][static_cast(type)]; + } + if(max[writeBuffer][static_cast(upd.objType)][static_cast(ST::RENDER_COMBINED)] < stm[key][static_cast(ST::RENDER_COMBINED)]) + { + max[writeBuffer][static_cast(upd.objType)][static_cast(ST::RENDER_COMBINED)] = stm[key][static_cast(ST::RENDER_COMBINED)]; + } + } + static inline void toggleBuffer() { - using ST = StatsEnum; + FSPlot("q size", static_cast(StatsRecorder::getInstance().q.size_approx())); + FSZone; + using ST = StatType_t; - // auto& statsMap = stats[writeBuffer]; - // for(auto& stat_entry : statsMap) - // { - // auto val = stat_entry.second[static_cast(ST::RENDER_COMBINED)]; - // auto avg = stats[(writeBuffer+1)%2][stat_entry.first][static_cast(ST::RENDER_COMBINED)]; - // stat_entry.second[static_cast(ST::RENDER_COMBINED)] = avg + (val/500) - (avg/500); - // } - if(enabled()) - { - writeBuffer = (writeBuffer+1)%2; - }; // note we are relying on atomic updates here. The risk is low and would cause minor errors in the stats display. - auto& statsMap = stats[writeBuffer]; + auto& statsMap = statsDoubleBuffer[writeBuffer][static_cast(ObjType_t::OT_ATTACHMENT)]; for(auto& stat_entry : statsMap) { - std::fill_n(stat_entry.second.begin() ,static_cast(ST::STATS_COUNT),0); + auto val = stat_entry.second[static_cast(ST::RENDER_COMBINED)]; + auto avg = statsDoubleBuffer[writeBuffer ^ 1][static_cast(ObjType_t::OT_ATTACHMENT)][stat_entry.first][static_cast(ST::RENDER_COMBINED)]; + stat_entry.second[static_cast(ST::RENDER_COMBINED)] = avg + (val/100) - (avg/100); + } + if(enabled()) + { + writeBuffer ^= 1; + }; // note we are relying on atomic updates here. The risk is low and would cause minor errors in the stats display. + auto& statsTypeMatrix = statsDoubleBuffer[writeBuffer]; + for(auto& statsMap : statsTypeMatrix) + { + FSZoneN("Clear stats maps"); + for(auto& stat_entry : statsMap) + { + std::fill_n(stat_entry.second.begin() ,static_cast(ST::STATS_COUNT),0); + } + statsMap.clear(); + } + for(int i=0; i< static_cast(ObjType_t::OT_COUNT); i++) + { + FSZoneN("clear max/sum"); + max[writeBuffer][i].fill(0); + sum[writeBuffer][i].fill(0); } - statsMap.clear(); - std::fill_n(max[writeBuffer].begin(),static_cast(ST::STATS_COUNT),0); - std::fill_n(sum[writeBuffer].begin(),static_cast(ST::STATS_COUNT),0); } - static inline int getReadbufferIndex(){return (writeBuffer+1)%2;}; - static inline StatsBlock& getCurrentStatsBuffer(){ return stats[(writeBuffer+1)%2]; } - static inline uint64_t getMax(StatsEnum type){return max[(writeBuffer+1)%2][static_cast(type)];} - static inline uint64_t getSum(StatsEnum type){return sum[(writeBuffer+1)%2][static_cast(type)];} - static inline uint64_t getNum(){return stats[(writeBuffer+1)%2].size();} - static inline uint64_t get(T key, StatsEnum type){return stats[(writeBuffer+1)%2][key][static_cast(type)];} - }; - template - class RecordAttachmentTime + + + + static void run() + { + StatsRecord upd; + auto& instance {StatsRecorder::getInstance()}; + FSThreadName( "PerfStats" ); + + while( !LLApp::isExiting() ) + { + if(instance.q.wait_dequeue_timed(upd, std::chrono::milliseconds(5))) + { + instance.processUpdate(upd); + } + } + } + + Queue q; + std::thread t; + + ~StatsRecorder() = default; + StatsRecorder(const StatsRecorder&) = delete; + StatsRecorder& operator=(const StatsRecorder&) = delete; + + }; + + // std::chrono::duration getTime(){ + + // auto begin= std::chrono::system_clock::now(); + // for ( size_t i= 0; i <= tenMill; ++i){ + // StatsRecorder::getInstance(); + // } + // return std::chrono::system_clock::now() - begin; + + // }; + + template + class RecordTime { - using StatsEnum = ObjStatType; - using StatsArray = std::array(StatsEnum::STATS_COUNT)>; - using StatsBlock = std::unordered_map; - static int writeBuffer; - static std::array stats; - - static std::array max; - static std::array sum; - static bool collectionEnabled; - - RecordAttachmentTime(const RecordAttachmentTime&) = delete; - RecordAttachmentTime() = delete; - const T key; - const StatsEnum type; - std::chrono::steady_clock::time_point start; + private: + RecordTime(const RecordTime&) = delete; + RecordTime() = delete; + const StatType_t type; + const decltype(ObjType) objType; + const LLUUID objID; + U64 start; + RecordTime( StatType_t type ){};// public: + static inline void enable(){collectionEnabled=true;}; static inline void disable(){collectionEnabled=false;}; static inline bool enabled(){return(collectionEnabled);}; - RecordAttachmentTime(T key, ObjStatType type):start{std::chrono::steady_clock::now()}, key{key}, type{type} {} - ~RecordAttachmentTime() + RecordTime( const LLUUID id, StatType_t type ):start{LLTimer::getCurrentClockCount()}, type{type}, objType{ObjType}, objID{id}{}; + + ~RecordTime() { - using ST = StatsEnum; - // Note: nullptr is used as the key for global stats - auto val = std::chrono::duration(std::chrono::steady_clock::now() - start).count(); - stats[writeBuffer][key][static_cast(type)] += val; - stats[writeBuffer][key][static_cast(ST::RENDER_COMBINED)] += val; - if(max[writeBuffer][static_cast(type)] < stats[writeBuffer][key][static_cast(type)]) - { - max[writeBuffer][static_cast(type)] = stats[writeBuffer][key][static_cast(type)]; - } - if(max[writeBuffer][static_cast(ST::RENDER_COMBINED)] < stats[writeBuffer][key][static_cast(ST::RENDER_COMBINED)]) - { - max[writeBuffer][static_cast(ST::RENDER_COMBINED)] = stats[writeBuffer][key][static_cast(ST::RENDER_COMBINED)]; - } - sum[writeBuffer][static_cast(type)] += val; - sum[writeBuffer][static_cast(ST::RENDER_COMBINED)] += val; + FSZoneC(tracy::Color::Red); + auto val = LLTimer::getCurrentClockCount() - start; + FSZoneValue(val); + FSZoneValue(static_cast(objType)); + FSZoneText(objID.asString().c_str(), 36); + StatsRecord stat{type, objType, objID, val}; + StatsRecorder::send(std::move(stat)); }; - static inline void toggleBuffer() - { - using ST = StatsEnum; - if(enabled()) - { - writeBuffer = (writeBuffer+1)%2; - }; // note we are relying on atomic updates here. The risk is low and would cause minor errors in the stats display. - auto& statsMap = stats[writeBuffer]; - for(auto& stat_entry : statsMap) - { - std::fill_n(stat_entry.second.begin() ,static_cast(ST::STATS_COUNT),0); - } - statsMap.clear(); - std::fill_n(max[writeBuffer].begin(),static_cast(ST::STATS_COUNT),0); - std::fill_n(sum[writeBuffer].begin(),static_cast(ST::STATS_COUNT),0); - } - static inline int getReadbufferIndex(){return (writeBuffer+1)%2;}; - static inline StatsBlock& getCurrentStatsBuffer(){ return stats[(writeBuffer+1)%2]; } - static inline uint64_t getMax(StatsEnum type){return max[(writeBuffer+1)%2][static_cast(type)];} - static inline uint64_t getSum(StatsEnum type){return sum[(writeBuffer+1)%2][static_cast(type)];} - static inline uint64_t getNum(){return stats[(writeBuffer+1)%2].size();} - static inline uint64_t get(T key, StatsEnum type){return stats[(writeBuffer+1)%2][key][static_cast(type)];} + }; - - static inline void toggleBuffer() - { - // RecordObjectTime::toggleBuffer(); - RecordSceneTime::toggleBuffer(); - } - template< typename T > - int RecordObjectTime::writeBuffer{0}; + inline double raw_to_ns(U64 raw) { return (static_cast(raw) * 1000000000.0) * get_timer_info().mClockFrequencyInv; }; + inline double raw_to_us(U64 raw) { return (static_cast(raw) * 1000000.0) * get_timer_info().mClockFrequencyInv; }; + inline double raw_to_ms(U64 raw) { return (static_cast(raw) * 1000.0) * get_timer_info().mClockFrequencyInv; }; - template< typename T > - bool RecordObjectTime::collectionEnabled{true}; - - template< typename T > - std::array< typename RecordObjectTime< T >::StatsArray, 2 > RecordObjectTime::max; - - template< typename T > - std::array< typename RecordObjectTime< T >::StatsArray, 2 > RecordObjectTime::sum; - - template< typename T > - std::array< typename RecordObjectTime< T >::StatsBlock, 2 > RecordObjectTime< T >::stats{ {{}} }; - - template< typename T > - int RecordAttachmentTime::writeBuffer{0}; - - template< typename T > - bool RecordAttachmentTime::collectionEnabled{true}; - - template< typename T > - std::array< typename RecordAttachmentTime< T >::StatsArray, 2 > RecordAttachmentTime::max; - - template< typename T > - std::array< typename RecordAttachmentTime< T >::StatsArray, 2 > RecordAttachmentTime::sum; - - template< typename T > - std::array< typename RecordAttachmentTime< T >::StatsBlock, 2 > RecordAttachmentTime< T >::stats{ {{}} }; + using RecordSceneTime = RecordTime; + using RecordAvatarTime = RecordTime; + using RecordAttachmentTime = RecordTime; + }// namespace FSPerfStats - - - - +// helper function +using RATptr = std::unique_ptr; +template +static inline RATptr trackMyAttachment(const T * vobj) +{ + if( !vobj ){return nullptr;}; + const T* rootAtt{vobj}; + if( rootAtt->isAttachment() ) + { + FSZone; + while( !rootAtt->isRootEdit() ) + { + rootAtt = (T*)(rootAtt->getParent()); + } + if( ((T*)(rootAtt->getParent()))->getID() == gAgentID ) + { + #if TRACY_ENABLE + FSZoneNC( "trackMyAttachment:self", tracy::Color::Red ); + auto& str = rootAtt->getAttachmentItemName(); + FSZoneText(str.c_str(), str.size()); + FSZoneText( rootAtt->getAttachmentItemID().asString().c_str(), 36); + #endif + return( std::make_unique( rootAtt->getAttachmentItemID(), FSPerfStats::StatType_t::RENDER_GEOMETRY) ); + } + } + return nullptr; +}; +// #endif \ No newline at end of file diff --git a/indra/llcommon/fstelemetry.h b/indra/llcommon/fstelemetry.h index ca9d33f9fe..5ab1b101dc 100644 --- a/indra/llcommon/fstelemetry.h +++ b/indra/llcommon/fstelemetry.h @@ -43,6 +43,8 @@ #define FSZoneN( name ) ZoneNamedN( ___tracy_scoped_zone, name, FSTelemetry::active) #define FSZoneC( color ) ZoneNamedC( ___tracy_scoped_zone, color, FSTelemetry::active) #define FSZoneNC( name, color ) ZoneNamedNC( ___tracy_scoped_zone, name, color, FSTelemetry::active) +#define FSZoneText( text, size ) ZoneText( text, size ) +#define FSZoneValue( num_uint64 ) ZoneValue( num_uint64 ) #define FSPlot( name, value ) TracyPlot( name, value) #define FSFrameMark FrameMark #define FSThreadName( name ) tracy::SetThreadName( name ) @@ -58,10 +60,12 @@ #define FSZoneN( name ) #define FSZoneC( color ) #define FSZoneNC( name, color ) +#define FSZoneText( text, size ) +#define FSZoneValue( num_uint64 ) #define FSPlot( name, value ) #define FSFrameMark #define FSThreadName( name ) -#define FSMessageL ( message ) +#define FSMessageL( message ) #define FSTelemetryIsConnected #endif // TRACY_ENABLE diff --git a/indra/llcommon/lightweightsemaphore.h b/indra/llcommon/lightweightsemaphore.h new file mode 100644 index 0000000000..b0f24e1cd8 --- /dev/null +++ b/indra/llcommon/lightweightsemaphore.h @@ -0,0 +1,411 @@ +// Provides an efficient implementation of a semaphore (LightweightSemaphore). +// This is an extension of Jeff Preshing's sempahore implementation (licensed +// under the terms of its separate zlib license) that has been adapted and +// extended by Cameron Desrochers. + +#pragma once + +#include // For std::size_t +#include +#include // For std::make_signed + +#if defined(_WIN32) +// Avoid including windows.h in a header; we only need a handful of +// items, so we'll redeclare them here (this is relatively safe since +// the API generally has to remain stable between Windows versions). +// I know this is an ugly hack but it still beats polluting the global +// namespace with thousands of generic names or adding a .cpp for nothing. +extern "C" { + struct _SECURITY_ATTRIBUTES; + __declspec(dllimport) void* __stdcall CreateSemaphoreW(_SECURITY_ATTRIBUTES* lpSemaphoreAttributes, long lInitialCount, long lMaximumCount, const wchar_t* lpName); + __declspec(dllimport) int __stdcall CloseHandle(void* hObject); + __declspec(dllimport) unsigned long __stdcall WaitForSingleObject(void* hHandle, unsigned long dwMilliseconds); + __declspec(dllimport) int __stdcall ReleaseSemaphore(void* hSemaphore, long lReleaseCount, long* lpPreviousCount); +} +#elif defined(__MACH__) +#include +#elif defined(__unix__) +#include +#endif + +namespace moodycamel +{ +namespace details +{ + +// Code in the mpmc_sema namespace below is an adaptation of Jeff Preshing's +// portable + lightweight semaphore implementations, originally from +// https://github.com/preshing/cpp11-on-multicore/blob/master/common/sema.h +// LICENSE: +// Copyright (c) 2015 Jeff Preshing +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgement in the product documentation would be +// appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source distribution. +#if defined(_WIN32) +class Semaphore +{ +private: + void* m_hSema; + + Semaphore(const Semaphore& other) MOODYCAMEL_DELETE_FUNCTION; + Semaphore& operator=(const Semaphore& other) MOODYCAMEL_DELETE_FUNCTION; + +public: + Semaphore(int initialCount = 0) + { + assert(initialCount >= 0); + const long maxLong = 0x7fffffff; + m_hSema = CreateSemaphoreW(nullptr, initialCount, maxLong, nullptr); + assert(m_hSema); + } + + ~Semaphore() + { + CloseHandle(m_hSema); + } + + bool wait() + { + const unsigned long infinite = 0xffffffff; + return WaitForSingleObject(m_hSema, infinite) == 0; + } + + bool try_wait() + { + return WaitForSingleObject(m_hSema, 0) == 0; + } + + bool timed_wait(std::uint64_t usecs) + { + return WaitForSingleObject(m_hSema, (unsigned long)(usecs / 1000)) == 0; + } + + void signal(int count = 1) + { + while (!ReleaseSemaphore(m_hSema, count, nullptr)); + } +}; +#elif defined(__MACH__) +//--------------------------------------------------------- +// Semaphore (Apple iOS and OSX) +// Can't use POSIX semaphores due to http://lists.apple.com/archives/darwin-kernel/2009/Apr/msg00010.html +//--------------------------------------------------------- +class Semaphore +{ +private: + semaphore_t m_sema; + + Semaphore(const Semaphore& other) MOODYCAMEL_DELETE_FUNCTION; + Semaphore& operator=(const Semaphore& other) MOODYCAMEL_DELETE_FUNCTION; + +public: + Semaphore(int initialCount = 0) + { + assert(initialCount >= 0); + kern_return_t rc = semaphore_create(mach_task_self(), &m_sema, SYNC_POLICY_FIFO, initialCount); + assert(rc == KERN_SUCCESS); + (void)rc; + } + + ~Semaphore() + { + semaphore_destroy(mach_task_self(), m_sema); + } + + bool wait() + { + return semaphore_wait(m_sema) == KERN_SUCCESS; + } + + bool try_wait() + { + return timed_wait(0); + } + + bool timed_wait(std::uint64_t timeout_usecs) + { + mach_timespec_t ts; + ts.tv_sec = static_cast(timeout_usecs / 1000000); + ts.tv_nsec = static_cast((timeout_usecs % 1000000) * 1000); + + // added in OSX 10.10: https://developer.apple.com/library/prerelease/mac/documentation/General/Reference/APIDiffsMacOSX10_10SeedDiff/modules/Darwin.html + kern_return_t rc = semaphore_timedwait(m_sema, ts); + return rc == KERN_SUCCESS; + } + + void signal() + { + while (semaphore_signal(m_sema) != KERN_SUCCESS); + } + + void signal(int count) + { + while (count-- > 0) + { + while (semaphore_signal(m_sema) != KERN_SUCCESS); + } + } +}; +#elif defined(__unix__) +//--------------------------------------------------------- +// Semaphore (POSIX, Linux) +//--------------------------------------------------------- +class Semaphore +{ +private: + sem_t m_sema; + + Semaphore(const Semaphore& other) MOODYCAMEL_DELETE_FUNCTION; + Semaphore& operator=(const Semaphore& other) MOODYCAMEL_DELETE_FUNCTION; + +public: + Semaphore(int initialCount = 0) + { + assert(initialCount >= 0); + int rc = sem_init(&m_sema, 0, static_cast(initialCount)); + assert(rc == 0); + (void)rc; + } + + ~Semaphore() + { + sem_destroy(&m_sema); + } + + bool wait() + { + // http://stackoverflow.com/questions/2013181/gdb-causes-sem-wait-to-fail-with-eintr-error + int rc; + do { + rc = sem_wait(&m_sema); + } while (rc == -1 && errno == EINTR); + return rc == 0; + } + + bool try_wait() + { + int rc; + do { + rc = sem_trywait(&m_sema); + } while (rc == -1 && errno == EINTR); + return rc == 0; + } + + bool timed_wait(std::uint64_t usecs) + { + struct timespec ts; + const int usecs_in_1_sec = 1000000; + const int nsecs_in_1_sec = 1000000000; + clock_gettime(CLOCK_REALTIME, &ts); + ts.tv_sec += (time_t)(usecs / usecs_in_1_sec); + ts.tv_nsec += (long)(usecs % usecs_in_1_sec) * 1000; + // sem_timedwait bombs if you have more than 1e9 in tv_nsec + // so we have to clean things up before passing it in + if (ts.tv_nsec >= nsecs_in_1_sec) { + ts.tv_nsec -= nsecs_in_1_sec; + ++ts.tv_sec; + } + + int rc; + do { + rc = sem_timedwait(&m_sema, &ts); + } while (rc == -1 && errno == EINTR); + return rc == 0; + } + + void signal() + { + while (sem_post(&m_sema) == -1); + } + + void signal(int count) + { + while (count-- > 0) + { + while (sem_post(&m_sema) == -1); + } + } +}; +#else +#error Unsupported platform! (No semaphore wrapper available) +#endif + +} // end namespace details + + +//--------------------------------------------------------- +// LightweightSemaphore +//--------------------------------------------------------- +class LightweightSemaphore +{ +public: + typedef std::make_signed::type ssize_t; + +private: + std::atomic m_count; + details::Semaphore m_sema; + int m_maxSpins; + + bool waitWithPartialSpinning(std::int64_t timeout_usecs = -1) + { + ssize_t oldCount; + int spin = m_maxSpins; + while (--spin >= 0) + { + oldCount = m_count.load(std::memory_order_relaxed); + if ((oldCount > 0) && m_count.compare_exchange_strong(oldCount, oldCount - 1, std::memory_order_acquire, std::memory_order_relaxed)) + return true; + std::atomic_signal_fence(std::memory_order_acquire); // Prevent the compiler from collapsing the loop. + } + oldCount = m_count.fetch_sub(1, std::memory_order_acquire); + if (oldCount > 0) + return true; + if (timeout_usecs < 0) + { + if (m_sema.wait()) + return true; + } + if (timeout_usecs > 0 && m_sema.timed_wait((std::uint64_t)timeout_usecs)) + return true; + // At this point, we've timed out waiting for the semaphore, but the + // count is still decremented indicating we may still be waiting on + // it. So we have to re-adjust the count, but only if the semaphore + // wasn't signaled enough times for us too since then. If it was, we + // need to release the semaphore too. + while (true) + { + oldCount = m_count.load(std::memory_order_acquire); + if (oldCount >= 0 && m_sema.try_wait()) + return true; + if (oldCount < 0 && m_count.compare_exchange_strong(oldCount, oldCount + 1, std::memory_order_relaxed, std::memory_order_relaxed)) + return false; + } + } + + ssize_t waitManyWithPartialSpinning(ssize_t max, std::int64_t timeout_usecs = -1) + { + assert(max > 0); + ssize_t oldCount; + int spin = m_maxSpins; + while (--spin >= 0) + { + oldCount = m_count.load(std::memory_order_relaxed); + if (oldCount > 0) + { + ssize_t newCount = oldCount > max ? oldCount - max : 0; + if (m_count.compare_exchange_strong(oldCount, newCount, std::memory_order_acquire, std::memory_order_relaxed)) + return oldCount - newCount; + } + std::atomic_signal_fence(std::memory_order_acquire); + } + oldCount = m_count.fetch_sub(1, std::memory_order_acquire); + if (oldCount <= 0) + { + if ((timeout_usecs == 0) || (timeout_usecs < 0 && !m_sema.wait()) || (timeout_usecs > 0 && !m_sema.timed_wait((std::uint64_t)timeout_usecs))) + { + while (true) + { + oldCount = m_count.load(std::memory_order_acquire); + if (oldCount >= 0 && m_sema.try_wait()) + break; + if (oldCount < 0 && m_count.compare_exchange_strong(oldCount, oldCount + 1, std::memory_order_relaxed, std::memory_order_relaxed)) + return 0; + } + } + } + if (max > 1) + return 1 + tryWaitMany(max - 1); + return 1; + } + +public: + LightweightSemaphore(ssize_t initialCount = 0, int maxSpins = 10000) : m_count(initialCount), m_maxSpins(maxSpins) + { + assert(initialCount >= 0); + assert(maxSpins >= 0); + } + + bool tryWait() + { + ssize_t oldCount = m_count.load(std::memory_order_relaxed); + while (oldCount > 0) + { + if (m_count.compare_exchange_weak(oldCount, oldCount - 1, std::memory_order_acquire, std::memory_order_relaxed)) + return true; + } + return false; + } + + bool wait() + { + return tryWait() || waitWithPartialSpinning(); + } + + bool wait(std::int64_t timeout_usecs) + { + return tryWait() || waitWithPartialSpinning(timeout_usecs); + } + + // Acquires between 0 and (greedily) max, inclusive + ssize_t tryWaitMany(ssize_t max) + { + assert(max >= 0); + ssize_t oldCount = m_count.load(std::memory_order_relaxed); + while (oldCount > 0) + { + ssize_t newCount = oldCount > max ? oldCount - max : 0; + if (m_count.compare_exchange_weak(oldCount, newCount, std::memory_order_acquire, std::memory_order_relaxed)) + return oldCount - newCount; + } + return 0; + } + + // Acquires at least one, and (greedily) at most max + ssize_t waitMany(ssize_t max, std::int64_t timeout_usecs) + { + assert(max >= 0); + ssize_t result = tryWaitMany(max); + if (result == 0 && max > 0) + result = waitManyWithPartialSpinning(max, timeout_usecs); + return result; + } + + ssize_t waitMany(ssize_t max) + { + ssize_t result = waitMany(max, -1); + assert(result > 0); + return result; + } + + void signal(ssize_t count = 1) + { + assert(count >= 0); + ssize_t oldCount = m_count.fetch_add(count, std::memory_order_release); + ssize_t toRelease = -oldCount < count ? -oldCount : count; + if (toRelease > 0) + { + m_sema.signal((int)toRelease); + } + } + + std::size_t availableApprox() const + { + ssize_t count = m_count.load(std::memory_order_relaxed); + return count > 0 ? static_cast(count) : 0; + } +}; + +} // end namespace moodycamel diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index b74d5a58c5..cd81d0b5f2 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -1633,7 +1633,7 @@ bool LLAppViewer::frame() bool LLAppViewer::doFrame() { { - FSPerfStats::RecordSceneTime T (FSPerfStats::SceneStatType::RENDER_FRAME); + FSPerfStats::RecordSceneTime T (const LLUUID{}, FSPerfStats::StatType_t::RENDER_FRAME); LLEventPump& mainloop(LLEventPumps::instance().obtain("mainloop")); LLSD newFrame; @@ -1771,7 +1771,7 @@ bool LLAppViewer::doFrame() // Update state based on messages, user input, object idle. { - FSPerfStats::RecordSceneTime T (FSPerfStats::SceneStatType::RENDER_IDLE); + FSPerfStats::RecordSceneTime T (const LLUUID{}, FSPerfStats::StatType_t::RENDER_IDLE); pauseMainloopTimeout(); // *TODO: Remove. Messages shouldn't be stalling for 20+ seconds! @@ -1851,7 +1851,7 @@ bool LLAppViewer::doFrame() // of equal priority on Windows if (milliseconds_to_sleep > 0) { - FSPerfStats::RecordSceneTime T ( FSPerfStats::SceneStatType::RENDER_SLEEP ); + FSPerfStats::RecordSceneTime T ( LLUUID{}, FSPerfStats::StatType_t::RENDER_SLEEP ); ms_sleep(milliseconds_to_sleep); // also pause worker threads during this wait period LLAppViewer::getTextureCache()->pause(); @@ -1929,7 +1929,7 @@ bool LLAppViewer::doFrame() if (fsLimitFramerate && LLStartUp::getStartupState() == STATE_STARTED && !gTeleportDisplay && !logoutRequestSent() && max_fps > F_APPROXIMATELY_ZERO) { // Sleep a while to limit frame rate. - FSPerfStats::RecordSceneTime T (FSPerfStats::SceneStatType::RENDER_FPSLIMIT); + FSPerfStats::RecordSceneTime T (const LLUUID{}, FSPerfStats::StatType_t::RENDER_FPSLIMIT); F32 min_frame_time = 1.f / (F32)max_fps; S32 milliseconds_to_sleep = llclamp((S32)((min_frame_time - frameTimer.getElapsedTimeF64()) * 1000.f), 0, 1000); if (milliseconds_to_sleep > 0) @@ -1970,9 +1970,7 @@ bool LLAppViewer::doFrame() FSFrameMark; // Tracy support delineate Frame LLPROFILE_UPDATE(); } - FSPerfStats::RecordSceneTime::toggleBuffer(); - FSPerfStats::RecordObjectTime::toggleBuffer(); - FSPerfStats::RecordAttachmentTime::toggleBuffer(); + FSPerfStats::StatsRecorder::endFrame(); return ! LLApp::isRunning(); } diff --git a/indra/newview/lldrawpool.cpp b/indra/newview/lldrawpool.cpp index 8224394b14..373e86cbb9 100644 --- a/indra/newview/lldrawpool.cpp +++ b/indra/newview/lldrawpool.cpp @@ -453,24 +453,15 @@ void LLRenderPass::applyModelMatrix(const LLDrawInfo& params) void LLRenderPass::pushBatch(LLDrawInfo& params, U32 mask, BOOL texture, BOOL batch_textures) { + FSZone; // Capture render times - LLViewerObject* rootAtt{}; - std::unique_ptr> T{}; + std::unique_ptr T{}; if(params.mFace) { - LLViewerObject* vobj = (LLViewerObject *)params.mFace->getViewerObject(); - + LLViewerObject* vobj = params.mFace->getViewerObject(); if(vobj->isAttachment()) { - auto par = (LLViewerObject*)vobj->getParent(); - rootAtt = vobj; - while( par->isAttachment() ) - { - rootAtt = par; - par = (LLViewerObject*)par->getParent(); - } - LL_INFOS() << "pushBatch recording time for ATT@" << rootAtt << " " << (rootAtt?rootAtt->getAttachmentItemName():"null") << " as " << rootAtt->getAttachmentItemID().getCRC32() << LL_ENDL; - if(rootAtt){T = std::unique_ptr>(new FSPerfStats::RecordAttachmentTime(rootAtt->getAttachmentItemID().getCRC32(), FSPerfStats::ObjStatType::RENDER_GEOMETRY));} + T = trackMyAttachment( vobj ); } } // diff --git a/indra/newview/lldrawpoolalpha.cpp b/indra/newview/lldrawpoolalpha.cpp index 3fbcab9d4a..932c0957f9 100644 --- a/indra/newview/lldrawpoolalpha.cpp +++ b/indra/newview/lldrawpoolalpha.cpp @@ -342,6 +342,7 @@ void LLDrawPoolAlpha::render(S32 pass) void LLDrawPoolAlpha::renderAlphaHighlight(U32 mask) { + FSZone; for (LLCullResult::sg_iterator i = gPipeline.beginAlphaGroups(); i != gPipeline.endAlphaGroups(); ++i) { LLSpatialGroup* group = *i; @@ -354,23 +355,13 @@ void LLDrawPoolAlpha::renderAlphaHighlight(U32 mask) { LLDrawInfo& params = **k; // Capture render times - std::unique_ptr> T{}; + std::unique_ptr T{}; if(params.mFace) { - LLViewerObject* rootAtt{}; LLViewerObject* vobj = (LLViewerObject *)params.mFace->getViewerObject(); - if(vobj->isAttachment()) { - auto par = (LLViewerObject*)vobj->getParent(); - rootAtt = vobj; - while( par->isAttachment() ) - { - rootAtt = par; - par = (LLViewerObject*)par->getParent(); - } - LL_INFOS() << "recording time for ATT@" << rootAtt << " " << (rootAtt?rootAtt->getAttachmentItemName():"null") << " as " << rootAtt->getAttachmentItemID().getCRC32() << LL_ENDL; - if(rootAtt){T = std::unique_ptr>(new FSPerfStats::RecordAttachmentTime(rootAtt->getAttachmentItemID().getCRC32(), FSPerfStats::ObjStatType::RENDER_GEOMETRY));} + T = trackMyAttachment(vobj); } } // @@ -499,6 +490,7 @@ void LLDrawPoolAlpha::RestoreTexSetup(bool tex_setup) void LLDrawPoolAlpha::renderSimples(U32 mask, std::vector& simples) { + FSZone; gPipeline.enableLightsDynamic(); simple_shader->bind(); simple_shader->bindTexture(LLShaderMgr::BUMP_MAP, LLViewerFetchedTexture::sFlatNormalImagep); @@ -509,6 +501,15 @@ void LLDrawPoolAlpha::renderSimples(U32 mask, std::vector& simples) bool use_shaders = gPipeline.canUseVertexShaders(); for (LLDrawInfo* draw : simples) { + // Capture render times + FSZoneN("Simples"); + std::unique_ptr T{}; + auto vobj = draw->mFace?draw->mFace->getViewerObject():nullptr; + if(vobj && vobj->isAttachment()) + { + T = trackMyAttachment(vobj); + } + // bool tex_setup = TexSetup(draw, use_shaders, false, simple_shader); LLGLEnableFunc stencil_test(GL_STENCIL_TEST, draw->mSelected, &LLGLCommonFunc::selected_stencil_test); gGL.blendFunc((LLRender::eBlendFactor) draw->mBlendFuncSrc, (LLRender::eBlendFactor) draw->mBlendFuncDst, mAlphaSFactor, mAlphaDFactor); @@ -527,6 +528,15 @@ void LLDrawPoolAlpha::renderFullbrights(U32 mask, std::vector& full bool use_shaders = gPipeline.canUseVertexShaders(); for (LLDrawInfo* draw : fullbrights) { + // Capture render times + FSZoneN("Fullbrights"); + std::unique_ptr T{}; + auto vobj = draw->mFace?draw->mFace->getViewerObject():nullptr; + if(vobj && vobj->isAttachment()) + { + T = trackMyAttachment(vobj); + } + // bool tex_setup = TexSetup(draw, use_shaders, false, fullbright_shader); LLGLEnableFunc stencil_test(GL_STENCIL_TEST, draw->mSelected, &LLGLCommonFunc::selected_stencil_test); @@ -547,6 +557,16 @@ void LLDrawPoolAlpha::renderMaterials(U32 mask, std::vector& materi bool use_shaders = gPipeline.canUseVertexShaders(); for (LLDrawInfo* draw : materials) { + // Capture render times + FSZoneN("Materials"); + std::unique_ptr T{}; + auto vobj = draw->mFace?draw->mFace->getViewerObject():nullptr; + if(vobj && vobj->isAttachment()) + { + T = trackMyAttachment(vobj); + } + // + U32 mask = draw->mShaderMask; llassert(mask < LLMaterial::SHADER_COUNT); @@ -629,6 +649,16 @@ void LLDrawPoolAlpha::renderEmissives(U32 mask, std::vector& emissi bool use_shaders = gPipeline.canUseVertexShaders(); for (LLDrawInfo* draw : emissives) { + // Capture render times + FSZoneN("Emissives"); + std::unique_ptr T{}; + auto vobj = draw->mFace?draw->mFace->getViewerObject():nullptr; + if(vobj && vobj->isAttachment()) + { + T = trackMyAttachment(vobj); + } + // + bool tex_setup = TexSetup(draw, use_shaders, false, emissive_shader); drawEmissive(mask, draw); RestoreTexSetup(tex_setup); @@ -702,23 +732,14 @@ void LLDrawPoolAlpha::renderAlpha(U32 mask, S32 pass) } // Capture render times - std::unique_ptr> T{}; + std::unique_ptr T{}; if(params.mFace) { - LLViewerObject* rootAtt{}; LLViewerObject* vobj = (LLViewerObject *)params.mFace->getViewerObject(); if(vobj->isAttachment()) { - auto par = (LLViewerObject*)vobj->getParent(); - rootAtt = vobj; - while( par->isAttachment() ) - { - rootAtt = par; - par = (LLViewerObject*)par->getParent(); - } - LL_INFOS() << "ALPHA recording time for ATT@" << rootAtt << " " << (rootAtt?rootAtt->getAttachmentItemName():"null") << " as " << rootAtt->getAttachmentItemID().getCRC32() << LL_ENDL; - if(rootAtt){T = std::unique_ptr>(new FSPerfStats::RecordAttachmentTime(rootAtt->getAttachmentItemID().getCRC32(), FSPerfStats::ObjStatType::RENDER_GEOMETRY));} + T = trackMyAttachment(vobj); } } // diff --git a/indra/newview/lldrawpoolavatar.cpp b/indra/newview/lldrawpoolavatar.cpp index 51fd2760d0..8ea7b3338b 100644 --- a/indra/newview/lldrawpoolavatar.cpp +++ b/indra/newview/lldrawpoolavatar.cpp @@ -581,7 +581,7 @@ void LLDrawPoolAvatar::renderShadow(S32 pass) { return; } - FSPerfStats::RecordObjectTime T(avatarp, FSPerfStats::ObjStatType::RENDER_SHADOWS); + FSPerfStats::RecordAvatarTime T(avatarp->getID(), FSPerfStats::StatType_t::RENDER_SHADOWS); LLVOAvatar::AvatarOverallAppearance oa = avatarp->getOverallAppearance(); BOOL impostor = !LLPipeline::sImpostorRender && avatarp->isImpostor(); @@ -1504,7 +1504,7 @@ void LLDrawPoolAvatar::renderAvatars(LLVOAvatar* single_avatar, S32 pass) { return; } - FSPerfStats::RecordObjectTime T(avatarp, FSPerfStats::ObjStatType::RENDER_GEOMETRY); + FSPerfStats::RecordAvatarTime T(avatarp->getID(), FSPerfStats::StatType_t::RENDER_GEOMETRY); // Add avatar hitbox debug static LLCachedControl render_hitbox(gSavedSettings, "DebugRenderHitboxes", false); @@ -2282,21 +2282,11 @@ void LLDrawPoolAvatar::renderRigged(LLVOAvatar* avatar, U32 type, bool glow) } auto self = avatar->isSelf(); - LLViewerObject * parentAttachment{nullptr}; + std::unique_ptr T{}; if(self && vobj->isAttachment()) { - LLViewerObject * vtop = vobj; - LLViewerObject * par = (LLViewerObject *) vobj->getParent(); - - while (par && !(par->asAvatar())) - { - vtop = par; - par = (LLViewerObject *)vtop->getParent(); - } - parentAttachment = vtop; + T = trackMyAttachment(vobj); } - FSPerfStats::RecordAttachmentTime T(parentAttachment?parentAttachment->getAttachmentItemID().getCRC32():0, FSPerfStats::ObjStatType::RENDER_GEOMETRY); - LLVolume* volume = vobj->getVolume(); S32 te = face->getTEOffset(); @@ -2612,7 +2602,13 @@ void LLDrawPoolAvatar::updateRiggedVertexBuffers(LLVOAvatar* avatar) { continue; } - + // Capture render times + std::unique_ptr T{}; + if(vobj->isAttachment()) + { + T = trackMyAttachment(vobj); + } + // LLVolume* volume = vobj->getVolume(); S32 te = face->getTEOffset(); diff --git a/indra/newview/lldrawpoolbump.cpp b/indra/newview/lldrawpoolbump.cpp index b8dcdbb0be..a61d7116e7 100644 --- a/indra/newview/lldrawpoolbump.cpp +++ b/indra/newview/lldrawpoolbump.cpp @@ -641,28 +641,20 @@ void LLDrawPoolBump::endFullbrightShiny() } void LLDrawPoolBump::renderGroup(LLSpatialGroup* group, U32 type, U32 mask, BOOL texture = TRUE) -{ +{ + FSZone; LLSpatialGroup::drawmap_elem_t& draw_info = group->mDrawMap[type]; for (LLSpatialGroup::drawmap_elem_t::iterator k = draw_info.begin(); k != draw_info.end(); ++k) { LLDrawInfo& params = **k; // Capture render times - LLViewerObject* rootAtt{}; - std::unique_ptr> T{}; + std::unique_ptr T{}; LLViewerObject* vobj = (LLViewerObject *)params.mFace->getViewerObject(); if(vobj->isAttachment()) { - auto par = (LLViewerObject*)vobj->getParent(); - rootAtt = vobj; - while( par->isAttachment() ) - { - rootAtt = par; - par = (LLViewerObject*)par->getParent(); - } - LL_INFOS() << "recording time for ATT@" << rootAtt << " " << (rootAtt?rootAtt->getAttachmentItemName():"null") << " as " << rootAtt->getAttachmentItemID().getCRC32() << LL_ENDL; - if(rootAtt){T = std::unique_ptr>(new FSPerfStats::RecordAttachmentTime(rootAtt->getAttachmentItemID().getCRC32(), FSPerfStats::ObjStatType::RENDER_GEOMETRY));} + T= trackMyAttachment(vobj); } // applyModelMatrix(params); @@ -1530,24 +1522,16 @@ void LLDrawPoolBump::renderBump(U32 type, U32 mask) void LLDrawPoolBump::pushBatch(LLDrawInfo& params, U32 mask, BOOL texture, BOOL batch_textures) { + FSZone; // Capture render times - std::unique_ptr> T{}; + std::unique_ptr T{}; if(params.mFace) { - LLViewerObject* rootAtt{}; LLViewerObject* vobj = (LLViewerObject *)params.mFace->getViewerObject(); if(vobj->isAttachment()) { - auto par = (LLViewerObject*)vobj->getParent(); - rootAtt = vobj; - while( par->isAttachment() ) - { - rootAtt = par; - par = (LLViewerObject*)par->getParent(); - } - // LL_INFOS() << "recording time for ATT@" << rootAtt << " " << (rootAtt?rootAtt->getAttachmentItemName():"null") << " as " << rootAtt->getAttachmentItemID().getCRC32() << LL_ENDL; - if(rootAtt){T = std::unique_ptr>(new FSPerfStats::RecordAttachmentTime(rootAtt->getAttachmentItemID().getCRC32(), FSPerfStats::ObjStatType::RENDER_GEOMETRY));} + T = trackMyAttachment(vobj); } } // diff --git a/indra/newview/lldrawpoolmaterials.cpp b/indra/newview/lldrawpoolmaterials.cpp index 710cf5f80b..2b1304c9eb 100644 --- a/indra/newview/lldrawpoolmaterials.cpp +++ b/indra/newview/lldrawpoolmaterials.cpp @@ -141,23 +141,14 @@ void LLDrawPoolMaterials::renderDeferred(S32 pass) LLDrawInfo& params = **i; // Capture render times - std::unique_ptr> T{}; + std::unique_ptr T{}; if(params.mFace) { - LLViewerObject* rootAtt{}; LLViewerObject* vobj = (LLViewerObject *)params.mFace->getViewerObject(); if(vobj->isAttachment()) { - auto par = (LLViewerObject*)vobj->getParent(); - rootAtt = vobj; - while( par->isAttachment() ) - { - rootAtt = par; - par = (LLViewerObject*)par->getParent(); - } - LL_INFOS() << "MATERIALS recording time for ATT@" << rootAtt << " " << (rootAtt?rootAtt->getAttachmentItemName():"null") << " as " << rootAtt->getAttachmentItemID().getCRC32() << LL_ENDL; - if(rootAtt){T = std::unique_ptr>(new FSPerfStats::RecordAttachmentTime(rootAtt->getAttachmentItemID().getCRC32(), FSPerfStats::ObjStatType::RENDER_GEOMETRY));} + T = trackMyAttachment(vobj); } } // @@ -196,6 +187,18 @@ void LLDrawPoolMaterials::bindNormalMap(LLViewerTexture* tex) void LLDrawPoolMaterials::pushBatch(LLDrawInfo& params, U32 mask, BOOL texture, BOOL batch_textures) { + // Capture render times + std::unique_ptr T{}; + if(params.mFace) + { + LLViewerObject* vobj = (LLViewerObject *)params.mFace->getViewerObject(); + + if(vobj->isAttachment()) + { + T = trackMyAttachment(vobj); + } + } + // applyModelMatrix(params); bool tex_setup = false; diff --git a/indra/newview/lldrawpoolsimple.cpp b/indra/newview/lldrawpoolsimple.cpp index f211cf6e27..b82b8571c7 100644 --- a/indra/newview/lldrawpoolsimple.cpp +++ b/indra/newview/lldrawpoolsimple.cpp @@ -36,6 +36,7 @@ #include "llspatialpartition.h" #include "llviewershadermgr.h" #include "llrender.h" +#include "fsperfstats.h" static LLGLSLShader* simple_shader = NULL; static LLGLSLShader* fullbright_shader = NULL; @@ -152,6 +153,18 @@ void LLDrawPoolGlow::render(S32 pass) void LLDrawPoolGlow::pushBatch(LLDrawInfo& params, U32 mask, BOOL texture, BOOL batch_textures) { + // Capture render times + std::unique_ptr T{}; + if(params.mFace) + { + LLViewerObject* vobj = (LLViewerObject *)params.mFace->getViewerObject(); + + if(vobj->isAttachment()) + { + T = trackMyAttachment(vobj); + } + } + // //gGL.diffuseColor4ubv(params.mGlowColor.mV); LLRenderPass::pushBatch(params, mask, texture, batch_textures); } diff --git a/indra/newview/lldynamictexture.cpp b/indra/newview/lldynamictexture.cpp index 86c598f70a..8761524e89 100644 --- a/indra/newview/lldynamictexture.cpp +++ b/indra/newview/lldynamictexture.cpp @@ -228,12 +228,15 @@ BOOL LLViewerDynamicTexture::updateAllInstances() BOOL ret = FALSE ; for( S32 order = 0; order < ORDER_COUNT; order++ ) { + FSZone; for (instance_list_t::iterator iter = LLViewerDynamicTexture::sInstances[order].begin(); iter != LLViewerDynamicTexture::sInstances[order].end(); ++iter) { + FSZone; LLViewerDynamicTexture *dynamicTexture = *iter; if (dynamicTexture->needsRender()) - { + { + FSZoneN("needsRender"); glClear(GL_DEPTH_BUFFER_BIT); gDepthDirty = TRUE; @@ -241,13 +244,19 @@ BOOL LLViewerDynamicTexture::updateAllInstances() dynamicTexture->setBoundTarget(use_fbo ? &gPipeline.mBake : nullptr); dynamicTexture->preRender(); // Must be called outside of startRender() result = FALSE; + { + FSZoneN("DynTexture->render"); if (dynamicTexture->render()) { ret = TRUE ; result = TRUE; sNumRenders++; } + } + { + FSZoneN("flush"); gGL.flush(); + } LLVertexBuffer::unbind(); dynamicTexture->setBoundTarget(nullptr); dynamicTexture->postRender(result); diff --git a/indra/newview/llface.cpp b/indra/newview/llface.cpp index e0251f6d23..2bb989fb4f 100644 --- a/indra/newview/llface.cpp +++ b/indra/newview/llface.cpp @@ -643,19 +643,10 @@ void renderFace(LLDrawable* drawable, LLFace *face) LLVOVolume* vobj = drawable->getVOVolume(); if (vobj) { - LLVOVolume* rootAtt{}; - std::unique_ptr> T{}; + std::unique_ptr T{}; if(vobj->isAttachment()) { - auto par = (LLVOVolume*)vobj->getParent(); - rootAtt = vobj; - while( par->isAttachment() ) - { - rootAtt = par; - par = (LLVOVolume*)par->getParent(); - } - // LL_INFOS() << "recording time for ATT@" << rootAtt << " " << (rootAtt?rootAtt->getAttachmentItemName():"null") << LL_ENDL; - if(rootAtt){T = std::unique_ptr>(new FSPerfStats::RecordAttachmentTime(rootAtt->getAttachmentItemID().getCRC32(), FSPerfStats::ObjStatType::RENDER_GEOMETRY));} + T = trackMyAttachment(vobj); } LLVolume* volume = NULL; @@ -1255,6 +1246,11 @@ bool LLFace::canRenderAsMask() { return false; } + + // shortcircuit fully alpha faces + if(getViewerObject()->isHUDAttachment()){return false;}; + if(te->getAlpha() == 0.0f && (te->getGlow() == 0.f)){FSZoneN("beqshortcircuit invisible");return true;} + // LLMaterial* mat = te->getMaterialParams(); if (mat && mat->getDiffuseAlphaMode() == LLMaterial::DIFFUSE_ALPHA_MODE_BLEND) diff --git a/indra/newview/llfloaterperformance.cpp b/indra/newview/llfloaterperformance.cpp index 4a18522244..4ab2d562b8 100644 --- a/indra/newview/llfloaterperformance.cpp +++ b/indra/newview/llfloaterperformance.cpp @@ -53,6 +53,10 @@ const S32 BAR_LEFT_PAD = 2; const S32 BAR_RIGHT_PAD = 5; const S32 BAR_BOTTOM_PAD = 9; +constexpr auto AvType {FSPerfStats::ObjType_t::OT_AVATAR}; +constexpr auto AttType {FSPerfStats::ObjType_t::OT_ATTACHMENT}; +constexpr auto HudType {FSPerfStats::ObjType_t::OT_HUD}; +constexpr auto SceneType {FSPerfStats::ObjType_t::OT_GENERAL}; class LLExceptionsContextMenu : public LLListContextMenu { public: @@ -164,44 +168,58 @@ void LLFloaterPerformance::showSelectedPanel(LLPanel* selected_panel) void LLFloaterPerformance::draw() { const S32 NUM_PERIODS = 50; + constexpr auto NANOS = 1000000000; + constexpr auto MICROS = 1000000; + constexpr auto MILLIS = 1000; + + static LLCachedControl fps_cap(gSavedSettings, "FramePerSecondLimit"); // user limited FPS static LLCachedControl target_fps(gSavedSettings, "FSTargetFPS"); // desired FPS static LLCachedControl auto_tune(gSavedSettings, "FSAutoTuneFPS"); // auto tune enabled? static LLCachedControl max_render_cost(gSavedSettings, "RenderAvatarMaxART", 0); + static auto freq_divisor = get_timer_info().mClockFrequencyInv; if (mUpdateTimer->hasExpired()) { LLStringUtil::format_map_t args; auto fps = LLTrace::get_frame_recording().getPeriodMedianPerSec(LLStatViewer::FPS, NUM_PERIODS); getChild("fps_value")->setValue((S32)llround(fps)); - auto tot_frame_time_ns = 1000000000/fps; - auto target_frame_time_ns = 1000000000/(target_fps==0?1:target_fps); - auto tot_avatar_time = FSPerfStats::RecordObjectTime::getSum(FSPerfStats::ObjStatType::RENDER_COMBINED); - auto tot_huds_time = FSPerfStats::RecordSceneTime::get(FSPerfStats::SceneStatType::RENDER_HUDS) ; - auto tot_sleep_time = FSPerfStats::RecordSceneTime::get(FSPerfStats::SceneStatType::RENDER_SLEEP); - auto tot_ui_time = FSPerfStats::RecordSceneTime::get(FSPerfStats::SceneStatType::RENDER_UI); - auto tot_idle_time = FSPerfStats::RecordSceneTime::get(FSPerfStats::SceneStatType::RENDER_IDLE); - auto tot_limit_time = FSPerfStats::RecordSceneTime::get(FSPerfStats::SceneStatType::RENDER_FPSLIMIT); - auto tot_swap_time = FSPerfStats::RecordSceneTime::get(FSPerfStats::SceneStatType::RENDER_SWAP); + auto tot_frame_time_ns = NANOS/fps; + auto target_frame_time_ns = NANOS/(target_fps==0?1:target_fps); + auto tot_avatar_time_raw = FSPerfStats::StatsRecorder::getSum(AvType, FSPerfStats::StatType_t::RENDER_COMBINED); + auto tot_huds_time_raw = FSPerfStats::StatsRecorder::getSceneStat(FSPerfStats::StatType_t::RENDER_HUDS); + auto tot_sleep_time_raw = FSPerfStats::StatsRecorder::getSceneStat(FSPerfStats::StatType_t::RENDER_SLEEP); + auto tot_ui_time_raw = FSPerfStats::StatsRecorder::getSceneStat(FSPerfStats::StatType_t::RENDER_UI); + auto tot_idle_time_raw = FSPerfStats::StatsRecorder::getSceneStat(FSPerfStats::StatType_t::RENDER_IDLE); + auto tot_limit_time_raw = FSPerfStats::StatsRecorder::getSceneStat(FSPerfStats::StatType_t::RENDER_FPSLIMIT); + auto tot_swap_time_raw = FSPerfStats::StatsRecorder::getSceneStat(FSPerfStats::StatType_t::RENDER_SWAP); - // once the rest is extracted what is left is the scene cost (we don't include non-render activities such as network here prlloy should.) - auto tot_scene_time = tot_frame_time_ns - tot_avatar_time - tot_huds_time - tot_ui_time - tot_sleep_time - tot_limit_time - tot_swap_time; + auto tot_avatar_time_ns = FSPerfStats::raw_to_ns( tot_avatar_time_raw ); + auto tot_huds_time_ns = FSPerfStats::raw_to_ns( tot_huds_time_raw ); + auto tot_sleep_time_ns = FSPerfStats::raw_to_ns( tot_sleep_time_raw ); + auto tot_ui_time_ns = FSPerfStats::raw_to_ns( tot_ui_time_raw ); + auto tot_idle_time_ns = FSPerfStats::raw_to_ns( tot_idle_time_raw ); + auto tot_limit_time_ns = FSPerfStats::raw_to_ns( tot_limit_time_raw ); + auto tot_swap_time_ns = FSPerfStats::raw_to_ns( tot_swap_time_raw ); + + // once the rest is extracted what is left is the scene cost + auto tot_scene_time_ns = tot_frame_time_ns - tot_avatar_time_ns - tot_huds_time_ns - tot_ui_time_ns - tot_sleep_time_ns - tot_limit_time_ns - tot_swap_time_ns - tot_idle_time_ns; // remove time spent sleeping for fps limit or out of focus. - tot_frame_time_ns -= tot_limit_time; - tot_frame_time_ns -= tot_sleep_time; + tot_frame_time_ns -= tot_limit_time_ns; + tot_frame_time_ns -= tot_sleep_time_ns; if(tot_frame_time_ns == 0) { LL_WARNS("performance") << "things went wrong, quit while we can." << LL_ENDL; return; } - auto pct_avatar_time = (tot_avatar_time*100)/tot_frame_time_ns; - auto pct_huds_time = (tot_huds_time*100)/tot_frame_time_ns; - auto pct_ui_time = (tot_ui_time*100)/tot_frame_time_ns; - auto pct_idle_time = (tot_idle_time*100)/tot_frame_time_ns; - auto pct_swap_time = (tot_swap_time*100)/tot_frame_time_ns; - auto pct_scene_time = (tot_scene_time*100)/tot_frame_time_ns; + auto pct_avatar_time = (tot_avatar_time_ns * 100)/tot_frame_time_ns; + auto pct_huds_time = (tot_huds_time_ns * 100)/tot_frame_time_ns; + auto pct_ui_time = (tot_ui_time_ns * 100)/tot_frame_time_ns; + auto pct_idle_time = (tot_idle_time_ns * 100)/tot_frame_time_ns; + auto pct_swap_time = (tot_swap_time_ns * 100)/tot_frame_time_ns; + auto pct_scene_time = (tot_scene_time_ns * 100)/tot_frame_time_ns; args["AV_FRAME_PCT"] = llformat("%02u", (U32)llround(pct_avatar_time)); args["HUDS_FRAME_PCT"] = llformat("%02u", (U32)llround(pct_huds_time)); @@ -217,13 +235,13 @@ void LLFloaterPerformance::draw() getChild("frame_breakdown")->setText(getString("frame_stats", args)); auto textbox = getChild("fps_warning"); - if(tot_sleep_time > 0) // We are sleeping because view is not focussed + if(tot_sleep_time_raw > 0) // We are sleeping because view is not focussed { textbox->setVisible(true); textbox->setText(getString("focus_fps")); textbox->setColor(LLUIColorTable::instance().getColor("DrYellow")); } - else if (tot_limit_time > 0) + else if (tot_limit_time_raw > 0) { textbox->setVisible(true); textbox->setText(getString("limit_fps", args)); @@ -242,11 +260,11 @@ void LLFloaterPerformance::draw() if( auto_tune ) { - auto av_render_max = FSPerfStats::RecordObjectTime::getMax(FSPerfStats::ObjStatType::RENDER_COMBINED); + auto av_render_max_raw = FSPerfStats::StatsRecorder::getMax(AvType, FSPerfStats::StatType_t::RENDER_COMBINED); // if( target_frame_time_ns <= tot_frame_time_ns ) // { - // U32 non_avatar_time_ns = tot_frame_time_ns - tot_avatar_time; + // U32 non_avatar_time_ns = tot_frame_time_ns - tot_avatar_time_raw; // if( non_avatar_time_ns < target_frame_time_ns ) // { // F32 target_avatar_time_ms {F32(target_frame_time_ns-non_avatar_time_ns)/1000000}; @@ -255,33 +273,41 @@ void LLFloaterPerformance::draw() // } // } + // Is our target frame time lower than current? If so we need to take action to reduce draw overheads. if( target_frame_time_ns <= tot_frame_time_ns ) { LL_INFOS() << "AUTO_TUNE: adapting frame rate" << LL_ENDL; - U32 non_avatar_time_ns = tot_frame_time_ns - tot_avatar_time; - LL_INFOS() << "AUTO_TUNE: adapting frame rate: target_frame=" << target_frame_time_ns << " nonav_frame_time=" << non_avatar_time_ns << " headroom=" << target_frame_time_ns - non_avatar_time_ns << LL_ENDL; + U32 non_avatar_time_ns = tot_frame_time_ns - tot_avatar_time_ns; + LL_INFOS() << "AUTO_TUNE: adapting frame rate: target_frame=" << target_frame_time_ns << " nonav_frame_time=" << non_avatar_time_ns << " headroom=" << (S64)target_frame_time_ns - non_avatar_time_ns << LL_ENDL; + // If the target frame time < non avatar frame time then we can pototentially reach it. if( non_avatar_time_ns < target_frame_time_ns ) { U64 target_avatar_time_ns {target_frame_time_ns-non_avatar_time_ns}; LL_INFOS() << "AUTO_TUNE: avatar_budget:" << target_avatar_time_ns << LL_ENDL; - if(target_avatar_time_ns < tot_avatar_time) + if(target_avatar_time_ns < tot_avatar_time_ns) { - F32 new_render_limit = (F32)(av_render_max-100000)/1000000; - if(new_render_limit >= max_render_cost) + F32 new_render_limit_ms = (F32)(FSPerfStats::raw_to_ms(av_render_max_raw)-0.1); + if(new_render_limit_ms >= max_render_cost) { // we caught a bad frame possibly with a forced refresh render. - new_render_limit = max_render_cost - 0.1; + new_render_limit_ms = max_render_cost - 0.1; } - gSavedSettings.setF32( "RenderAvatarMaxART", new_render_limit); - LL_INFOS() << "AUTO_TUNE: avatar_budget adjusted to:" << new_render_limit << LL_ENDL; + gSavedSettings.setF32( "RenderAvatarMaxART", new_render_limit_ms); + LL_INFOS() << "AUTO_TUNE: avatar_budget adjusted to:" << new_render_limit_ms << LL_ENDL; } - LL_INFOS() << "AUTO_TUNE: Target frame time:"<setColor(LLUIColorTable::instance().getColor("red")); } } else if( target_frame_time_ns > (tot_frame_time_ns + max_render_cost)) { - // if we have more space to spare let's shift up little in the hope we'll restore an avatar. + // if we have more time to spare let's shift up little in the hope we'll restore an avatar. gSavedSettings.setF32( "RenderAvatarMaxART", max_render_cost + 0.5 ); } } @@ -339,18 +365,20 @@ 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) { max_complexity = llmax(max_complexity, (*iter).objectsCost); } - auto huds_max_render_time = FSPerfStats::RecordObjectTime::getMax(FSPerfStats::ObjStatType::RENDER_GEOMETRY); + auto huds_max_render_time_raw = FSPerfStats::StatsRecorder::getMax(HudType, FSPerfStats::StatType_t::RENDER_GEOMETRY); for (iter = complexity_list.begin(); iter != end; ++iter) { LLHUDComplexity hud_object_complexity = *iter; auto hud_ptr = hud_object_complexity.objectPtr; - auto hud_render_time = FSPerfStats::RecordObjectTime::get(hud_ptr, FSPerfStats::ObjStatType::RENDER_GEOMETRY); + auto hud_render_time_raw = FSPerfStats::StatsRecorder::get(HudType, hud_ptr->getID(), FSPerfStats::StatType_t::RENDER_GEOMETRY); LLSD item; item["special_id"] = hud_object_complexity.objectId; item["target"] = LLNameListCtrl::SPECIAL; @@ -358,15 +386,15 @@ void LLFloaterPerformance::populateHUDList() row[0]["column"] = "complex_visual"; row[0]["type"] = "bar"; LLSD& value = row[0]["value"]; - value["ratio"] = (F32)hud_render_time / huds_max_render_time; + value["ratio"] = (F32)hud_render_time_raw / huds_max_render_time_raw; value["bottom"] = BAR_BOTTOM_PAD; value["left_pad"] = BAR_LEFT_PAD; value["right_pad"] = BAR_RIGHT_PAD; row[1]["column"] = "complex_value"; row[1]["type"] = "text"; - LL_INFOS() << "HUD : hud[" << hud_ptr << " time:" << hud_render_time <<" total_time:" << huds_max_render_time << LL_ENDL; - row[1]["value"] = llformat("%.2f",((double)hud_render_time / 1000000000)); + LL_INFOS() << "HUD : hud[" << hud_ptr << " time:" << hud_render_time_raw <<" total_time:" << huds_max_render_time_raw << LL_ENDL; + row[1]["value"] = llformat( "%.3f",FSPerfStats::raw_to_us(hud_render_time_raw) ); row[1]["font"]["name"] = "SANSSERIF"; row[2]["column"] = "name"; @@ -401,42 +429,49 @@ void LLFloaterPerformance::populateObjectList() object_complexity_list_t::iterator iter = complexity_list.begin(); object_complexity_list_t::iterator end = complexity_list.end(); + static auto freq_divisor = get_timer_info().mClockFrequencyInv; + U32 max_complexity = 0; for (; iter != end; ++iter) { max_complexity = llmax(max_complexity, (*iter).objectCost); } - auto max_render_time = FSPerfStats::RecordAttachmentTime::getMax(FSPerfStats::ObjStatType::RENDER_GEOMETRY); + auto att_max_render_time_raw = FSPerfStats::StatsRecorder::getMax(AttType, FSPerfStats::StatType_t::RENDER_COMBINED); for (iter = complexity_list.begin(); iter != end; ++iter) { LLObjectComplexity object_complexity = *iter; - // S32 obj_cost_short = llmax((S32)object_complexity.objectCost / 1000, 1); - auto attach_render_time = FSPerfStats::RecordAttachmentTime::get(object_complexity.objectId.getCRC32(), FSPerfStats::ObjStatType::RENDER_GEOMETRY); + S32 obj_cost_short = llmax((S32)object_complexity.objectCost / 1000, 1); + auto attach_render_time_raw = FSPerfStats::StatsRecorder::get(AttType, object_complexity.objectId, FSPerfStats::StatType_t::RENDER_COMBINED); LLSD item; item["special_id"] = object_complexity.objectId; item["target"] = LLNameListCtrl::SPECIAL; LLSD& row = item["columns"]; - row[0]["column"] = "complex_visual"; + row[0]["column"] = "art_visual"; row[0]["type"] = "bar"; LLSD& value = row[0]["value"]; - value["ratio"] = (F32)attach_render_time / max_render_time; + value["ratio"] = (F32)attach_render_time_raw / att_max_render_time_raw; value["bottom"] = BAR_BOTTOM_PAD; value["left_pad"] = BAR_LEFT_PAD; value["right_pad"] = BAR_RIGHT_PAD; - row[1]["column"] = "complex_value"; + row[1]["column"] = "art_value"; row[1]["type"] = "text"; // row[1]["value"] = std::to_string(obj_cost_short); - row[1]["value"] = llformat("%.3f",((double)attach_render_time / 1000000)); + row[1]["value"] = llformat( "%.4f", FSPerfStats::raw_to_us(attach_render_time_raw) ); row[1]["font"]["name"] = "SANSSERIF"; - row[2]["column"] = "name"; + row[2]["column"] = "complex_value"; row[2]["type"] = "text"; - row[2]["value"] = object_complexity.objectName; + row[2]["value"] = std::to_string(obj_cost_short); row[2]["font"]["name"] = "SANSSERIF"; + row[3]["column"] = "name"; + row[3]["type"] = "text"; + row[3]["value"] = object_complexity.objectName; + row[3]["font"]["name"] = "SANSSERIF"; + LLScrollListItem* obj = mObjectList->addElement(item); if (obj) { @@ -467,7 +502,7 @@ void LLFloaterPerformance::populateNearbyList() getNearbyAvatars(valid_nearby_avs); std::vector::iterator char_iter = valid_nearby_avs.begin(); - auto render_max = FSPerfStats::RecordObjectTime::getMax(FSPerfStats::ObjStatType::RENDER_COMBINED); + auto av_render_max_raw = FSPerfStats::StatsRecorder::getMax(AvType, FSPerfStats::StatType_t::RENDER_COMBINED); while (char_iter != valid_nearby_avs.end()) { LLVOAvatar* avatar = dynamic_cast(*char_iter); @@ -477,40 +512,46 @@ void LLFloaterPerformance::populateNearbyList() if(overall_appearance == LLVOAvatar::AOA_INVISIBLE) continue; - // S32 complexity_short = llmax((S32)avatar->getVisualComplexity() / 1000, 1); - auto render_av = FSPerfStats::RecordObjectTime::get(avatar,FSPerfStats::ObjStatType::RENDER_COMBINED); + S32 complexity_short = llmax((S32)avatar->getVisualComplexity() / 1000, 1); + auto render_av_raw = FSPerfStats::StatsRecorder::get(AvType, avatar->getID(),FSPerfStats::StatType_t::RENDER_COMBINED); auto is_slow = avatar->isTooSlow(true); // auto is_slow_without_shadows = avatar->isTooSlow(); LLSD item; item["id"] = avatar->getID(); LLSD& row = item["columns"]; - row[0]["column"] = "complex_visual"; + row[0]["column"] = "art_visual"; row[0]["type"] = "bar"; LLSD& value = row[0]["value"]; - value["ratio"] = (double)render_av / render_max; + value["ratio"] = (double)render_av_raw / av_render_max_raw; value["bottom"] = BAR_BOTTOM_PAD; value["left_pad"] = BAR_LEFT_PAD; value["right_pad"] = BAR_RIGHT_PAD; - row[1]["column"] = "complex_value"; + row[1]["column"] = "art_value"; row[1]["type"] = "text"; if(is_slow) { - row[1]["value"] = llformat("%.2f", ((double)avatar->getLastART() / 1000000)); + row[1]["value"] = llformat( "%.2f", FSPerfStats::raw_to_ms( avatar->getLastART() ) ); } else { - row[1]["value"] = llformat("%.2f",((double)render_av / 1000000)); + row[1]["value"] = llformat( "%.2f", FSPerfStats::raw_to_ms( render_av_raw ) ); } - row[1]["font"]["name"] = "SANSSERIF"; row[1]["width"] = "50"; - row[2]["column"] = "name"; + row[2]["column"] = "complex_value"; row[2]["type"] = "text"; - row[2]["value"] = avatar->getFullname(); + row[2]["value"] = std::to_string(complexity_short); row[2]["font"]["name"] = "SANSSERIF"; + row[2]["width"] = "50"; + + + row[3]["column"] = "name"; + row[3]["type"] = "text"; + row[3]["value"] = avatar->getFullname(); + row[3]["font"]["name"] = "SANSSERIF"; LLScrollListItem* av_item = mNearbyList->addElement(item); if(av_item) diff --git a/indra/newview/llspatialpartition.cpp b/indra/newview/llspatialpartition.cpp index 2aef348685..9bc62acd6c 100644 --- a/indra/newview/llspatialpartition.cpp +++ b/indra/newview/llspatialpartition.cpp @@ -1128,6 +1128,7 @@ public: virtual S32 frustumCheck(const LLViewerOctreeGroup* group) { + FSZone; S32 res = AABBInFrustumNoFarClipGroupBounds(group); if (res != 0) { @@ -1138,6 +1139,7 @@ public: virtual S32 frustumCheckObjects(const LLViewerOctreeGroup* group) { + FSZone; S32 res = AABBInFrustumNoFarClipObjectBounds(group); if (res != 0) { @@ -1148,6 +1150,7 @@ public: virtual void processGroup(LLViewerOctreeGroup* base_group) { + FSZone; LLSpatialGroup* group = (LLSpatialGroup*)base_group; if (group->needsUpdate() || group->getVisible(LLViewerCamera::sCurCameraID) < LLDrawable::getCurrentFrame() - 1) diff --git a/indra/newview/llviewerdisplay.cpp b/indra/newview/llviewerdisplay.cpp index db2f65f4d6..63cd695a37 100644 --- a/indra/newview/llviewerdisplay.cpp +++ b/indra/newview/llviewerdisplay.cpp @@ -1193,7 +1193,7 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot) void render_hud_attachments() { - FSPerfStats::RecordSceneTime T (FSPerfStats::SceneStatType::RENDER_HUDS); + FSPerfStats::RecordSceneTime T (LLUUID{}, FSPerfStats::StatType_t::RENDER_HUDS); gGL.matrixMode(LLRender::MM_PROJECTION); gGL.pushMatrix(); gGL.matrixMode(LLRender::MM_MODELVIEW); @@ -1401,7 +1401,7 @@ bool setup_hud_matrices(const LLRect& screen_region) void render_ui(F32 zoom_factor, int subfield) { - FSPerfStats::RecordSceneTime T (FSPerfStats::SceneStatType::RENDER_UI); + FSPerfStats::RecordSceneTime T (const LLUUID{}, FSPerfStats::StatType_t::RENDER_UI); LL_RECORD_BLOCK_TIME(FTM_RENDER_UI); LLGLState::checkStates(); @@ -1487,7 +1487,7 @@ static LLTrace::BlockTimerStatHandle FTM_SWAP("Swap"); void swap() { - FSPerfStats::RecordSceneTime T (FSPerfStats::SceneStatType::RENDER_SWAP); + FSPerfStats::RecordSceneTime T (const LLUUID{}, FSPerfStats::StatType_t::RENDER_SWAP); LL_RECORD_BLOCK_TIME(FTM_SWAP); if (gDisplaySwapBuffers) diff --git a/indra/newview/llviewerjointmesh.cpp b/indra/newview/llviewerjointmesh.cpp index 0361986a27..4d98fb9aef 100644 --- a/indra/newview/llviewerjointmesh.cpp +++ b/indra/newview/llviewerjointmesh.cpp @@ -233,20 +233,12 @@ U32 LLViewerJointMesh::drawShape( F32 pixelArea, BOOL first_pass, BOOL is_dummy) } + std::unique_ptr T{}; auto vobj = mFace->getViewerObject(); - if(vobj && !vobj->asAvatar() && vobj->getAvatar()->isSelf()) + if( vobj && vobj->isAttachment() ) { - LLViewerObject * vtop = vobj; - LLViewerObject * par = (LLViewerObject *) vobj->getParent(); - - while (par && !(par->asAvatar())) - { - vtop = par; - par = (LLViewerObject *)vtop->getParent(); - } - vobj = vtop; + T = trackMyAttachment(vobj); } - FSPerfStats::RecordAttachmentTime T(vobj?vobj->getAttachmentItemID().getCRC32():0, FSPerfStats::ObjStatType::RENDER_GEOMETRY); U32 triangle_count = 0; diff --git a/indra/newview/llvieweroctree.cpp b/indra/newview/llvieweroctree.cpp index cdfd7c2f04..69cc810c00 100644 --- a/indra/newview/llvieweroctree.cpp +++ b/indra/newview/llvieweroctree.cpp @@ -1361,6 +1361,7 @@ bool LLViewerOctreeCull::earlyFail(LLViewerOctreeGroup* group) //virtual void LLViewerOctreeCull::traverse(const OctreeNode* n) { + FSZone; LLViewerOctreeGroup* group = (LLViewerOctreeGroup*) n->getListener(0); if (earlyFail(group)) @@ -1371,14 +1372,17 @@ void LLViewerOctreeCull::traverse(const OctreeNode* n) if (mRes == 2 || (mRes && group->hasState(LLViewerOctreeGroup::SKIP_FRUSTUM_CHECK))) { //fully in, just add everything + FSZoneN("AllInside"); OctreeTraveler::traverse(n); } else { + FSZoneN("Check inside?") mRes = frustumCheck(group); if (mRes) { //at least partially in, run on down + FSZoneN("PartiallyIn"); OctreeTraveler::traverse(n); } diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp index c9490b12c2..67f905d9f9 100644 --- a/indra/newview/llvoavatar.cpp +++ b/indra/newview/llvoavatar.cpp @@ -9157,38 +9157,38 @@ bool LLVOAvatar::isTooSlow(bool combined) const } // Either we're not stale or we've updated. - U64 render_time; - U64 render_geom_time; + U64 render_time_raw; + U64 render_geom_time_raw; if(!mARTCapped) { // no cap, so we use the live values - render_time = FSPerfStats::RecordObjectTime::get(this,FSPerfStats::ObjStatType::RENDER_COMBINED); - render_geom_time = FSPerfStats::RecordObjectTime::get(this,FSPerfStats::ObjStatType::RENDER_GEOMETRY); + render_time_raw = FSPerfStats::StatsRecorder::get(FSPerfStats::ObjType_t::OT_AVATAR, this->getID(), FSPerfStats::StatType_t::RENDER_COMBINED); + render_geom_time_raw = FSPerfStats::StatsRecorder::get(FSPerfStats::ObjType_t::OT_AVATAR, this->getID(), FSPerfStats::StatType_t::RENDER_GEOMETRY); } else { // use the cached values. - render_time = mRenderTime; - render_geom_time = mGeomTime; + render_time_raw = mRenderTime; + render_geom_time_raw = mGeomTime; } - if( (LLVOAvatar::sRenderTimeCap_ns > 0) && (render_time >= LLVOAvatar::sRenderTimeCap_ns) ) + if( (LLVOAvatar::sRenderTimeCap_ns > 0) && (FSPerfStats::raw_to_ns(render_time_raw) >= LLVOAvatar::sRenderTimeCap_ns) ) { if(!mARTCapped) { // if we weren't capped, we are now - abuse_constness->mRenderTime = FSPerfStats::RecordObjectTime::get(this,FSPerfStats::ObjStatType::RENDER_COMBINED); - abuse_constness->mGeomTime = FSPerfStats::RecordObjectTime::get(this,FSPerfStats::ObjStatType::RENDER_GEOMETRY); + abuse_constness->mRenderTime = render_time_raw; + abuse_constness->mGeomTime = render_geom_time_raw; abuse_constness->mARTStale = false; abuse_constness->mARTCapped = true; abuse_constness->mLastARTUpdateFrame = LLFrameTimer::getFrameCount(); - LL_INFOS() << this->getFullname() << " ("<< (combined?"combined":"geometry") << ") mLastART too high = " << render_time << " vs ("<< LLVOAvatar::sRenderTimeCap_ns << " set @ " << mLastARTUpdateFrame << LL_ENDL; + LL_INFOS() << this->getFullname() << " ("<< (combined?"combined":"geometry") << ") mLastART too high = " << FSPerfStats::raw_to_ns(render_time_raw) << " vs ("<< LLVOAvatar::sRenderTimeCap_ns << " set @ " << mLastARTUpdateFrame << LL_ENDL; } // return true only if that is the case in the context of the combined/geom_only flag. - return combined ? true : (render_geom_time >= LLVOAvatar::sRenderTimeCap_ns); + return combined ? true : (render_geom_time_raw >= LLVOAvatar::sRenderTimeCap_ns); } - LL_INFOS() << this->getFullname() << " ("<< (combined?"combined":"geometry") << ") good render time = " << render_time << " vs ("<< LLVOAvatar::sRenderTimeCap_ns << " set @ " << mLastARTUpdateFrame << LL_ENDL; + LL_INFOS() << this->getFullname() << " ("<< (combined?"combined":"geometry") << ") good render time = " << FSPerfStats::raw_to_ns(render_time_raw) << " vs ("<< LLVOAvatar::sRenderTimeCap_ns << " set @ " << mLastARTUpdateFrame << LL_ENDL; abuse_constness->mARTCapped = false; return false; } diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp index 2141ec6caa..ee0ebf1d9b 100644 --- a/indra/newview/llvovolume.cpp +++ b/indra/newview/llvovolume.cpp @@ -5546,7 +5546,7 @@ void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep, } } - if (type == LLRenderPass::PASS_ALPHA) + // if (type == LLRenderPass::PASS_ALPHA) // allow tracking through pipeline { //for alpha sorting facep->setDrawInfo(draw_info); } @@ -5784,6 +5784,14 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group) continue; } + std::unique_ptr T{}; + // Capture render times + if(vobj->isAttachment()) + { + T= trackMyAttachment(vobj); + } + // + // Stop doing stupid stuff we don;t need to. // Moving this inside a debug enabled check // std::string vobj_name = llformat("Vol%p", vobj); @@ -6382,20 +6390,14 @@ void LLVolumeGeometryManager::rebuildMesh(LLSpatialGroup* group) if (drawablep && !drawablep->isDead() && drawablep->isState(LLDrawable::REBUILD_ALL) && !drawablep->isState(LLDrawable::RIGGED) ) { + FSZoneN("Rebuild all non-Rigged") LLVOVolume* vobj = drawablep->getVOVolume(); - LLVOVolume* rootAtt{}; + std::unique_ptr T{}; + if(vobj->isAttachment()) { - auto par = (LLVOVolume*)vobj->getParent(); - rootAtt = vobj; - while( par->isAttachment() ) - { - rootAtt = par; - par = (LLVOVolume*)par->getParent(); - } - LL_INFOS() << "recording time for ATT@" << rootAtt << " " << (rootAtt?rootAtt->getAttachmentItemName():"null") << LL_ENDL; + T = trackMyAttachment(vobj); } - FSPerfStats::RecordAttachmentTime T(rootAtt?rootAtt->getAttachmentItemID().getCRC32():0, FSPerfStats::ObjStatType::RENDER_GEOMETRY); // avoid unfortunate sleep during trylock by static check //if(debugLoggingEnabled("AnimatedObjectsLinkset")) static auto debug_logging_on = debugLoggingEnabled("AnimatedObjectsLinkset"); @@ -6808,10 +6810,18 @@ U32 LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, LLFace U32 indices_index = 0; U16 index_offset = 0; + std::unique_ptr T{}; + LLViewerObject * lastVObj{nullptr}; while (face_iter < i) { //update face indices for new buffer facep = *face_iter; + LLViewerObject* vobj = facep->getViewerObject(); + if(vobj && vobj != lastVObj && vobj->isAttachment()) + { + T = trackMyAttachment(vobj); + lastVObj = vobj; + } if (buffer.isNull()) { // Bulk allocation failed @@ -7027,8 +7037,12 @@ U32 LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, LLFace else if (is_alpha) { // can we safely treat this as an alpha mask? - if (facep->getFaceColor().mV[3] <= 0.f) + // Nothing actually sets facecolor use the TE alpha instead. + // if (facep->getFaceColor().mV[3] <= 0.f) + if (te->getAlpha() <=0.f || facep->getFaceColor().mV[3] <= 0.f) + // { //100% transparent, don't render unless we're highlighting transparent + FSZoneN("facep->alpha -> invisible"); registerFace(group, facep, LLRenderPass::PASS_ALPHA_INVISIBLE); } else if (facep->canRenderAsMask()) diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp index 21b97292c3..4946bfabd4 100644 --- a/indra/newview/pipeline.cpp +++ b/indra/newview/pipeline.cpp @@ -3549,6 +3549,8 @@ void LLPipeline::stateSort(LLCamera& camera, LLCullResult &result) //LLVertexBuffer::unbind(); grabReferences(result); + { + FSZoneN("checkOcclusionAndRebuildMesh"); for (LLCullResult::sg_iterator iter = sCull->beginDrawableGroups(); iter != sCull->endDrawableGroups(); ++iter) { LLSpatialGroup* group = *iter; @@ -3572,9 +3574,11 @@ void LLPipeline::stateSort(LLCamera& camera, LLCullResult &result) } } } + } if (LLViewerCamera::sCurCameraID == LLViewerCamera::CAMERA_WORLD) { + FSZoneN("WorldCamera"); LLSpatialGroup* last_group = NULL; BOOL fov_changed = LLViewerCamera::getInstance()->isDefaultFOVChanged(); for (LLCullResult::bridge_iterator i = sCull->beginVisibleBridge(); i != sCull->endVisibleBridge(); ++i) @@ -3608,7 +3612,8 @@ void LLPipeline::stateSort(LLCamera& camera, LLCullResult &result) last_group->mLastUpdateDistance = last_group->mDistance; } } - + { + FSZoneN("StateSort: visible groups"); for (LLCullResult::sg_iterator iter = sCull->beginVisibleGroups(); iter != sCull->endVisibleGroups(); ++iter) { LLSpatialGroup* group = *iter; @@ -3627,7 +3632,7 @@ void LLPipeline::stateSort(LLCamera& camera, LLCullResult &result) group->rebuildMesh(); } } - } + }} { LL_RECORD_BLOCK_TIME(FTM_STATESORT_DRAWABLE); @@ -3983,6 +3988,8 @@ void LLPipeline::postSort(LLCamera& camera) LL_PUSH_CALLSTACKS(); //rebuild drawable geometry + { + FSZoneN("PostSort: rebuildGeom") for (LLCullResult::sg_iterator i = sCull->beginDrawableGroups(); i != sCull->endDrawableGroups(); ++i) { LLSpatialGroup* group = *i; @@ -4001,6 +4008,8 @@ void LLPipeline::postSort(LLCamera& camera) //build render map + { + FSZoneN("build render map"); for (LLCullResult::sg_iterator i = sCull->beginVisibleGroups(); i != sCull->endVisibleGroups(); ++i) { LLSpatialGroup* group = *i; @@ -4046,6 +4055,7 @@ void LLPipeline::postSort(LLCamera& camera) if (hasRenderType(LLPipeline::RENDER_TYPE_PASS_ALPHA)) { + FSZone("Collect Alpha groups"); LLSpatialGroup::draw_map_t::iterator alpha = group->mDrawMap.find(LLRenderPass::PASS_ALPHA); if (alpha != group->mDrawMap.end()) @@ -4071,6 +4081,7 @@ void LLPipeline::postSort(LLCamera& camera) } } } + } //flush particle VB if (LLVOPartGroup::sVB) @@ -4096,12 +4107,14 @@ void LLPipeline::postSort(LLCamera& camera) glBeginQueryARB(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN, mMeshDirtyQueryObject); }*/ - + { + FSZoneN("rebuild delayed upd groups") } //pack vertex buffers for groups that chose to delay their updates for (LLSpatialGroup::sg_vector_t::iterator iter = mMeshDirtyGroup.begin(); iter != mMeshDirtyGroup.end(); ++iter) { (*iter)->rebuildMesh(); } + } /*if (use_transform_feedback) { @@ -4110,12 +4123,17 @@ void LLPipeline::postSort(LLCamera& camera) mMeshDirtyGroup.clear(); + { + FSZoneN("sort alpha groups") if (!sShadowRender) { std::sort(sCull->beginAlphaGroups(), sCull->endAlphaGroups(), LLSpatialGroup::CompareDepthGreater()); } + } LL_PUSH_CALLSTACKS(); + { + FSZoneN("beacon rendering flags"); // only render if the flag is set. The flag is only set if we are in edit mode or the toggle is set in the menus // Ansariel: Make beacons also show when beacons floater is closed. if (/*LLFloaterReg::instanceVisible("beacons") &&*/ !sShadowRender) @@ -4169,6 +4187,7 @@ void LLPipeline::postSort(LLCamera& camera) forAllVisibleDrawables(renderSoundHighlights); } } + } LL_PUSH_CALLSTACKS(); // If managing your telehub, draw beacons at telehub and currently selected spawnpoint. if (LLFloaterTelehub::renderBeacons()) @@ -4178,6 +4197,7 @@ void LLPipeline::postSort(LLCamera& camera) if (!sShadowRender) { + FSZoneN("Render face highlights"); mSelectedFaces.clear(); LLPipeline::setRenderHighlightTextureChannel(gFloaterTools->getPanelFace()->getTextureChannelToEdit()); 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 40159314f7..c7201d8385 100644 --- a/indra/newview/skins/default/xui/en/panel_performance_complexity.xml +++ b/indra/newview/skins/default/xui/en/panel_performance_complexity.xml @@ -91,8 +91,12 @@ width="540"> + + width="80" /> - 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 ad0710e6d0..1e77273f2f 100644 --- a/indra/newview/skins/default/xui/en/panel_performance_nearby.xml +++ b/indra/newview/skins/default/xui/en/panel_performance_nearby.xml @@ -148,12 +148,16 @@ width="540"> + + width="40" /> From a95d846a5c2ba681c165e62699a163780f5d4b75 Mon Sep 17 00:00:00 2001 From: Mnikolenko Productengine Date: Mon, 25 Oct 2021 15:15:02 +0300 Subject: [PATCH 189/256] SL-16218 treat texture selection similar to diffuse map handling. --- indra/newview/llpanelface.cpp | 4 ++-- indra/newview/llpanelvolume.cpp | 26 +++++++++++++++++----- indra/newview/llpanelvolume.h | 3 +++ indra/newview/llselectmgr.cpp | 38 +++++++++++++++++++++++++++++---- indra/newview/llselectmgr.h | 4 ++-- 5 files changed, 62 insertions(+), 13 deletions(-) diff --git a/indra/newview/llpanelface.cpp b/indra/newview/llpanelface.cpp index 23394b26f2..71657239a6 100644 --- a/indra/newview/llpanelface.cpp +++ b/indra/newview/llpanelface.cpp @@ -361,7 +361,7 @@ void LLPanelFace::sendBump(U32 bumpiness) // LLSelectedTEMaterial::setNormalID(this, current_normal_map); - LLSelectMgr::getInstance()->selectionSetBumpmap( bump ); + LLSelectMgr::getInstance()->selectionSetBumpmap( bump, bumpytexture_ctrl->getImageItemID() ); } void LLPanelFace::sendTexGen() @@ -390,7 +390,7 @@ void LLPanelFace::sendShiny(U32 shininess) LLSelectedTEMaterial::setSpecularID(this, specmap); - LLSelectMgr::getInstance()->selectionSetShiny( shiny ); + LLSelectMgr::getInstance()->selectionSetShiny( shiny, texture_ctrl->getImageItemID() ); updateShinyControls(!specmap.isNull(), true); diff --git a/indra/newview/llpanelvolume.cpp b/indra/newview/llpanelvolume.cpp index 05d9346f89..89c558e4f8 100644 --- a/indra/newview/llpanelvolume.cpp +++ b/indra/newview/llpanelvolume.cpp @@ -50,6 +50,7 @@ //#include "llfirstuse.h" #include "llfocusmgr.h" #include "llmanipscale.h" +#include "llinventorymodel.h" #include "llpreviewscript.h" #include "llresmgr.h" #include "llselectmgr.h" @@ -57,6 +58,7 @@ #include "lltextbox.h" #include "lltool.h" #include "lltoolcomp.h" +#include "lltooldraganddrop.h" #include "lltoolmgr.h" #include "lltrans.h" #include "llui.h" @@ -780,7 +782,7 @@ void LLPanelVolume::onLightCancelTexture(const LLSD& data) // selection of "None" texture. LLUUID tex_id = LightTextureCtrl->getImageAssetID(); bool is_spotlight = volobjp->isLightSpotlight(); - volobjp->setLightTextureID(tex_id); //updates spotlight + setLightTextureID(tex_id, LightTextureCtrl->getImageItemID(), volobjp); //updates spotlight if (!is_spotlight && tex_id.notNull()) { @@ -825,7 +827,7 @@ void LLPanelVolume::onLightSelectTexture(const LLSD& data) if(LightTextureCtrl) { LLUUID id = LightTextureCtrl->getImageAssetID(); - volobjp->setLightTextureID(id); + setLightTextureID(id, LightTextureCtrl->getImageItemID(), volobjp); } } @@ -888,11 +890,12 @@ void LLPanelVolume::onCommitLight( LLUICtrl* ctrl, void* userdata ) if(LightTextureCtrl) { LLUUID id = LightTextureCtrl->getImageAssetID(); + LLUUID item_id = LightTextureCtrl->getImageItemID(); if (id.notNull()) { if (!volobjp->isLightSpotlight()) { //this commit is making this a spot light, set UI to default params - volobjp->setLightTextureID(id); + setLightTextureID(id, item_id, volobjp); LLVector3 spot_params = volobjp->getSpotLightParams(); self->getChild("Light FOV")->setValue(spot_params.mV[0]); self->getChild("Light Focus")->setValue(spot_params.mV[1]); @@ -902,7 +905,7 @@ void LLPanelVolume::onCommitLight( LLUICtrl* ctrl, void* userdata ) { //modifying existing params, this time volobjp won't change params on its own. if (volobjp->getLightTextureID() != id) { - volobjp->setLightTextureID(id); + setLightTextureID(id, item_id, volobjp); } LLVector3 spot_params; @@ -914,7 +917,7 @@ void LLPanelVolume::onCommitLight( LLUICtrl* ctrl, void* userdata ) } else if (volobjp->isLightSpotlight()) { //no longer a spot light - volobjp->setLightTextureID(id); + setLightTextureID(id, item_id, volobjp); //self->getChildView("Light FOV")->setEnabled(FALSE); //self->getChildView("Light Focus")->setEnabled(FALSE); //self->getChildView("Light Ambiance")->setEnabled(FALSE); @@ -931,6 +934,19 @@ void LLPanelVolume::onCommitIsLight( LLUICtrl* ctrl, void* userdata ) self->sendIsLight(); } +// static +void LLPanelVolume::setLightTextureID(const LLUUID &asset_id, const LLUUID &item_id, LLVOVolume* volobjp) +{ + if (volobjp) + { + LLViewerInventoryItem* item = gInventory.getItem(item_id); + if (item && !item->getPermissions().allowOperationBy(PERM_COPY, gAgent.getID())) + { + LLToolDragAndDrop::handleDropTextureProtections(volobjp, item, LLToolDragAndDrop::SOURCE_AGENT, LLUUID::null); + } + volobjp->setLightTextureID(asset_id); + } +} //---------------------------------------------------------------------------- // static diff --git a/indra/newview/llpanelvolume.h b/indra/newview/llpanelvolume.h index 66117316cf..6e49ccb742 100644 --- a/indra/newview/llpanelvolume.h +++ b/indra/newview/llpanelvolume.h @@ -40,6 +40,7 @@ class LLButton; class LLViewerObject; class LLComboBox; class LLColorSwatchCtrl; +class LLVOVolume; class LLPanelVolume : public LLPanel { @@ -73,6 +74,8 @@ public: void onLightCancelTexture(const LLSD& data); void onLightSelectTexture(const LLSD& data); + static void setLightTextureID(const LLUUID &asset_id, const LLUUID &item_id, LLVOVolume* volobjp); + protected: void getState(); diff --git a/indra/newview/llselectmgr.cpp b/indra/newview/llselectmgr.cpp index 5bbdeb1f98..b0a566755f 100644 --- a/indra/newview/llselectmgr.cpp +++ b/indra/newview/llselectmgr.cpp @@ -1936,7 +1936,7 @@ BOOL LLSelectMgr::selectionRevertTextures() return revert_successful; } -void LLSelectMgr::selectionSetBumpmap(U8 bumpmap) +void LLSelectMgr::selectionSetBumpmap(U8 bumpmap, const LLUUID &image_id) { struct f : public LLSelectedTEFunctor { @@ -1952,7 +1952,22 @@ void LLSelectMgr::selectionSetBumpmap(U8 bumpmap) return true; } } setfunc(bumpmap); - getSelection()->applyToTEs(&setfunc); + + LLViewerInventoryItem* item = gInventory.getItem(image_id); + if(item + && !item->getPermissions().allowOperationBy(PERM_COPY, gAgent.getID()) + && (mSelectedObjects->getNumNodes() > 1) ) + { + LL_WARNS() << "Attempted to apply no-copy texture to multiple objects" << LL_ENDL; + return; + } + if (item && !item->getPermissions().allowOperationBy(PERM_COPY, gAgent.getID())) + { + LLViewerObject *object = mSelectedObjects->getFirstRootObject(); + if (!object) return; + LLToolDragAndDrop::handleDropTextureProtections(object, item, LLToolDragAndDrop::SOURCE_AGENT, LLUUID::null); + } + getSelection()->applyToTEs(&setfunc); LLSelectMgrSendFunctor sendfunc; getSelection()->applyToObjects(&sendfunc); @@ -1981,7 +1996,7 @@ void LLSelectMgr::selectionSetTexGen(U8 texgen) } -void LLSelectMgr::selectionSetShiny(U8 shiny) +void LLSelectMgr::selectionSetShiny(U8 shiny, const LLUUID &image_id) { struct f : public LLSelectedTEFunctor { @@ -1997,7 +2012,22 @@ void LLSelectMgr::selectionSetShiny(U8 shiny) return true; } } setfunc(shiny); - getSelection()->applyToTEs(&setfunc); + + LLViewerInventoryItem* item = gInventory.getItem(image_id); + if(item + && !item->getPermissions().allowOperationBy(PERM_COPY, gAgent.getID()) + && (mSelectedObjects->getNumNodes() > 1) ) + { + LL_WARNS() << "Attempted to apply no-copy texture to multiple objects" << LL_ENDL; + return; + } + if (item && !item->getPermissions().allowOperationBy(PERM_COPY, gAgent.getID())) + { + LLViewerObject *object = mSelectedObjects->getFirstRootObject(); + if (!object) return; + LLToolDragAndDrop::handleDropTextureProtections(object, item, LLToolDragAndDrop::SOURCE_AGENT, LLUUID::null); + } + getSelection()->applyToTEs(&setfunc); LLSelectMgrSendFunctor sendfunc; getSelection()->applyToObjects(&sendfunc); diff --git a/indra/newview/llselectmgr.h b/indra/newview/llselectmgr.h index 57fdfce152..2b00fa1595 100644 --- a/indra/newview/llselectmgr.h +++ b/indra/newview/llselectmgr.h @@ -609,9 +609,9 @@ public: void selectionRevertColors(); void selectionRevertShinyColors(); BOOL selectionRevertTextures(); - void selectionSetBumpmap( U8 bumpmap ); + void selectionSetBumpmap( U8 bumpmap, const LLUUID &image_id ); void selectionSetTexGen( U8 texgen ); - void selectionSetShiny( U8 shiny ); + void selectionSetShiny( U8 shiny, const LLUUID &image_id ); void selectionSetFullbright( U8 fullbright ); void selectionSetMedia( U8 media_type, const LLSD &media_data ); void selectionSetClickAction(U8 action); From 8acce67f95bab5bfae06a2f5d9de8bf9234c8b21 Mon Sep 17 00:00:00 2001 From: Andrey Lihatskiy Date: Thu, 28 Oct 2021 00:05:47 +0300 Subject: [PATCH 190/256] SL-16247 Post-d520 libvlc plugin fixes by Callum --- .../libvlc/media_plugin_libvlc.cpp | 39 +++++-------------- 1 file changed, 10 insertions(+), 29 deletions(-) diff --git a/indra/media_plugins/libvlc/media_plugin_libvlc.cpp b/indra/media_plugins/libvlc/media_plugin_libvlc.cpp index 5d4a488e64..ce0947a1bc 100644 --- a/indra/media_plugins/libvlc/media_plugin_libvlc.cpp +++ b/indra/media_plugins/libvlc/media_plugin_libvlc.cpp @@ -283,35 +283,16 @@ void MediaPluginLibVLC::playMedia() return; } + // A new call to play the media is received after the initial one. Typically + // this is due to a size change request either as the media naturally resizes + // to the size of the prim container, or else, as a 2D window is resized by the + // user. Stopping the media, helps avoid a race condition where the media pixel + // buffer size is out of sync with the declared size (width/height) for a frame + // or two and the plugin crashes as VLC tries to decode a frame into unallocated + // memory. if (mLibVLCMediaPlayer) { - // stop listening to events while we reset things - libvlc_event_manager_t* em = libvlc_media_player_event_manager(mLibVLCMediaPlayer); - if (em) - { - libvlc_event_detach(em, libvlc_MediaPlayerOpening, eventCallbacks, NULL); - libvlc_event_detach(em, libvlc_MediaPlayerPlaying, eventCallbacks, NULL); - libvlc_event_detach(em, libvlc_MediaPlayerPaused, eventCallbacks, NULL); - libvlc_event_detach(em, libvlc_MediaPlayerStopped, eventCallbacks, NULL); - libvlc_event_detach(em, libvlc_MediaPlayerEndReached, eventCallbacks, NULL); - libvlc_event_detach(em, libvlc_MediaPlayerEncounteredError, eventCallbacks, NULL); - libvlc_event_detach(em, libvlc_MediaPlayerTimeChanged, eventCallbacks, NULL); - libvlc_event_detach(em, libvlc_MediaPlayerPositionChanged, eventCallbacks, NULL); - libvlc_event_detach(em, libvlc_MediaPlayerLengthChanged, eventCallbacks, NULL); - libvlc_event_detach(em, libvlc_MediaPlayerTitleChanged, eventCallbacks, NULL); - }; - libvlc_media_player_stop(mLibVLCMediaPlayer); - libvlc_media_player_release(mLibVLCMediaPlayer); - - mLibVLCMediaPlayer = 0; - } - - if (mLibVLCMedia) - { - libvlc_media_release(mLibVLCMedia); - - mLibVLCMedia = 0; } mLibVLCMedia = libvlc_media_new_location(mLibVLC, mURL.c_str()); @@ -345,6 +326,9 @@ void MediaPluginLibVLC::playMedia() libvlc_event_attach(em, libvlc_MediaPlayerTitleChanged, eventCallbacks, this); } + libvlc_video_set_callbacks(mLibVLCMediaPlayer, lock, unlock, display, &mLibVLCCallbackContext); + libvlc_video_set_format(mLibVLCMediaPlayer, "RV32", mWidth, mHeight, mWidth * mDepth); + mLibVLCCallbackContext.parent = this; mLibVLCCallbackContext.texture_pixels = mPixels; mLibVLCCallbackContext.mp = mLibVLCMediaPlayer; @@ -366,9 +350,6 @@ void MediaPluginLibVLC::playMedia() setStatus(STATUS_LOADED); - libvlc_video_set_callbacks(mLibVLCMediaPlayer, lock, unlock, display, &mLibVLCCallbackContext); - libvlc_video_set_format(mLibVLCMediaPlayer, "RV32", mWidth, mHeight, mWidth * mDepth); - // note this relies on the "set_loop" message arriving before the "start" (play) one // but that appears to always be the case if (mIsLooping) From 404e69e5945d357d70bd2da684b7a3dbedd1579d Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Thu, 28 Oct 2021 18:41:10 +0300 Subject: [PATCH 191/256] SL-15462 Convert waitForChannel() into state machine --- indra/newview/llappviewer.cpp | 6 + indra/newview/llvoicevivox.cpp | 238 +++++++++++++++++++++++---------- 2 files changed, 174 insertions(+), 70 deletions(-) diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 3ec6d3f90e..f668dc754d 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -1520,6 +1520,12 @@ bool LLAppViewer::doFrame() { pauseMainloopTimeout(); saveFinalSnapshot(); + + if (LLVoiceClient::instanceExists()) + { + LLVoiceClient::getInstance()->terminate(); + } + disconnectViewer(); resumeMainloopTimeout(); } diff --git a/indra/newview/llvoicevivox.cpp b/indra/newview/llvoicevivox.cpp index 4aa6f2c6b2..c7a544f8eb 100644 --- a/indra/newview/llvoicevivox.cpp +++ b/indra/newview/llvoicevivox.cpp @@ -400,6 +400,11 @@ void LLVivoxVoiceClient::init(LLPumpIO *pump) void LLVivoxVoiceClient::terminate() { + if (sShuttingDown) + { + return; + } + // needs to be done manually here since we will not get another pass in // coroutines... that mechanism is long since gone. if (mIsLoggedIn) @@ -1126,6 +1131,11 @@ bool LLVivoxVoiceClient::provisionVoiceAccount() LLVoiceVivoxStats::getInstance()->provisionAttemptStart(); result = httpAdapter->postAndSuspend(httpRequest, url, LLSD(), httpOpts); + if (sShuttingDown) + { + return false; + } + LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); @@ -1133,14 +1143,12 @@ bool LLVivoxVoiceClient::provisionVoiceAccount() { F32 timeout = pow(PROVISION_RETRY_TIMEOUT, static_cast(retryCount)); LL_WARNS("Voice") << "Provision CAP 404. Retrying in " << timeout << " seconds. Retries: " << (S32)retryCount << LL_ENDL; + llcoro::suspendUntilTimeout(timeout); + if (sShuttingDown) { return false; } - else - { - llcoro::suspendUntilTimeout(timeout); - } } else if (!status) { @@ -1515,6 +1523,11 @@ bool LLVivoxVoiceClient::requestParcelVoiceInfo() LLSD result = httpAdapter->postAndSuspend(httpRequest, url, LLSD()); + if (sShuttingDown) + { + return false; + } + LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); @@ -1620,6 +1633,11 @@ bool LLVivoxVoiceClient::addAndJoinSession(const sessionStatePtr_t &nextSession) llcoro::suspend(); + if (sShuttingDown) + { + return false; + } + LLSD result; if (mSpatialJoiningNum == MAX_NORMAL_JOINING_SPATIAL_NUM) @@ -1685,7 +1703,6 @@ bool LLVivoxVoiceClient::addAndJoinSession(const sessionStatePtr_t &nextSession) if (sShuttingDown) { - mIsJoiningSession = false; return false; } @@ -1808,6 +1825,11 @@ bool LLVivoxVoiceClient::terminateAudioSession(bool wait) result = llcoro::suspendUntilEventOnWithTimeout(mVivoxPump, LOGOUT_ATTEMPT_TIMEOUT, timeoutResult); + if (sShuttingDown) + { + return false; + } + LL_DEBUGS("Voice") << "event=" << ll_stream_notation_sd(result) << LL_ENDL; if (result.has("session")) { @@ -1870,54 +1892,76 @@ bool LLVivoxVoiceClient::terminateAudioSession(bool wait) return status; } + +typedef enum e_voice_wait_for_channel_state +{ + VOICE_CHANNEL_STATE_LOGIN = 0, // entry point + VOICE_CHANNEL_STATE_CHECK_EFFECTS, + VOICE_CHANNEL_STATE_START_CHANNEL_PROCESSING, + VOICE_CHANNEL_STATE_PROCESS_CHANNEL, + VOICE_CHANNEL_STATE_NEXT_CHANNEL_DELAY, + VOICE_CHANNEL_STATE_NEXT_CHANNEL_CHECK, + VOICE_CHANNEL_STATE_LOGOUT, + VOICE_CHANNEL_STATE_RELOG, + VOICE_CHANNEL_STATE_DONE, +} EVoiceWaitForChannelState; + bool LLVivoxVoiceClient::waitForChannel() { LL_INFOS("Voice") << "Waiting for channel" << LL_ENDL; + EVoiceWaitForChannelState state = VOICE_CHANNEL_STATE_LOGIN; + do { - if (!loginToVivox()) - { - return false; - } - if (sShuttingDown) { + // terminate() forcefully disconects voice, no need for cleanup return false; } - if (LLVoiceClient::instance().getVoiceEffectEnabled()) + switch (state) { - retrieveVoiceFonts(); - - if (sShuttingDown) + case VOICE_CHANNEL_STATE_LOGIN: + if (!loginToVivox()) { return false; } + state = VOICE_CHANNEL_STATE_CHECK_EFFECTS; + break; - // Request the set of available voice fonts. - refreshVoiceEffectLists(false); - } - -#if USE_SESSION_GROUPS - // Rider: This code is completely unchanged from the original state machine - // It does not seem to be in active use... but I'd rather not rip it out. - // create the main session group - setState(stateCreatingSessionGroup); - sessionGroupCreateSendMessage(); -#endif - - do - { - mIsProcessingChannels = true; - llcoro::suspend(); - - if (sShuttingDown) + case VOICE_CHANNEL_STATE_CHECK_EFFECTS: + if (LLVoiceClient::instance().getVoiceEffectEnabled()) { - mRelogRequested = false; - break; + retrieveVoiceFonts(); + + if (sShuttingDown) + { + return false; + } + + // Request the set of available voice fonts. + refreshVoiceEffectLists(false); } +#if USE_SESSION_GROUPS + // Rider: This code is completely unchanged from the original state machine + // It does not seem to be in active use... but I'd rather not rip it out. + // create the main session group + setState(stateCreatingSessionGroup); + sessionGroupCreateSendMessage(); +#endif + + state = VOICE_CHANNEL_STATE_START_CHANNEL_PROCESSING; + break; + + case VOICE_CHANNEL_STATE_START_CHANNEL_PROCESSING: + mIsProcessingChannels = true; + llcoro::suspend(); + state = VOICE_CHANNEL_STATE_PROCESS_CHANNEL; + break; + + case VOICE_CHANNEL_STATE_PROCESS_CHANNEL: if (mTuningMode) { performMicTuning(); @@ -1958,63 +2002,91 @@ bool LLVivoxVoiceClient::waitForChannel() } } - if (!mNextAudioSession && !sShuttingDown) + state = VOICE_CHANNEL_STATE_NEXT_CHANNEL_DELAY; + break; + + case VOICE_CHANNEL_STATE_NEXT_CHANNEL_DELAY: + if (!mNextAudioSession) { llcoro::suspendUntilTimeout(1.0); } + state = VOICE_CHANNEL_STATE_NEXT_CHANNEL_CHECK; + break; - if (sShuttingDown) + case VOICE_CHANNEL_STATE_NEXT_CHANNEL_CHECK: + if (mVoiceEnabled && !mRelogRequested) { - mRelogRequested = false; + state = VOICE_CHANNEL_STATE_START_CHANNEL_PROCESSING; + break; + } + else + { + mIsProcessingChannels = false; + LL_DEBUGS("Voice") + << "leaving inner waitForChannel loop" + << " RelogRequested=" << mRelogRequested + << " VoiceEnabled=" << mVoiceEnabled + << LL_ENDL; + state = VOICE_CHANNEL_STATE_LOGOUT; break; } - } while (!sShuttingDown && mVoiceEnabled && !mRelogRequested); + case VOICE_CHANNEL_STATE_LOGOUT: + logoutOfVivox(true /*bool wait*/); + if (mRelogRequested) + { + state = VOICE_CHANNEL_STATE_RELOG; + } + else + { + state = VOICE_CHANNEL_STATE_DONE; + } + break; - if (!sShuttingDown) - { - LL_DEBUGS("Voice") - << "leaving inner waitForChannel loop" - << " RelogRequested=" << mRelogRequested - << " VoiceEnabled=" << mVoiceEnabled - << LL_ENDL; - } - else - { - // if sShuttingDown is set, we already logged out - LL_DEBUGS("Voice") << "leaving inner waitForChannel loop." << LL_ENDL; - return false; - } - - mIsProcessingChannels = false; - - logoutOfVivox(!sShuttingDown /*bool wait*/); - - if (mRelogRequested && !sShuttingDown) - { + case VOICE_CHANNEL_STATE_RELOG: LL_DEBUGS("Voice") << "Relog Requested, restarting provisioning" << LL_ENDL; if (!provisionVoiceAccount()) { + if (sShuttingDown) + { + return false; + } LL_WARNS("Voice") << "provisioning voice failed; giving up" << LL_ENDL; giveUp(); return false; } + if (mVoiceEnabled && mRelogRequested && isGatewayRunning()) + { + state = VOICE_CHANNEL_STATE_LOGIN; + } + else + { + state = VOICE_CHANNEL_STATE_DONE; + } + break; + case VOICE_CHANNEL_STATE_DONE: + LL_DEBUGS("Voice") + << "exiting" + << " RelogRequested=" << mRelogRequested + << " VoiceEnabled=" << mVoiceEnabled + << LL_ENDL; + return !sShuttingDown; } - } while (!sShuttingDown && mVoiceEnabled && mRelogRequested && isGatewayRunning()); - - LL_DEBUGS("Voice") - << "exiting" - << " RelogRequested=" << mRelogRequested - << " VoiceEnabled=" << mVoiceEnabled - << LL_ENDL; - return !sShuttingDown; + } while (true); } bool LLVivoxVoiceClient::runSession(const sessionStatePtr_t &session) { LL_INFOS("Voice") << "running new voice session " << session->mHandle << LL_ENDL; - if (!addAndJoinSession(session)) + bool joined_session = addAndJoinSession(session); + + if (sShuttingDown) + { + return false; + } + + if (!joined_session) { notifyStatusObservers(LLVoiceClientStatusObserver::ERROR_UNKNOWN); @@ -2038,9 +2110,19 @@ bool LLVivoxVoiceClient::runSession(const sessionStatePtr_t &session) mIsInChannel = true; mMuteMicDirty = true; - while (mVoiceEnabled && isGatewayRunning() && !mSessionTerminateRequested && !mTuningMode) + while (!sShuttingDown + && mVoiceEnabled + && isGatewayRunning() + && !mSessionTerminateRequested + && !mTuningMode) { sendCaptureAndRenderDevices(); // suspends + + if (sShuttingDown) + { + return false; + } + if (mSessionTerminateRequested) { break; @@ -2070,10 +2152,15 @@ bool LLVivoxVoiceClient::runSession(const sessionStatePtr_t &session) // cap for the parcel voice info. If we can't request it // then we don't have the cap URL so we do nothing and will // recheck next time around - if (requestParcelVoiceInfo()) + if (requestParcelVoiceInfo()) // suspends { // The parcel voice URI has changed.. break out and reconnect. break; } + + if (sShuttingDown) + { + return false; + } } // Do the calculation that enforces the listener<->speaker tether (and also updates the real camera position) enforceTether(); @@ -2092,6 +2179,12 @@ bool LLVivoxVoiceClient::runSession(const sessionStatePtr_t &session) mIsInitialized = true; LLSD result = llcoro::suspendUntilEventOnWithTimeout(mVivoxPump, UPDATE_THROTTLE_SECONDS, timeoutEvent); + + if (sShuttingDown) + { + return false; + } + if (!result.has("timeout")) // logging the timeout event spams the log { LL_DEBUGS("Voice") << "event=" << ll_stream_notation_sd(result) << LL_ENDL; @@ -2134,6 +2227,11 @@ bool LLVivoxVoiceClient::runSession(const sessionStatePtr_t &session) } } + if (sShuttingDown) + { + return false; + } + mIsInChannel = false; LL_DEBUGS("Voice") << "terminating at end of runSession" << LL_ENDL; terminateAudioSession(true); From 6921edcc39a4559ec267602b818c4fef9c974349 Mon Sep 17 00:00:00 2001 From: Andrey Lihatskiy Date: Mon, 1 Nov 2021 21:23:12 +0200 Subject: [PATCH 192/256] SL-16293 Updated vlc to CT build 565299 --- autobuild.xml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/autobuild.xml b/autobuild.xml index fb9314f1a1..59d65972f5 100644 --- a/autobuild.xml +++ b/autobuild.xml @@ -3172,9 +3172,9 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors archive hash - b639d0035f4a8c9b4973be428a1b7e61 + 738688816ebd76958e49772712a6b972 url - http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/69569/671323/vlc_bin-3.0.9.549888-darwin64-549888.tar.bz2 + https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/90004/820701/vlc_bin-3.0.16.565299-darwin64-565299.tar.bz2 name darwin64 @@ -3196,9 +3196,9 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors archive hash - 4f50b0c47daa081dd4fcb83763d5b0b2 + 6801f91f3f27e626898bab90d40fc1c3 url - http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/69567/671314/vlc_bin-3.0.9.549888-windows-549888.tar.bz2 + https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/90005/820712/vlc_bin-3.0.16.565299-windows-565299.tar.bz2 name windows @@ -3208,16 +3208,16 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors archive hash - c2f8c01fb6c261b72beb07f0c4cd423f + 7f66982d6edf3c38f3493e28826d58e8 url - http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/69568/671315/vlc_bin-3.0.9.549888-windows64-549888.tar.bz2 + https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/90006/820713/vlc_bin-3.0.16.565299-windows64-565299.tar.bz2 name windows64 version - 3.0.9.549888 + 3.0.16.565299 xmlrpc-epi From 0c364328562a982fc9016e74c0fbef206a323f24 Mon Sep 17 00:00:00 2001 From: Beq Date: Wed, 3 Nov 2021 15:40:29 +0000 Subject: [PATCH 193/256] Move perf stats to newview --- indra/llcommon/CMakeLists.txt | 4 - indra/llcommon/fsperfstats.cpp | 36 ---- indra/llcommon/fsperfstats.h | 316 --------------------------------- indra/newview/CMakeLists.txt | 4 + 4 files changed, 4 insertions(+), 356 deletions(-) delete mode 100644 indra/llcommon/fsperfstats.cpp delete mode 100644 indra/llcommon/fsperfstats.h diff --git a/indra/llcommon/CMakeLists.txt b/indra/llcommon/CMakeLists.txt index 463f8286a0..061a5af975 100644 --- a/indra/llcommon/CMakeLists.txt +++ b/indra/llcommon/CMakeLists.txt @@ -264,10 +264,6 @@ set(llcommon_HEADER_FILES list(APPEND llcommon_SOURCE_FILES fstracyclient.cpp) endif() # Tracy Profiler support - # Performance stast support - list(APPEND llcommon_SOURCE_FILES fsperfstats.cpp) - list(APPEND llcommon_HEADER_FILES fsperfstats.h) - # # Add all nd* files. memory pool, intrinsics, ... SET( llcommon_ND_SOURCE_FILES diff --git a/indra/llcommon/fsperfstats.cpp b/indra/llcommon/fsperfstats.cpp deleted file mode 100644 index ac2d5f2de3..0000000000 --- a/indra/llcommon/fsperfstats.cpp +++ /dev/null @@ -1,36 +0,0 @@ -/** - * @file fsperfstats.cpp - * @brief Stats collection to support perf floater and auto tune - * - * $LicenseInfo:firstyear=2021&license=fsviewerlgpl$ - * Phoenix Firestorm Viewer Source Code - * Copyright (C) 2021, The Phoenix Firestorm Project, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * The Phoenix Firestorm Project, Inc., 1831 Oakwood Drive, Fairmont, Minnesota 56031-3225 USA - * http://www.firestormviewer.org - * $/LicenseInfo$ - */ -#include "fsperfstats.h" -namespace FSPerfStats -{ - std::atomic StatsRecorder::writeBuffer{0}; - bool StatsRecorder::collectionEnabled{true}; - std::array StatsRecorder::statsDoubleBuffer{ {} }; - std::array StatsRecorder::max{ {} }; - std::array StatsRecorder::sum{ {} }; - -} \ No newline at end of file diff --git a/indra/llcommon/fsperfstats.h b/indra/llcommon/fsperfstats.h deleted file mode 100644 index c55aeb6333..0000000000 --- a/indra/llcommon/fsperfstats.h +++ /dev/null @@ -1,316 +0,0 @@ -#pragma once -#ifndef FS_PERFSTATS_H_INCLUDED -#define FS_PERFSTATS_H_INCLUDED -/** - * @file fsperfstats.h - * @brief Statistics collection to support autotune and perf flaoter. - * - * $LicenseInfo:firstyear=2021&license=fsviewerlgpl$ - * Phoenix Firestorm Viewer Source Code - * Copyright (C) 2021, The Phoenix Firestorm Project, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * The Phoenix Firestorm Project, Inc., 1831 Oakwood Drive, Fairmont, Minnesota 56031-3225 USA - * http://www.firestormviewer.org - * $/LicenseInfo$ - */ - -#include -#include -#include -#include -#include "lluuid.h" -#include "lltimer.h" -#include "blockingconcurrentqueue.h" -#include "llapp.h" -#include "fstelemetry.h" - -extern LLUUID gAgentID; -namespace FSPerfStats -{ - - enum class ObjType_t{ - OT_GENERAL=0, // Also Unknown. Used for n/a type stats such as scenery - OT_AVATAR, - OT_ATTACHMENT, - OT_HUD, - OT_COUNT - }; - enum class StatType_t{ - RENDER_GEOMETRY=0, - RENDER_SHADOWS, - RENDER_HUDS, - RENDER_UI, - RENDER_COMBINED, - RENDER_SWAP, - RENDER_FRAME, - RENDER_SLEEP, - RENDER_LFS, - RENDER_MESHREPO, - RENDER_FPSLIMIT, - RENDER_FPS, - RENDER_IDLE, - STATS_COUNT - }; - - struct StatsRecord - { - StatType_t statType; - ObjType_t objType; - LLUUID objID; - uint64_t time; - }; - - class StatsRecorder{ - using Queue = moodycamel::BlockingConcurrentQueue; - public: - static inline StatsRecorder& getInstance() - { - static StatsRecorder instance; - // volatile int dummy{}; - return instance; - } - - static inline void send(const StatsRecord& u){StatsRecorder::getInstance().q.enqueue(u);}; - static inline void endFrame(){StatsRecorder::getInstance().q.enqueue(StatsRecord{});}; - - static inline void enable() { collectionEnabled=true; }; - static inline void disable() { collectionEnabled=false; }; - static inline bool enabled() { return(collectionEnabled); }; - - static inline int getReadBufferIndex() { return (writeBuffer ^ 1); }; - // static inline const StatsTypeMatrix& getCurrentStatsMatrix(){ return statsDoubleBuffer[getReadBufferIndex()];} - static inline uint64_t get(ObjType_t otype, LLUUID id, StatType_t type) - { - return statsDoubleBuffer[getReadBufferIndex()][static_cast(otype)][id][static_cast(type)]; - } - static inline uint64_t getSceneStat(StatType_t type) - { - static const LLUUID null_id{}; - return statsDoubleBuffer[getReadBufferIndex()][static_cast(ObjType_t::OT_GENERAL)][null_id][static_cast(type)]; - } - - static inline uint64_t getSum(ObjType_t otype, StatType_t type) - { - return sum[getReadBufferIndex()][static_cast(otype)][static_cast(type)]; - } - static inline uint64_t getMax(ObjType_t otype, StatType_t type) - { - return max[getReadBufferIndex()][static_cast(otype)][static_cast(type)]; - } - private: - StatsRecorder():q(100),t(&StatsRecorder::run) - { - // create a queue - // create a thread to consume from the queue - t.detach(); - } - -// StatsArray is a uint64_t for each possible statistic type. - using StatsArray = std::array(FSPerfStats::StatType_t::STATS_COUNT)>; - using StatsMap = std::unordered_map; - using StatsTypeMatrix = std::array(FSPerfStats::ObjType_t::OT_COUNT)>; - using StatsSummaryArray = std::array(FSPerfStats::ObjType_t::OT_COUNT)>; - - static std::atomic writeBuffer; - static std::array statsDoubleBuffer; - static std::array max; - static std::array sum; - static bool collectionEnabled; - - - void processUpdate(const StatsRecord& upd) - { - FSZone; - using ST = StatType_t; - // Note: nullptr is used as the key for global stats - constexpr auto period{500}; - if(upd.statType == StatType_t::RENDER_GEOMETRY && upd.objType == ObjType_t::OT_GENERAL && upd.objID == LLUUID{} && upd.time == 0) - { - toggleBuffer(); - return; - } - - StatsMap& stm {statsDoubleBuffer[writeBuffer][static_cast(upd.objType)]}; - auto& key{upd.objID}; - auto val {upd.time}; - auto type {upd.statType}; - FSZoneText(key.asString().c_str(), 36); - FSZoneValue(val); - auto& thisAsset = stm[key]; - thisAsset[static_cast(type)] += val; - thisAsset[static_cast(ST::RENDER_COMBINED)] += val; - FSZoneValue(thisAsset[static_cast(type)]); - sum[writeBuffer][static_cast(upd.objType)][static_cast(type)] += val; - sum[writeBuffer][static_cast(upd.objType)][static_cast(ST::RENDER_COMBINED)] += val; - FSZoneValue(static_cast(upd.objType)); - FSZoneValue(statsDoubleBuffer[writeBuffer][static_cast(upd.objType)][key][static_cast(ST::RENDER_COMBINED)]); - if(max[writeBuffer][static_cast(upd.objType)][static_cast(type)] < stm[key][static_cast(type)]) - { - max[writeBuffer][static_cast(upd.objType)][static_cast(type)] = stm[key][static_cast(type)]; - } - if(max[writeBuffer][static_cast(upd.objType)][static_cast(ST::RENDER_COMBINED)] < stm[key][static_cast(ST::RENDER_COMBINED)]) - { - max[writeBuffer][static_cast(upd.objType)][static_cast(ST::RENDER_COMBINED)] = stm[key][static_cast(ST::RENDER_COMBINED)]; - } - } - - static inline void toggleBuffer() - { - FSPlot("q size", static_cast(StatsRecorder::getInstance().q.size_approx())); - FSZone; - using ST = StatType_t; - - auto& statsMap = statsDoubleBuffer[writeBuffer][static_cast(ObjType_t::OT_ATTACHMENT)]; - for(auto& stat_entry : statsMap) - { - auto val = stat_entry.second[static_cast(ST::RENDER_COMBINED)]; - auto avg = statsDoubleBuffer[writeBuffer ^ 1][static_cast(ObjType_t::OT_ATTACHMENT)][stat_entry.first][static_cast(ST::RENDER_COMBINED)]; - stat_entry.second[static_cast(ST::RENDER_COMBINED)] = avg + (val/100) - (avg/100); - } - if(enabled()) - { - writeBuffer ^= 1; - }; // note we are relying on atomic updates here. The risk is low and would cause minor errors in the stats display. - auto& statsTypeMatrix = statsDoubleBuffer[writeBuffer]; - for(auto& statsMap : statsTypeMatrix) - { - FSZoneN("Clear stats maps"); - for(auto& stat_entry : statsMap) - { - std::fill_n(stat_entry.second.begin() ,static_cast(ST::STATS_COUNT),0); - } - statsMap.clear(); - } - for(int i=0; i< static_cast(ObjType_t::OT_COUNT); i++) - { - FSZoneN("clear max/sum"); - max[writeBuffer][i].fill(0); - sum[writeBuffer][i].fill(0); - } - } - - - - static void run() - { - StatsRecord upd; - auto& instance {StatsRecorder::getInstance()}; - FSThreadName( "PerfStats" ); - - while( !LLApp::isExiting() ) - { - if(instance.q.wait_dequeue_timed(upd, std::chrono::milliseconds(5))) - { - instance.processUpdate(upd); - } - } - } - - Queue q; - std::thread t; - - ~StatsRecorder() = default; - StatsRecorder(const StatsRecorder&) = delete; - StatsRecorder& operator=(const StatsRecorder&) = delete; - - }; - - // std::chrono::duration getTime(){ - - // auto begin= std::chrono::system_clock::now(); - // for ( size_t i= 0; i <= tenMill; ++i){ - // StatsRecorder::getInstance(); - // } - // return std::chrono::system_clock::now() - begin; - - // }; - - template - class RecordTime - { - - private: - RecordTime(const RecordTime&) = delete; - RecordTime() = delete; - const StatType_t type; - const decltype(ObjType) objType; - const LLUUID objID; - U64 start; - RecordTime( StatType_t type ){};// - - public: - - static inline void enable(){collectionEnabled=true;}; - static inline void disable(){collectionEnabled=false;}; - static inline bool enabled(){return(collectionEnabled);}; - - - RecordTime( const LLUUID id, StatType_t type ):start{LLTimer::getCurrentClockCount()}, type{type}, objType{ObjType}, objID{id}{}; - - ~RecordTime() - { - FSZoneC(tracy::Color::Red); - auto val = LLTimer::getCurrentClockCount() - start; - FSZoneValue(val); - FSZoneValue(static_cast(objType)); - FSZoneText(objID.asString().c_str(), 36); - StatsRecord stat{type, objType, objID, val}; - StatsRecorder::send(std::move(stat)); - }; - - - }; - - inline double raw_to_ns(U64 raw) { return (static_cast(raw) * 1000000000.0) * get_timer_info().mClockFrequencyInv; }; - inline double raw_to_us(U64 raw) { return (static_cast(raw) * 1000000.0) * get_timer_info().mClockFrequencyInv; }; - inline double raw_to_ms(U64 raw) { return (static_cast(raw) * 1000.0) * get_timer_info().mClockFrequencyInv; }; - - using RecordSceneTime = RecordTime; - using RecordAvatarTime = RecordTime; - using RecordAttachmentTime = RecordTime; - -}// namespace FSPerfStats - -// helper function -using RATptr = std::unique_ptr; -template -static inline RATptr trackMyAttachment(const T * vobj) -{ - if( !vobj ){return nullptr;}; - const T* rootAtt{vobj}; - if( rootAtt->isAttachment() ) - { - FSZone; - while( !rootAtt->isRootEdit() ) - { - rootAtt = (T*)(rootAtt->getParent()); - } - if( ((T*)(rootAtt->getParent()))->getID() == gAgentID ) - { - #if TRACY_ENABLE - FSZoneNC( "trackMyAttachment:self", tracy::Color::Red ); - auto& str = rootAtt->getAttachmentItemName(); - FSZoneText(str.c_str(), str.size()); - FSZoneText( rootAtt->getAttachmentItemID().asString().c_str(), 36); - #endif - return( std::make_unique( rootAtt->getAttachmentItemID(), FSPerfStats::StatType_t::RENDER_GEOMETRY) ); - } - } - return nullptr; -}; -// -#endif \ No newline at end of file diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index 962491fb1f..0bcdd48710 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -1682,6 +1682,10 @@ configure_file( list(APPEND viewer_HEADER_FILES ${CMAKE_CURRENT_BINARY_DIR}/fsversionvalues.h) # + # Performance stast support + list(APPEND viewer_SOURCE_FILES fsperfstats.cpp) + list(APPEND viewer_HEADER_FILES fsperfstats.h) + # source_group("CMake Rules" FILES ViewerInstall.cmake) #build_data.json creation moved to viewer_manifest.py MAINT-6413 From ea4f6931ab0ccd2d4602ec89b8864db19ebdd22a Mon Sep 17 00:00:00 2001 From: Beq Date: Wed, 3 Nov 2021 16:07:57 +0000 Subject: [PATCH 194/256] Significantly faster UUID to string TBD merge into the std::string version, for a more general speedup. --- indra/llcommon/lluuid.cpp | 6 +++- indra/llcommon/lluuid.h | 60 ++++++++++++++++++++++++++++++++++++++- 2 files changed, 64 insertions(+), 2 deletions(-) diff --git a/indra/llcommon/lluuid.cpp b/indra/llcommon/lluuid.cpp index 7ff040a602..191f8512e0 100644 --- a/indra/llcommon/lluuid.cpp +++ b/indra/llcommon/lluuid.cpp @@ -44,7 +44,7 @@ #include "lltimer.h" #include "llthread.h" #include "llmutex.h" - +#include "fstelemetry.h" const LLUUID LLUUID::null; const LLTransactionID LLTransactionID::tnull; @@ -155,6 +155,7 @@ U32 janky_fast_random_seeded_bytes(U32 seed, U32 val) // Common to all UUID implementations void LLUUID::toString(std::string& out) const { + FSZone; out = llformat( "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x", (U8)(mData[0]), @@ -217,6 +218,7 @@ BOOL LLUUID::set(const char* in_string, BOOL emit) BOOL LLUUID::set(const std::string& in_string, BOOL emit) { + FSZone; BOOL broken_format = FALSE; // empty strings should make NULL uuid @@ -1027,6 +1029,7 @@ LLUUID::LLUUID() // Copy constructor LLUUID::LLUUID(const LLUUID& rhs) { + FSZone; // Fix for misaligned unsigned ints in LLUUID; by Sovereign Engineer / Shyotl Kuhr //U32 *tmp = (U32 *)mData; //U32 *rhstmp = (U32 *)rhs.mData; @@ -1045,6 +1048,7 @@ LLUUID::LLUUID() // Assignment LLUUID& LLUUID::operator=(const LLUUID& rhs) { + FSZone; // Fix for misaligned unsigned ints in LLUUID; by Sovereign Engineer / Shyotl Kuhr //// No need to check the case where this==&rhs. The branch is slower than the write. //U32 *tmp = (U32 *)mData; diff --git a/indra/llcommon/lluuid.h b/indra/llcommon/lluuid.h index b6399ad094..270a8e7f06 100644 --- a/indra/llcommon/lluuid.h +++ b/indra/llcommon/lluuid.h @@ -29,10 +29,11 @@ #include #include #include +#include // for std::memmove #include "stdtypes.h" #include "llpreprocessor.h" #include - +#include "fstelemetry.h" class LLMutex; const S32 UUID_BYTES = 16; @@ -56,7 +57,9 @@ public: explicit LLUUID(const char *in_string); // Convert from string. explicit LLUUID(const std::string& in_string); // Convert from string. LLUUID(const LLUUID &in); + LLUUID(LLUUID&& rhs) noexcept { FSZone; std::memmove(mData, rhs.mData, sizeof(mData));}; LLUUID &operator=(const LLUUID &rhs); + LLUUID &operator=(LLUUID &&rhs) noexcept {FSZone; std::memmove(mData, rhs.mData, sizeof(mData));return *this;}; ~LLUUID(); @@ -112,6 +115,61 @@ public: void toString(std::string& out) const; void toCompressedString(char *out) const; // Does not allocate memory, needs 17 characters (including \0) void toCompressedString(std::string& out) const; + + // last 4 chars for quick ref - Very lightweight, no nul-term added - provide your own, ensure min 4 bytes. +# define hexnybl(N) (N)>9?((N)-10)+'a':(N)+'0' + inline char * LLUUID::toShortString(char *out) const + { + FSZone; + out[0] = hexnybl(mData[14]>>4); + out[1] = hexnybl(mData[14]&15); + out[2] = hexnybl(mData[15]>>4); + out[3] = hexnybl(mData[15]&15); + return out; + } + // full uuid - Much lighterweight than default, no allocation, or nul-term added - provide your own, ensure min 36 bytes. + inline char * LLUUID::toStringFast(char *out) const + { + FSZone; + out[0] = hexnybl(mData[0]>>4); + out[1] = hexnybl(mData[0]&15); + out[2] = hexnybl(mData[1]>>4); + out[3] = hexnybl(mData[1]&15); + out[4] = hexnybl(mData[2]>>4); + out[5] = hexnybl(mData[2]&15); + out[6] = hexnybl(mData[3]>>4); + out[7] = hexnybl(mData[3]&15); + out[8] = '-'; + out[9] = hexnybl(mData[4]>>4); + out[10] = hexnybl(mData[4]&15); + out[11] = hexnybl(mData[5]>>4); + out[12] = hexnybl(mData[5]&15); + out[13] = '-'; + out[14] = hexnybl(mData[6]>>4); + out[15] = hexnybl(mData[6]&15); + out[16] = hexnybl(mData[7]>>4); + out[17] = hexnybl(mData[7]&15); + out[18] = '-'; + out[19] = hexnybl(mData[8]>>4); + out[20] = hexnybl(mData[8]&15); + out[21] = hexnybl(mData[9]>>4); + out[22] = hexnybl(mData[9]&15); + out[23] = '-'; + out[24] = hexnybl(mData[10]>>4); + out[25] = hexnybl(mData[10]&15); + out[26] = hexnybl(mData[11]>>4); + out[27] = hexnybl(mData[11]&15); + out[28] = hexnybl(mData[12]>>4); + out[29] = hexnybl(mData[12]&15); + out[30] = hexnybl(mData[13]>>4); + out[31] = hexnybl(mData[13]&15); + out[32] = hexnybl(mData[14]>>4); + out[33] = hexnybl(mData[14]&15); + out[34] = hexnybl(mData[15]>>4); + out[35] = hexnybl(mData[15]&15); + return out; + } + std::string asString() const; std::string getString() const; From 0c999849cc7e2805bf761f234b697a4726b06599 Mon Sep 17 00:00:00 2001 From: Beq Date: Wed, 3 Nov 2021 16:26:01 +0000 Subject: [PATCH 195/256] relocated and extended perfstats Major changes in processing. More configuration options to control tweaks tweak application migrated from performance floater to service etc. --- indra/newview/fsperfstats.cpp | 344 ++++++++++++++++++++++++++ indra/newview/fsperfstats.h | 439 ++++++++++++++++++++++++++++++++++ 2 files changed, 783 insertions(+) create mode 100644 indra/newview/fsperfstats.cpp create mode 100644 indra/newview/fsperfstats.h diff --git a/indra/newview/fsperfstats.cpp b/indra/newview/fsperfstats.cpp new file mode 100644 index 0000000000..a62559c335 --- /dev/null +++ b/indra/newview/fsperfstats.cpp @@ -0,0 +1,344 @@ +/** + * @file fsperfstats.cpp + * @brief Stats collection to support perf floater and auto tune + * + * $LicenseInfo:firstyear=2021&license=fsviewerlgpl$ + * Phoenix Firestorm Viewer Source Code + * Copyright (C) 2021, The Phoenix Firestorm Project, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * The Phoenix Firestorm Project, Inc., 1831 Oakwood Drive, Fairmont, Minnesota 56031-3225 USA + * http://www.firestormviewer.org + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" +#include "fsperfstats.h" +#include "llcontrol.h" +#include "pipeline.h" + +extern LLControlGroup gSavedSettings; + +namespace FSPerfStats +{ + #ifdef USAGE_TRACKING + std::atomic inUse{0}; + std::atomic inUseAvatar{0}; +#endif + std::atomic tunedAvatars{0}; + U32 targetFPS; // desired FPS + U32 renderAvatarMaxART{50000}; // highest render time we'll allow without culling features + U32 fpsTuningStrategy{0}; // linked to FSTuningFPSStrategy + U32 lastGlobalPrefChange{0}; + std::mutex bufferToggleLock{}; + bool autoTune{false}; + + U32 smoothingPeriods{1}; // number of frames to smooth over. + + + std::atomic StatsRecorder::writeBuffer{0}; + bool StatsRecorder::collectionEnabled{true}; + LLUUID StatsRecorder::focusAv{LLUUID::null}; + std::array StatsRecorder::statsDoubleBuffer{ {} }; + std::array StatsRecorder::max{ {} }; + std::array StatsRecorder::sum{ {} }; + + + StatsRecorder::StatsRecorder():q(1024*16),t(&StatsRecorder::run) + { + // create a queue + // create a thread to consume from the queue + + FSPerfStats::targetFPS = gSavedSettings.getU32("FSTargetFPS"); + FSPerfStats::autoTune = gSavedSettings.getBOOL("FSAutoTuneFPS"); + FSPerfStats::renderAvatarMaxART = gSavedSettings.getBOOL("FSRenderAvatarMaxART"); + FSPerfStats::smoothingPeriods = gSavedSettings.getU32("FSPerfFloaterSmoothingPeriods"); + + t.detach(); + } + + // static + void StatsRecorder::toggleBuffer() + { + FSZone; + using ST = StatType_t; + + bool unreliable{false}; + + auto& sceneStats = statsDoubleBuffer[writeBuffer][static_cast(ObjType_t::OT_GENERAL)][LLUUID::null]; + auto& lastStats = statsDoubleBuffer[writeBuffer ^ 1][static_cast(ObjType_t::OT_GENERAL)][LLUUID::null]; + + static constexpr std::initializer_list sceneStatsToAvg = { + StatType_t::RENDER_FRAME, + StatType_t::RENDER_DISPLAY, + StatType_t::RENDER_HUDS, + StatType_t::RENDER_UI, + StatType_t::RENDER_SWAP, + // RENDER_LFS, + // RENDER_MESHREPO, + StatType_t::RENDER_IDLE }; + + static constexpr std::initializer_list avatarStatsToAvg = { + StatType_t::RENDER_GEOMETRY, + StatType_t::RENDER_SHADOWS, + StatType_t::RENDER_COMBINED, + StatType_t::RENDER_IDLE }; + + + if( sceneStats[static_cast(StatType_t::RENDER_FPSLIMIT)] != 0 || sceneStats[static_cast(StatType_t::RENDER_SLEEP)] != 0 ) + { + unreliable = true; + } + + if(!unreliable) + { + // only use these stats when things are reliable. + + for(auto & statEntry : sceneStatsToAvg) + { + auto avg = lastStats[static_cast(statEntry)]; + auto val = sceneStats[static_cast(statEntry)]; + sceneStats[static_cast(statEntry)] = avg + (val/smoothingPeriods) - (avg/smoothingPeriods); + // LL_INFOS("scenestats") << "Scenestat: " << static_cast(statEntry) << " before=" << avg << " new=" << val << " newavg=" << statsDoubleBuffer[writeBuffer][static_cast(ObjType_t::OT_GENERAL)][LLUUID::null][static_cast(statEntry)] << LL_ENDL; + } + + auto& statsMap = statsDoubleBuffer[writeBuffer][static_cast(ObjType_t::OT_ATTACHMENT)]; + for(auto& stat_entry : statsMap) + { + auto val = stat_entry.second[static_cast(ST::RENDER_COMBINED)]; + if(val>smoothingPeriods){ + auto avg = statsDoubleBuffer[writeBuffer ^ 1][static_cast(ObjType_t::OT_ATTACHMENT)][stat_entry.first][static_cast(ST::RENDER_COMBINED)]; + stat_entry.second[static_cast(ST::RENDER_COMBINED)] = avg + (val/smoothingPeriods) - (avg/smoothingPeriods); + } + } + + + auto& statsMapAv = statsDoubleBuffer[writeBuffer][static_cast(ObjType_t::OT_AVATAR)]; + for(auto& stat_entry : statsMapAv) + { + for(auto& stat : avatarStatsToAvg) + { + auto val = stat_entry.second[static_cast(stat)]; + if(val>smoothingPeriods) + { + auto avg = statsDoubleBuffer[writeBuffer ^ 1][static_cast(ObjType_t::OT_AVATAR)][stat_entry.first][static_cast(stat)]; + stat_entry.second[static_cast(stat)] = avg + (val/smoothingPeriods) - (avg/smoothingPeriods); + } + } + } + + // swap the buffers + if(enabled()) + { + std::lock_guard lock{bufferToggleLock}; + writeBuffer ^= 1; + }; // note we are relying on atomic updates here. The risk is low and would cause minor errors in the stats display. + } + + // clean the write maps in all cases. + auto& statsTypeMatrix = statsDoubleBuffer[writeBuffer]; + for(auto& statsMap : statsTypeMatrix) + { + FSZoneN("Clear stats maps"); + for(auto& stat_entry : statsMap) + { + std::fill_n(stat_entry.second.begin() ,static_cast(ST::STATS_COUNT),0); + } + statsMap.clear(); + } + for(int i=0; i< static_cast(ObjType_t::OT_COUNT); i++) + { + FSZoneN("clear max/sum"); + max[writeBuffer][i].fill(0); + sum[writeBuffer][i].fill(0); + } + + // and now adjust the visuals. + if(autoTune) + { + updateAvatarParams(); + } + } + + // clear buffers when we change region or need a hard reset. + // static + void StatsRecorder::clearStatsBuffers() + { + FSZone; + using ST = StatType_t; + + auto& statsTypeMatrix = statsDoubleBuffer[writeBuffer]; + for(auto& statsMap : statsTypeMatrix) + { + FSZoneN("Clear stats maps"); + for(auto& stat_entry : statsMap) + { + std::fill_n(stat_entry.second.begin() ,static_cast(ST::STATS_COUNT),0); + } + statsMap.clear(); + } + for(int i=0; i< static_cast(ObjType_t::OT_COUNT); i++) + { + FSZoneN("clear max/sum"); + max[writeBuffer][i].fill(0); + sum[writeBuffer][i].fill(0); + } + // swap the clean buffers in + if(enabled()) + { + std::lock_guard lock{bufferToggleLock}; + writeBuffer ^= 1; + }; + // repeat before we start processing new stuff + for(auto& statsMap : statsTypeMatrix) + { + FSZoneN("Clear stats maps"); + for(auto& stat_entry : statsMap) + { + std::fill_n(stat_entry.second.begin() ,static_cast(ST::STATS_COUNT),0); + } + statsMap.clear(); + } + for(int i=0; i< static_cast(ObjType_t::OT_COUNT); i++) + { + FSZoneN("clear max/sum"); + max[writeBuffer][i].fill(0); + sum[writeBuffer][i].fill(0); + } + } + + + // static + void StatsRecorder::updateAvatarParams() + { + LLCachedControl drawDistance(gSavedSettings, "RenderFarClip"); + auto av_render_max_raw = FSPerfStats::StatsRecorder::getMax(ObjType_t::OT_AVATAR, FSPerfStats::StatType_t::RENDER_COMBINED); + // Is our target frame time lower than current? If so we need to take action to reduce draw overheads. + // cumulative avatar time (includes idle processing, attachments and base av) + auto tot_avatar_time_raw = FSPerfStats::StatsRecorder::getSum(ObjType_t::OT_AVATAR, FSPerfStats::StatType_t::RENDER_COMBINED); + // sleep time is basically forced sleep when window out of focus + auto tot_sleep_time_raw = FSPerfStats::StatsRecorder::getSceneStat(FSPerfStats::StatType_t::RENDER_SLEEP); + // similar to sleep time, induced by FPS limit + auto tot_limit_time_raw = FSPerfStats::StatsRecorder::getSceneStat(FSPerfStats::StatType_t::RENDER_FPSLIMIT); + + + // the time spent this frame on the "doFrame" call. Treated as "tot time for frame" + auto tot_frame_time_raw = FSPerfStats::StatsRecorder::getSceneStat(FSPerfStats::StatType_t::RENDER_FRAME); + + if(tot_sleep_time_raw != 0 || tot_limit_time_raw !=0 ) + { + // Note: we do not average sleep and fpslimit, therefore we cannot reliably use them here. + // if at some point we need to, the averaging will need to take this into account or + // we forever think we're in the background due to residuals. + LL_DEBUGS() << "No tuning when not in focus" << LL_ENDL; + return; + } + + // LL_INFOS() << "Effective FPS:" << (1000000/FSPerfStats::raw_to_us(tot_frame_time_raw)) << " Target:" << targetFPS << LL_ENDL; + + // The frametime budget we have based on the target FPS selected + auto target_frame_time_raw = (U64)llround(get_timer_info().mClockFrequency/(targetFPS==0?1:targetFPS)); + // LL_INFOS() << "Effective FPS(raw):" << tot_frame_time_raw << " Target:" << target_frame_time_raw << LL_ENDL; + + // 1) Is the target frame tim lower than current? + if( target_frame_time_raw <= tot_frame_time_raw ) + { + // if so we've got work to do + + // how much of the frame was spent on non avatar related work? + U32 non_avatar_time_raw = tot_frame_time_raw - tot_avatar_time_raw; + + // If the target frame time < non avatar frame time thne adjusting avatars is only goin gto get us so far. + U64 target_avatar_time_raw; + if(target_frame_time_raw < non_avatar_time_raw) + { + // we cannnot do this by avatar adjustment alone. + if((gFrameCount - FSPerfStats::lastGlobalPrefChange) > 10) // give changes a short time to take effect. + { + if(FSPerfStats::fpsTuningStrategy == 1) + { + // 1 - hack the water to opaque. all non opaque have a significan t hit, this is a big boost. + if(LLPipeline::RenderReflectionDetail != -2) + { + gSavedSettings.setS32("RenderReflectionDetail", -2); + FSPerfStats::lastGlobalPrefChange = gFrameCount; + } + else // deliberately "else" here so we only do these in steps + { + // step down the DD by 10m per update + auto new_dd = (drawDistance>42)?(drawDistance - 10) : 32; + gSavedSettings.setF32("RenderFarClip", new_dd); + FSPerfStats::lastGlobalPrefChange = gFrameCount; + } + } + } + // slam the avatar time to 0 "imposter all the things" + target_avatar_time_raw = 0; + } + else + { + // desired avatar budget. + target_avatar_time_raw = target_frame_time_raw - non_avatar_time_raw; + } + + if( target_avatar_time_raw < tot_avatar_time_raw ) + { + // we need to spend less time drawing avatars to meet our budget + // Note: working in usecs now cos reasons. + U32 new_render_limit_us {0}; + // max render this frame may be higher than the last (cos new entrants and jitter) so make sure we are heading in the right direction + if(FSPerfStats::raw_to_us(av_render_max_raw) < renderAvatarMaxART) + { + new_render_limit_us = FSPerfStats::raw_to_us(av_render_max_raw); + } + else + { + new_render_limit_us = renderAvatarMaxART; + } + new_render_limit_us -= 100; + // bounce at the bottom to prevent "no limit" + if(new_render_limit_us <= 0 || new_render_limit_us >1000000) + { + new_render_limit_us = 100; + } + // assign the new value + renderAvatarMaxART = new_render_limit_us; + // LL_DEBUGS() << "AUTO_TUNE: avatar_budget adjusted to:" << new_render_limit_us << LL_ENDL; + } + // LL_DEBUGS() << "AUTO_TUNE: Target frame time:"<< FSPerfStats::raw_to_us(target_frame_time_raw) << "usecs (non_avatar is " << FSPerfStats::raw_to_us(non_avatar_time_raw) << "usecs) Max cost limited=" << renderAvatarMaxART << LL_ENDL; + } + else if( FSPerfStats::raw_to_us(target_frame_time_raw) > (FSPerfStats::raw_to_us(tot_frame_time_raw) + renderAvatarMaxART) ) + { + if( FSPerfStats::tunedAvatars > 0 ) + { + // if we have more time to spare let's shift up little in the hope we'll restore an avatar. + renderAvatarMaxART += 10; + } + if(drawDistance < 180.) // TODO(Beq) make this less arbitrary + { + gSavedSettings.setF32("RenderFarClip", drawDistance + 10.); + } + if( (FSPerfStats::raw_to_us(target_frame_time_raw) * 1.5) > FSPerfStats::raw_to_us(tot_frame_time_raw) && + FSPerfStats::tunedAvatars == 0 && + drawDistance >= 128. ) + { + // if everything else is "max" and we have 50% headroom let's knock the water quality up a notch at a time. + auto water = gSavedSettings.getS32("RenderReflectionDetail"); + gSavedSettings.setS32("RenderReflectionDetail", water+1); + } + } + } +} \ No newline at end of file diff --git a/indra/newview/fsperfstats.h b/indra/newview/fsperfstats.h new file mode 100644 index 0000000000..677d4e1419 --- /dev/null +++ b/indra/newview/fsperfstats.h @@ -0,0 +1,439 @@ +#pragma once +#ifndef FS_PERFSTATS_H_INCLUDED +#define FS_PERFSTATS_H_INCLUDED +/** + * @file fsperfstats.h + * @brief Statistics collection to support autotune and perf flaoter. + * + * $LicenseInfo:firstyear=2021&license=fsviewerlgpl$ + * Phoenix Firestorm Viewer Source Code + * Copyright (C) 2021, The Phoenix Firestorm Project, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * The Phoenix Firestorm Project, Inc., 1831 Oakwood Drive, Fairmont, Minnesota 56031-3225 USA + * http://www.firestormviewer.org + * $/LicenseInfo$ + */ + +#include +#include +#include +#include +#include +#include "lluuid.h" +#include "lltimer.h" +#include "blockingconcurrentqueue.h" +#include "llapp.h" +#include "fstelemetry.h" + +// Additional logging options. These can skew inworld numbers so onyl use for debugging and tracking issues +#ifdef FS_HAS_TELEMETRY_SUPPORT +// USAGE_TRACKING - displays overlapping stats that may imply double counting. +// ATTACHMENT_TRACKING - displays detailed tracking info for Avatar and Attachment. very heavy overhead. +// #define USAGE_TRACKING +// #define ATTACHMENT_TRACKING +#else +#undef USAGE_TRACKING +#undef ATTACHMENT_TRACKING +#endif + +extern U32 gFrameCount; +extern LLUUID gAgentID; +namespace FSPerfStats +{ +#ifdef USAGE_TRACKING + extern std::atomic inUse; + extern std::atomic inUseAvatar; +#endif + extern std::atomic tunedAvatars; + extern U32 targetFPS; // desired FPS + extern U32 renderAvatarMaxART; + extern U32 fpsTuningStrategy; + extern U32 lastGlobalPrefChange; + extern std::mutex bufferToggleLock; + extern bool autoTune; + + extern U32 smoothingPeriods; // number of frames to smooth over. + + enum class ObjType_t{ + OT_GENERAL=0, // Also Unknown. Used for n/a type stats such as scenery + OT_AVATAR, + OT_ATTACHMENT, + OT_HUD, + OT_COUNT + }; + enum class StatType_t{ + RENDER_GEOMETRY=0, + RENDER_SHADOWS, + RENDER_HUDS, + RENDER_UI, + RENDER_COMBINED, + RENDER_SWAP, + RENDER_FRAME, + RENDER_DISPLAY, + RENDER_SLEEP, + RENDER_LFS, + RENDER_MESHREPO, + RENDER_FPSLIMIT, + RENDER_FPS, + RENDER_IDLE, + RENDER_DONE, // toggle buffer & clearbuffer (see processUpdate for hackery) + STATS_COUNT + }; + + struct StatsRecord + { + StatType_t statType; + ObjType_t objType; + LLUUID avID; + LLUUID objID; + uint64_t time; + uint32_t count; + bool isRigged; + }; + + class StatsRecorder{ + using Queue = moodycamel::BlockingConcurrentQueue; + public: + + static inline StatsRecorder& getInstance() + { + static StatsRecorder instance; + // volatile int dummy{}; + return instance; + } + static inline void setFocusAv(const LLUUID& avID){focusAv = avID;}; + static inline const LLUUID& getFocusAv(){return (focusAv);}; + static inline void send(StatsRecord&& u){StatsRecorder::getInstance().q.enqueue(u);}; + static void endFrame(){StatsRecorder::getInstance().q.enqueue(StatsRecord{StatType_t::RENDER_DONE, ObjType_t::OT_GENERAL, LLUUID::null, LLUUID::null, 0});}; + static void clearStats(){StatsRecorder::getInstance().q.enqueue(StatsRecord{StatType_t::RENDER_DONE, ObjType_t::OT_GENERAL, LLUUID::null, LLUUID::null, 1});}; + + static inline void setEnabled(bool on_or_off){collectionEnabled=on_or_off;}; + static inline void enable() { collectionEnabled=true; }; + static inline void disable() { collectionEnabled=false; }; + static inline bool enabled() { return(collectionEnabled); }; + + static inline int getReadBufferIndex() { return (writeBuffer ^ 1); }; + // static inline const StatsTypeMatrix& getCurrentStatsMatrix(){ return statsDoubleBuffer[getReadBufferIndex()];} + static inline uint64_t get(ObjType_t otype, LLUUID id, StatType_t type) + { + return statsDoubleBuffer[getReadBufferIndex()][static_cast(otype)][id][static_cast(type)]; + } + static inline uint64_t getSceneStat(StatType_t type) + { + return statsDoubleBuffer[getReadBufferIndex()][static_cast(ObjType_t::OT_GENERAL)][LLUUID::null][static_cast(type)]; + } + + static inline uint64_t getSum(ObjType_t otype, StatType_t type) + { + return sum[getReadBufferIndex()][static_cast(otype)][static_cast(type)]; + } + static inline uint64_t getMax(ObjType_t otype, StatType_t type) + { + return max[getReadBufferIndex()][static_cast(otype)][static_cast(type)]; + } + + static void StatsRecorder::updateAvatarParams(); + private: + StatsRecorder(); + +// StatsArray is a uint64_t for each possible statistic type. + using StatsArray = std::array(FSPerfStats::StatType_t::STATS_COUNT)>; + using StatsMap = std::unordered_map; + using StatsTypeMatrix = std::array(FSPerfStats::ObjType_t::OT_COUNT)>; + using StatsSummaryArray = std::array(FSPerfStats::ObjType_t::OT_COUNT)>; + + static std::atomic writeBuffer; + static LLUUID focusAv; + static std::array statsDoubleBuffer; + static std::array max; + static std::array sum; + static bool collectionEnabled; + + + void processUpdate(const StatsRecord& upd) + { + FSZone; + // LL_INFOS("perfstats") << "processing update:" << LL_ENDL; + using ST = StatType_t; + // Note: nullptr is used as the key for global stats + static char avstr[36]; + static char obstr[36]; + if(upd.statType == StatType_t::RENDER_DONE && upd.objType == ObjType_t::OT_GENERAL && upd.time == 0) + { + // LL_INFOS("perfstats") << "End of Frame Toggle Buffer:" << gFrameCount << LL_ENDL; + toggleBuffer(); + return; + } + if(upd.statType == StatType_t::RENDER_DONE && upd.objType == ObjType_t::OT_GENERAL && upd.time == 1) + { + // LL_INFOS("perfstats") << "New region - clear buffers:" << gFrameCount << LL_ENDL; + clearStatsBuffers(); + return; + } + + auto ot{upd.objType}; + auto& key{upd.objID}; + auto& avKey{upd.avID}; + auto type {upd.statType}; + auto val {upd.time}; + + FSZoneText(key.toStringFast(obstr),36); + FSZoneText(avKey.toStringFast(avstr),36); + FSZoneValue(val); + + if(ot == ObjType_t::OT_GENERAL) + { + // LL_INFOS("perfstats") << "General update:" << LL_ENDL; + doUpd(key, ot, type,val); + return; + } + + if(ot == ObjType_t::OT_AVATAR) + { + // LL_INFOS("perfstats") << "Avatar update:" << LL_ENDL; + doUpd(avKey, ot, type, val); + return; + } + + if(ot == ObjType_t::OT_ATTACHMENT) + { + if( !upd.isRigged ) + { + // For all attachments that are not rigged we add them to the avatar (for all avatars) cost. + doUpd(avKey, ObjType_t::OT_AVATAR, type, val); + } + if( avKey == focusAv ) + { + // For attachments that are for the focusAv (self for now) we record them for the attachment/complexity view + // LL_INFOS("perfstats") << "frame: " << gFrameCount << " Attachment update("<< (type==StatType_t::RENDER_GEOMETRY?"GEOMETRY":"SHADOW") << ": " << key.asString() << " = " << val << LL_ENDL; + doUpd(key, ot, type, val); + } + else + { + // LL_INFOS("perfstats") << "frame: " << gFrameCount << " non-self Att update("<< (type==StatType_t::RENDER_GEOMETRY?"GEOMETRY":"SHADOW") << ": " << key.asString() << " = " << val << " for av " << avKey.asString() << LL_ENDL; + } + } + + } + + static inline void doUpd(const LLUUID& key, ObjType_t ot, StatType_t type, uint64_t val) + { + FSZone; + using ST = StatType_t; + StatsMap& stm {statsDoubleBuffer[writeBuffer][static_cast(ot)]}; + auto& thisAsset = stm[key]; + + thisAsset[static_cast(type)] += val; + thisAsset[static_cast(ST::RENDER_COMBINED)] += val; + + sum[writeBuffer][static_cast(ot)][static_cast(type)] += val; + sum[writeBuffer][static_cast(ot)][static_cast(ST::RENDER_COMBINED)] += val; + + if(max[writeBuffer][static_cast(ot)][static_cast(type)] < thisAsset[static_cast(type)]) + { + max[writeBuffer][static_cast(ot)][static_cast(type)] = thisAsset[static_cast(type)]; + } + if(max[writeBuffer][static_cast(ot)][static_cast(ST::RENDER_COMBINED)] < thisAsset[static_cast(ST::RENDER_COMBINED)]) + { + max[writeBuffer][static_cast(ot)][static_cast(ST::RENDER_COMBINED)] = thisAsset[static_cast(ST::RENDER_COMBINED)]; + } + } + + static void toggleBuffer(); + static void clearStatsBuffers(); + + // thread entry + static void run() + { + StatsRecord upd[10]; + auto& instance {StatsRecorder::getInstance()}; + FSThreadName( "PerfStats" ); + + while( !LLApp::isExiting() ) + { + FSZone("perf batch"); + auto count = instance.q.wait_dequeue_bulk_timed(upd, 10, std::chrono::milliseconds(5)); + if(count) + { + // LL_INFOS("perfstats") << "processing " << count << " updates." << LL_ENDL; + for(auto i =0; i < count; i++) + { + instance.processUpdate(upd[i]); + } + } + } + } + + Queue q; + std::thread t; + + ~StatsRecorder() = default; + StatsRecorder(const StatsRecorder&) = delete; + StatsRecorder& operator=(const StatsRecorder&) = delete; + + }; + + template + class RecordTime + { + + private: + RecordTime(const RecordTime&) = delete; + RecordTime() = delete; + U64 start; + public: + StatsRecord stat; + + RecordTime( const LLUUID& av, const LLUUID& id, StatType_t type, bool isRiggedAtt=false):start{LLTimer::getCurrentClockCount()}, + stat{type, ObjTypeDiscriminator, std::move(av), std::move(id), 0, isRiggedAtt}{ + 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); + FSPerfStats::inUse++; + if( !stat.isRigged ) {FSPerfStats::inUseAvatar++;}; + FSPlot("InUse", (int64_t)FSPerfStats::inUse); + FSPlot("InUseAv", (int64_t)FSPerfStats::inUseAvatar); + } + #endif + + }; + + template < typename = std::enable_if_t > + RecordTime( StatType_t type ):RecordTime(LLUUID::null, LLUUID::null, type ) + { + FSZone; + }; + + template < typename = std::enable_if_t > + RecordTime( const LLUUID & av, StatType_t type ):RecordTime(std::move(av), LLUUID::null, type) + { + FSZoneC(tracy::Color::Purple); + + #ifdef USAGE_TRACKING + if(FSPerfStats::inUseAvatar){FSZoneText("OVERLAP AVATAR",14);} + + FSPlot("InUseAv", (int64_t)FSPerfStats::inUseAvatar); + FSPerfStats::inUseAvatar++; + FSPlot("InUseAv", (int64_t)FSPerfStats::inUseAvatar); + #endif + + }; + + ~RecordTime() + { + if(!FSPerfStats::StatsRecorder::enabled()) + { + return; + } + + + FSZoneC(tracy::Color::Red); + + #ifdef USAGE_TRACKING + if (stat.objType == FSPerfStats::ObjType_t::OT_ATTACHMENT) + { + FSPlot("InUse", (int64_t)FSPerfStats::inUse); + --FSPerfStats::inUse; + FSPlot("InUse", (int64_t)FSPerfStats::inUse); + } + if( ( stat.objType == FSPerfStats::ObjType_t::OT_ATTACHMENT && !stat.isRigged ) || stat.objType == FSPerfStats::ObjType_t::OT_AVATAR ) + { + FSPlot("InUseAv", (int64_t)FSPerfStats::inUseAvatar); + --FSPerfStats::inUseAvatar; + FSPlot("InUseAv", (int64_t)FSPerfStats::inUseAvatar); + } + #endif + + stat.time = LLTimer::getCurrentClockCount() - start; + + #ifdef ATTACHMENT_TRACKING + static char obstr[36]; + static char avstr[36]; + FSZoneValue(static_cast(stat.objType)); + FSZoneText(stat.avID.toStringFast(avstr), 36); + FSZoneText(stat.objID.toStringFast(obstr), 36); + FSZoneValue(stat.time); + #endif + + StatsRecorder::send(std::move(stat)); + }; + + + }; + + + inline double raw_to_ns(U64 raw) { return (static_cast(raw) * 1000000000.0) * get_timer_info().mClockFrequencyInv; }; + inline double raw_to_us(U64 raw) { return (static_cast(raw) * 1000000.0) * get_timer_info().mClockFrequencyInv; }; + inline double raw_to_ms(U64 raw) { return (static_cast(raw) * 1000.0) * get_timer_info().mClockFrequencyInv; }; + + using RecordSceneTime = RecordTime; + using RecordAvatarTime = RecordTime; + using RecordAttachmentTime = RecordTime; + +};// namespace FSPerfStats + +// helper functions +using RATptr = std::unique_ptr; + +template +static inline void trackAttachments(const T * vobj, bool isRigged, RATptr* ratPtrp) +{ + if( !vobj ){ ratPtrp->reset(); return;}; + + const T* rootAtt{vobj}; + if( rootAtt->isAttachment() ) + { + FSZone; + + while( !rootAtt->isRootEdit() ) + { + rootAtt = (T*)(rootAtt->getParent()); + } + + auto avPtr = (T*)(rootAtt->getParent()); + if(!avPtr){ratPtrp->reset(); return;} + + auto& av = avPtr->getID(); + auto& obj = rootAtt->getAttachmentItemID(); + if(!*ratPtrp || (*ratPtrp)->stat.objID != obj || (*ratPtrp)->stat.avID != av ) + { + #if TRACY_ENABLE && defined(ATTACHMENT_TRACKING) + FSZoneNC( "trackAttachments:new", tracy::Color::Red ); + auto& str = rootAtt->getAttachmentItemName(); + FSZoneText(str.c_str(), str.size()); + static char avStr[36]; + av.toStringFast(avStr); + static char obStr[4]; + obj.toShortString(obStr); + FSZoneText( avStr, 36); + FSZoneText( obStr, 4); + #endif + if(*ratPtrp){ratPtrp->reset();}; // deliberately reset to ensure destruction before construction of replacement. + *ratPtrp = std::make_unique( av, obj, ( (LLPipeline::sShadowRender)?FSPerfStats::StatType_t::RENDER_SHADOWS : FSPerfStats::StatType_t::RENDER_GEOMETRY ), isRigged ); + } + (*ratPtrp)->stat.count++; + } + return; +}; + +#endif \ No newline at end of file From e70415f1d77f6ad4ab1e581900d2b42436118bd9 Mon Sep 17 00:00:00 2001 From: Andrey Lihatskiy Date: Wed, 3 Nov 2021 20:01:57 +0200 Subject: [PATCH 196/256] SL-16299 Added entitlements for the app bundle signing --- indra/newview/slplugin.entitlements | 12 ++++++++++++ indra/newview/viewer_manifest.py | 2 +- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/indra/newview/slplugin.entitlements b/indra/newview/slplugin.entitlements index a1c430a57a..1c2f2e5d2c 100644 --- a/indra/newview/slplugin.entitlements +++ b/indra/newview/slplugin.entitlements @@ -4,5 +4,17 @@ com.apple.security.cs.allow-unsigned-executable-memory + com.apple.security.automation.apple-events + + com.apple.security.cs.allow-jit + + 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 + diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py index b932f43141..1d82e95e98 100755 --- a/indra/newview/viewer_manifest.py +++ b/indra/newview/viewer_manifest.py @@ -1309,7 +1309,7 @@ class DarwinManifest(ViewerManifest): self.run_command(['codesign', '--force', '--timestamp', '--keychain', viewer_keychain, '--sign', identity, cef_path]) self.run_command(['codesign', '--force', '--timestamp', '--keychain', viewer_keychain, '--sign', identity, greenlet_path]) self.run_command(['codesign', '--verbose', '--deep', '--force', '--entitlements', self.src_path_of("slplugin.entitlements"), '--options', 'runtime', '--keychain', viewer_keychain, '--sign', identity, slplugin_path]) - self.run_command(['codesign', '--verbose', '--deep', '--force', '--options', 'runtime', '--keychain', viewer_keychain, '--sign', identity, app_in_dmg]) + self.run_command(['codesign', '--verbose', '--deep', '--force', '--entitlements', self.src_path_of("slplugin.entitlements"), '--options', 'runtime', '--keychain', viewer_keychain, '--sign', identity, app_in_dmg]) signed=True # if no exception was raised, the codesign worked except ManifestError as err: if sign_attempts: From 855738570703c33c48c67f59dd1769fa7d7de97c Mon Sep 17 00:00:00 2001 From: Beq Date: Wed, 3 Nov 2021 19:13:12 +0000 Subject: [PATCH 197/256] rationalised changes for stats collection includes additional tracy scopes for testing most changes are to allow batching stat updates to reduce overhead. --- indra/newview/llappviewer.cpp | 25 +++++-- indra/newview/llcontrolavatar.cpp | 2 + indra/newview/lldrawpool.cpp | 45 ++++++++---- indra/newview/lldrawpoolalpha.cpp | 29 ++++---- indra/newview/lldrawpoolavatar.cpp | 37 +++++++--- indra/newview/lldrawpoolbump.cpp | 43 ++++++----- indra/newview/lldrawpoolmaterials.cpp | 18 +---- indra/newview/lldrawpoolsimple.cpp | 14 +--- indra/newview/llface.cpp | 12 ++-- indra/newview/llstartup.cpp | 10 ++- indra/newview/llviewerdisplay.cpp | 7 +- indra/newview/llviewerjointmesh.cpp | 9 +-- indra/newview/llviewerwindow.cpp | 4 +- indra/newview/llvoavatar.cpp | 100 ++++++++++++++++---------- indra/newview/llvoavatar.h | 18 ++++- indra/newview/llvovolume.cpp | 35 ++++----- indra/newview/pipeline.cpp | 2 +- 17 files changed, 251 insertions(+), 159 deletions(-) diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index cd81d0b5f2..575ff2cfa0 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -1571,6 +1571,7 @@ void LLAppViewer::initMaxHeapSize() } static LLTrace::BlockTimerStatHandle FTM_MESSAGES("System Messages"); +static LLTrace::BlockTimerStatHandle FTM_MESSAGES2("System Messages2"); static LLTrace::BlockTimerStatHandle FTM_SLEEP("Sleep"); static LLTrace::BlockTimerStatHandle FTM_YIELD("Yield"); @@ -1633,7 +1634,7 @@ bool LLAppViewer::frame() bool LLAppViewer::doFrame() { { - FSPerfStats::RecordSceneTime T (const LLUUID{}, FSPerfStats::StatType_t::RENDER_FRAME); + FSPerfStats::RecordSceneTime T (FSPerfStats::StatType_t::RENDER_FRAME); LLEventPump& mainloop(LLEventPumps::instance().obtain("mainloop")); LLSD newFrame; @@ -1716,7 +1717,7 @@ bool LLAppViewer::doFrame() if (gViewerWindow) { - LL_RECORD_BLOCK_TIME(FTM_MESSAGES); + LL_RECORD_BLOCK_TIME(FTM_MESSAGES2); if (!restoreErrorTrap()) { LL_WARNS() << " Someone took over my signal/exception handler (post messagehandling)!" << LL_ENDL; @@ -1739,7 +1740,10 @@ bool LLAppViewer::doFrame() // canonical per-frame event mainloop.post(newFrame); // give listeners a chance to run + { + FSZoneN("Main:Coro"); llcoro::suspend(); + } if (!LLApp::isExiting()) { @@ -1756,6 +1760,8 @@ bool LLAppViewer::doFrame() && (gHeadlessClient || !gViewerWindow->getShowProgress()) && !gFocusMgr.focusLocked()) { + FSPerfStats::RecordSceneTime T (FSPerfStats::StatType_t::RENDER_IDLE); + FSZoneN("Main:JoystickKeyboard"); joystick->scanJoystick(); gKeyboard->scanKeyboard(); gViewerInput.scanMouse(); @@ -1771,7 +1777,7 @@ bool LLAppViewer::doFrame() // Update state based on messages, user input, object idle. { - FSPerfStats::RecordSceneTime T (const LLUUID{}, FSPerfStats::StatType_t::RENDER_IDLE); + FSPerfStats::RecordSceneTime T (FSPerfStats::StatType_t::RENDER_IDLE); pauseMainloopTimeout(); // *TODO: Remove. Messages shouldn't be stalling for 20+ seconds! @@ -1783,6 +1789,7 @@ bool LLAppViewer::doFrame() if (gDoDisconnect && (LLStartUp::getStartupState() == STATE_STARTED)) { + FSZoneN("Shutdown:SaveSnapshot"); pauseMainloopTimeout(); saveFinalSnapshot(); disconnectViewer(); @@ -1793,6 +1800,7 @@ bool LLAppViewer::doFrame() // *TODO: Should we run display() even during gHeadlessClient? DK 2011-02-18 if (!LLApp::isExiting() && !gHeadlessClient && gViewerWindow) { + FSZoneN("Main:Display"); pingMainloopTimeout("Main:Display"); gGLActive = TRUE; @@ -1816,8 +1824,11 @@ bool LLAppViewer::doFrame() // pingMainloopTimeout("Main:Snapshot"); + { + FSZoneN("Main:Snapshot"); LLFloaterSnapshot::update(); // take snapshots LLFloaterOutfitSnapshot::update(); + } gGLActive = FALSE; } } @@ -1845,13 +1856,13 @@ bool LLAppViewer::doFrame() || !gFocusMgr.getAppHasFocus())) { // Sleep if we're not rendering, or the window is minimized. - static LLCachedControl s_bacground_yeild_time(gSavedSettings, "BackgroundYieldTime", 40); + static LLCachedControl s_bacground_yeild_time(gSavedSettings, "back", 40); S32 milliseconds_to_sleep = llclamp((S32)s_bacground_yeild_time, 0, 1000); // don't sleep when BackgroundYieldTime set to 0, since this will still yield to other threads // of equal priority on Windows if (milliseconds_to_sleep > 0) { - FSPerfStats::RecordSceneTime T ( LLUUID{}, FSPerfStats::StatType_t::RENDER_SLEEP ); + FSPerfStats::RecordSceneTime T ( FSPerfStats::StatType_t::RENDER_SLEEP ); ms_sleep(milliseconds_to_sleep); // also pause worker threads during this wait period LLAppViewer::getTextureCache()->pause(); @@ -1929,7 +1940,7 @@ bool LLAppViewer::doFrame() if (fsLimitFramerate && LLStartUp::getStartupState() == STATE_STARTED && !gTeleportDisplay && !logoutRequestSent() && max_fps > F_APPROXIMATELY_ZERO) { // Sleep a while to limit frame rate. - FSPerfStats::RecordSceneTime T (const LLUUID{}, FSPerfStats::StatType_t::RENDER_FPSLIMIT); + FSPerfStats::RecordSceneTime T ( FSPerfStats::StatType_t::RENDER_FPSLIMIT ); F32 min_frame_time = 1.f / (F32)max_fps; S32 milliseconds_to_sleep = llclamp((S32)((min_frame_time - frameTimer.getElapsedTimeF64()) * 1000.f), 0, 1000); if (milliseconds_to_sleep > 0) @@ -1971,7 +1982,6 @@ bool LLAppViewer::doFrame() LLPROFILE_UPDATE(); } FSPerfStats::StatsRecorder::endFrame(); - return ! LLApp::isRunning(); } @@ -5781,6 +5791,7 @@ void LLAppViewer::idle() if (!(logoutRequestSent() && hasSavedFinalSnapshot())) { + FSPerfStats::tunedAvatars=0; // reset the number of avatars that have been tweaked. gObjectList.update(gAgent); } } diff --git a/indra/newview/llcontrolavatar.cpp b/indra/newview/llcontrolavatar.cpp index 8cd0332be9..6cdd30e698 100644 --- a/indra/newview/llcontrolavatar.cpp +++ b/indra/newview/llcontrolavatar.cpp @@ -80,6 +80,7 @@ void LLControlAvatar::initInstance() const LLVOAvatar *LLControlAvatar::getAttachedAvatar() const { + FSZone; if (mRootVolp && mRootVolp->isAttachment()) { return mRootVolp->getAvatarAncestor(); @@ -89,6 +90,7 @@ const LLVOAvatar *LLControlAvatar::getAttachedAvatar() const LLVOAvatar *LLControlAvatar::getAttachedAvatar() { + FSZone; if (mRootVolp && mRootVolp->isAttachment()) { return mRootVolp->getAvatarAncestor(); diff --git a/indra/newview/lldrawpool.cpp b/indra/newview/lldrawpool.cpp index 373e86cbb9..2ebd699b15 100644 --- a/indra/newview/lldrawpool.cpp +++ b/indra/newview/lldrawpool.cpp @@ -389,10 +389,21 @@ void LLRenderPass::renderGroup(LLSpatialGroup* group, U32 type, U32 mask, BOOL t { LLSpatialGroup::drawmap_elem_t& draw_info = group->mDrawMap[type]; + std::unique_ptr ratPtr{}; // Perf stats for (LLSpatialGroup::drawmap_elem_t::iterator k = draw_info.begin(); k != draw_info.end(); ++k) { LLDrawInfo *pparams = *k; if (pparams) { + // Capture render times + if(pparams->mFace) + { + LLViewerObject* vobj = pparams->mFace->getViewerObject(); + if(vobj->isAttachment()) + { + trackAttachments( vobj, pparams->mFace->isState(LLFace::RIGGED),&ratPtr); + } + } + // pushBatch(*pparams, mask, texture); } } @@ -405,11 +416,22 @@ void LLRenderPass::renderTexture(U32 type, U32 mask, BOOL batch_textures) void LLRenderPass::pushBatches(U32 type, U32 mask, BOOL texture, BOOL batch_textures) { + std::unique_ptr ratPtr{}; for (LLCullResult::drawinfo_iterator i = gPipeline.beginRenderMap(type); i != gPipeline.endRenderMap(type); ++i) { LLDrawInfo* pparams = *i; if (pparams) { + // Capture render times + if(pparams->mFace) + { + LLViewerObject* vobj = pparams->mFace->getViewerObject(); + if(vobj->isAttachment()) + { + trackAttachments( vobj, pparams->mFace->isState(LLFace::RIGGED),&ratPtr); + } + } + // pushBatch(*pparams, mask, texture, batch_textures); } } @@ -417,11 +439,22 @@ void LLRenderPass::pushBatches(U32 type, U32 mask, BOOL texture, BOOL batch_text void LLRenderPass::pushMaskBatches(U32 type, U32 mask, BOOL texture, BOOL batch_textures) { + std::unique_ptr ratPtr{}; for (LLCullResult::drawinfo_iterator i = gPipeline.beginRenderMap(type); i != gPipeline.endRenderMap(type); ++i) { LLDrawInfo* pparams = *i; if (pparams) { + // Capture render times + if((*pparams).mFace) + { + LLViewerObject* vobj = (*pparams).mFace->getViewerObject(); + if(vobj->isAttachment()) + { + trackAttachments( vobj, (*pparams).mFace->isState(LLFace::RIGGED),&ratPtr); + } + } + // if (LLGLSLShader::sCurBoundShaderPtr) { LLGLSLShader::sCurBoundShaderPtr->setMinimumAlpha(pparams->mAlphaMaskCutoff); @@ -453,18 +486,6 @@ void LLRenderPass::applyModelMatrix(const LLDrawInfo& params) void LLRenderPass::pushBatch(LLDrawInfo& params, U32 mask, BOOL texture, BOOL batch_textures) { - FSZone; - // Capture render times - std::unique_ptr T{}; - if(params.mFace) - { - LLViewerObject* vobj = params.mFace->getViewerObject(); - if(vobj->isAttachment()) - { - T = trackMyAttachment( vobj ); - } - } - // if (!params.mCount) { return; diff --git a/indra/newview/lldrawpoolalpha.cpp b/indra/newview/lldrawpoolalpha.cpp index 932c0957f9..c6ec168cc2 100644 --- a/indra/newview/lldrawpoolalpha.cpp +++ b/indra/newview/lldrawpoolalpha.cpp @@ -351,17 +351,17 @@ void LLDrawPoolAlpha::renderAlphaHighlight(U32 mask) { LLSpatialGroup::drawmap_elem_t& draw_info = group->mDrawMap[LLRenderPass::PASS_ALPHA]; + std::unique_ptr ratPtr{}; // Render time Stats collection for (LLSpatialGroup::drawmap_elem_t::iterator k = draw_info.begin(); k != draw_info.end(); ++k) { LLDrawInfo& params = **k; // Capture render times - std::unique_ptr T{}; if(params.mFace) { LLViewerObject* vobj = (LLViewerObject *)params.mFace->getViewerObject(); if(vobj->isAttachment()) { - T = trackMyAttachment(vobj); + trackAttachments( vobj, params.mFace->isState(LLFace::RIGGED), &ratPtr ); } } // @@ -499,15 +499,15 @@ void LLDrawPoolAlpha::renderSimples(U32 mask, std::vector& simples) simple_shader->uniform1f(LLShaderMgr::ENVIRONMENT_INTENSITY, 0.0f); simple_shader->uniform1f(LLShaderMgr::EMISSIVE_BRIGHTNESS, 0.0f); bool use_shaders = gPipeline.canUseVertexShaders(); + std::unique_ptr ratPtr{};// Render time Stats collection for (LLDrawInfo* draw : simples) { // Capture render times FSZoneN("Simples"); - std::unique_ptr T{}; auto vobj = draw->mFace?draw->mFace->getViewerObject():nullptr; if(vobj && vobj->isAttachment()) { - T = trackMyAttachment(vobj); + trackAttachments( vobj, draw->mFace->isState(LLFace::RIGGED), &ratPtr ); } // bool tex_setup = TexSetup(draw, use_shaders, false, simple_shader); @@ -526,15 +526,15 @@ void LLDrawPoolAlpha::renderFullbrights(U32 mask, std::vector& full fullbright_shader->bind(); fullbright_shader->uniform1f(LLShaderMgr::EMISSIVE_BRIGHTNESS, 1.0f); bool use_shaders = gPipeline.canUseVertexShaders(); + std::unique_ptr ratPtr{}; // Render time Stats collection for (LLDrawInfo* draw : fullbrights) { // Capture render times FSZoneN("Fullbrights"); - std::unique_ptr T{}; auto vobj = draw->mFace?draw->mFace->getViewerObject():nullptr; if(vobj && vobj->isAttachment()) { - T = trackMyAttachment(vobj); + trackAttachments( vobj, draw->mFace->isState(LLFace::RIGGED), &ratPtr ); } // bool tex_setup = TexSetup(draw, use_shaders, false, fullbright_shader); @@ -550,20 +550,21 @@ void LLDrawPoolAlpha::renderFullbrights(U32 mask, std::vector& full void LLDrawPoolAlpha::renderMaterials(U32 mask, std::vector& materials) { + FSZone;// Tracy markup LLGLSLShader::bindNoShader(); current_shader = NULL; gPipeline.enableLightsDynamic(); bool use_shaders = gPipeline.canUseVertexShaders(); + std::unique_ptr ratPtr{}; // Render time Stats collection for (LLDrawInfo* draw : materials) { // Capture render times FSZoneN("Materials"); - std::unique_ptr T{}; auto vobj = draw->mFace?draw->mFace->getViewerObject():nullptr; if(vobj && vobj->isAttachment()) { - T = trackMyAttachment(vobj); + trackAttachments( vobj, draw->mFace->isState(LLFace::RIGGED), &ratPtr ); } // @@ -647,15 +648,15 @@ void LLDrawPoolAlpha::renderEmissives(U32 mask, std::vector& emissi // don't touch color, add to alpha (glow) gGL.blendFunc(LLRender::BF_ZERO, LLRender::BF_ONE, LLRender::BF_ONE, LLRender::BF_ONE); bool use_shaders = gPipeline.canUseVertexShaders(); + std::unique_ptr ratPtr{}; // Render time Stats collection for (LLDrawInfo* draw : emissives) { // Capture render times FSZoneN("Emissives"); - std::unique_ptr T{}; auto vobj = draw->mFace?draw->mFace->getViewerObject():nullptr; if(vobj && vobj->isAttachment()) { - T = trackMyAttachment(vobj); + trackAttachments( vobj, draw->mFace->isState(LLFace::RIGGED), &ratPtr ); } // @@ -716,6 +717,7 @@ void LLDrawPoolAlpha::renderAlpha(U32 mask, S32 pass) LLSpatialGroup::drawmap_elem_t& draw_info = group->mDrawMap[LLRenderPass::PASS_ALPHA]; + std::unique_ptr ratPtr{}; // Render time Stats collection for (LLSpatialGroup::drawmap_elem_t::iterator k = draw_info.begin(); k != draw_info.end(); ++k) { LLDrawInfo& params = **k; @@ -732,14 +734,13 @@ void LLDrawPoolAlpha::renderAlpha(U32 mask, S32 pass) } // Capture render times - std::unique_ptr T{}; if(params.mFace) { LLViewerObject* vobj = (LLViewerObject *)params.mFace->getViewerObject(); if(vobj->isAttachment()) { - T = trackMyAttachment(vobj); + trackAttachments( vobj, params.mFace->isState(LLFace::RIGGED), &ratPtr ); } } // @@ -923,7 +924,9 @@ void LLDrawPoolAlpha::renderAlpha(U32 mask, S32 pass) gGL.matrixMode(LLRender::MM_MODELVIEW); } } - + // performance stats + ratPtr.reset(); // force the final batch to terminate to avoid double counting on the subsidiary batches for FB and Emmissives + // if (batch_fullbrights) { light_enabled = false; diff --git a/indra/newview/lldrawpoolavatar.cpp b/indra/newview/lldrawpoolavatar.cpp index 8ea7b3338b..06da6e4504 100644 --- a/indra/newview/lldrawpoolavatar.cpp +++ b/indra/newview/lldrawpoolavatar.cpp @@ -590,7 +590,7 @@ void LLDrawPoolAvatar::renderShadow(S32 pass) // (impostor && oa == LLVOAvatar::AOA_JELLYDOLL)) // Note: Impostors should not cast shadows, also all JDs are impostor nowadays so we do not need the extra check at all. // also no shadows if the shadows are causing this avatar to breach the limit. - if ( avatarp->isTooSlow(true) || impostor || (oa == LLVOAvatar::AOA_INVISIBLE) ) + if ( avatarp->isTooSlowWithShadows() || impostor || (oa == LLVOAvatar::AOA_INVISIBLE) ) // { // No shadows for jellydolled or invisible avs. @@ -1492,6 +1492,7 @@ void LLDrawPoolAvatar::renderAvatars(LLVOAvatar* single_avatar, S32 pass) } else { + FSZoneN("Find avatarp"); // Tracy markup const LLFace *facep = mDrawFace[0]; if (!facep->getDrawable()) { @@ -1507,7 +1508,10 @@ void LLDrawPoolAvatar::renderAvatars(LLVOAvatar* single_avatar, S32 pass) FSPerfStats::RecordAvatarTime T(avatarp->getID(), FSPerfStats::StatType_t::RENDER_GEOMETRY); // Add avatar hitbox debug + { + FSZoneN("cached control renderhitboxes"); static LLCachedControl render_hitbox(gSavedSettings, "DebugRenderHitboxes", false); + if (render_hitbox && pass == 2) { FSZoneN("render_hitbox"); @@ -1589,8 +1593,11 @@ void LLDrawPoolAvatar::renderAvatars(LLVOAvatar* single_avatar, S32 pass) } } } - // - + }// +// rendertime Tracy annotations +{ + FSZoneN("check fully_loaded"); +// if (!single_avatar && !avatarp->isFullyLoaded() ) { FSZoneN("avatar not loaded"); @@ -1616,9 +1623,14 @@ void LLDrawPoolAvatar::renderAvatars(LLVOAvatar* single_avatar, S32 pass) // don't render please return; } +}// rendertime Tracy annotations BOOL impostor = !LLPipeline::sImpostorRender && avatarp->isImpostor() && !single_avatar; +// rendertime Tracy annotations +{ + FSZoneN("check appearance"); +// if (( /*avatarp->isInMuteList() // Partially undo MAINT-5700: Draw imposter for muted avatars ||*/ impostor || (LLVOAvatar::AOA_NORMAL != avatarp->getOverallAppearance() && !avatarp->needsImpostorUpdate()) ) && pass != 0) @@ -1626,6 +1638,7 @@ void LLDrawPoolAvatar::renderAvatars(LLVOAvatar* single_avatar, S32 pass) { //don't draw anything but the impostor for impostored avatars return; } +}// rendertime Tracy annotations if (pass == 0 && !impostor && LLPipeline::sUnderWaterRender) { //don't draw foot shadows under water @@ -2258,6 +2271,7 @@ void LLDrawPoolAvatar::renderRigged(LLVOAvatar* avatar, U32 type, bool glow) stop_glerror(); + std::unique_ptr ratPtr{};// Perf stats capture for (U32 i = 0; i < mRiggedFace[type].size(); ++i) { LLFace* face = mRiggedFace[type][i]; @@ -2281,12 +2295,12 @@ void LLDrawPoolAvatar::renderRigged(LLVOAvatar* avatar, U32 type, bool glow) continue; } - auto self = avatar->isSelf(); - std::unique_ptr T{}; - if(self && vobj->isAttachment()) + // Capture render times + if(vobj->isAttachment()) { - T = trackMyAttachment(vobj); + trackAttachments( vobj, true, &ratPtr); } + // LLVolume* volume = vobj->getVolume(); S32 te = face->getTEOffset(); @@ -2582,10 +2596,14 @@ static LLTrace::BlockTimerStatHandle FTM_RIGGED_VBO("Rigged VBO"); void LLDrawPoolAvatar::updateRiggedVertexBuffers(LLVOAvatar* avatar) { LL_RECORD_BLOCK_TIME(FTM_RIGGED_VBO); - + // render stats collection + if(!avatar)return; // in theory this never happens...right + FSPerfStats::RecordAvatarTime T( avatar->getID(), ( (LLPipeline::sShadowRender)?FSPerfStats::StatType_t::RENDER_SHADOWS : FSPerfStats::StatType_t::RENDER_GEOMETRY ) ); + // //update rigged vertex buffers for (U32 type = 0; type < NUM_RIGGED_PASSES; ++type) { + std::unique_ptr ratPtr{}; for (U32 i = 0; i < mRiggedFace[type].size(); ++i) { FSZoneN("updateRiggedVBO"); @@ -2603,10 +2621,9 @@ void LLDrawPoolAvatar::updateRiggedVertexBuffers(LLVOAvatar* avatar) continue; } // Capture render times - std::unique_ptr T{}; if(vobj->isAttachment()) { - T = trackMyAttachment(vobj); + trackAttachments( vobj, true, &ratPtr ); } // LLVolume* volume = vobj->getVolume(); diff --git a/indra/newview/lldrawpoolbump.cpp b/indra/newview/lldrawpoolbump.cpp index a61d7116e7..d49c0d95d3 100644 --- a/indra/newview/lldrawpoolbump.cpp +++ b/indra/newview/lldrawpoolbump.cpp @@ -645,16 +645,16 @@ void LLDrawPoolBump::renderGroup(LLSpatialGroup* group, U32 type, U32 mask, BOOL FSZone; LLSpatialGroup::drawmap_elem_t& draw_info = group->mDrawMap[type]; + std::unique_ptr ratPtr{}; // render time capture for (LLSpatialGroup::drawmap_elem_t::iterator k = draw_info.begin(); k != draw_info.end(); ++k) { LLDrawInfo& params = **k; // Capture render times - std::unique_ptr T{}; LLViewerObject* vobj = (LLViewerObject *)params.mFace->getViewerObject(); - if(vobj->isAttachment()) + if( vobj && vobj->isAttachment() ) { - T= trackMyAttachment(vobj); + trackAttachments( vobj, params.mFace->isState(LLFace::RIGGED), &ratPtr ); } // applyModelMatrix(params); @@ -898,10 +898,21 @@ void LLDrawPoolBump::renderDeferred(S32 pass) U32 mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0 | LLVertexBuffer::MAP_TANGENT | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_COLOR; + std::unique_ptr ratPtr{}; // render time capture for (LLCullResult::drawinfo_iterator i = begin; i != end; ++i) { LLDrawInfo& params = **i; - + // Capture render times + if(params.mFace) + { + LLViewerObject* vobj = (LLViewerObject *)params.mFace->getViewerObject(); + + if(vobj && vobj->isAttachment()) + { + trackAttachments( vobj, params.mFace->isState(LLFace::RIGGED), &ratPtr ); + } + } + // gDeferredBumpProgram.setMinimumAlpha(params.mAlphaMaskCutoff); LLDrawPoolBump::bindBumpMap(params, bump_channel); pushBatch(params, mask, TRUE); @@ -1509,9 +1520,21 @@ void LLDrawPoolBump::renderBump(U32 type, U32 mask) LLCullResult::drawinfo_iterator begin = gPipeline.beginRenderMap(type); LLCullResult::drawinfo_iterator end = gPipeline.endRenderMap(type); + std::unique_ptr ratPtr{}; // render time capture for (LLCullResult::drawinfo_iterator i = begin; i != end; ++i) { LLDrawInfo& params = **i; + // Capture render times + if(params.mFace) + { + LLViewerObject* vobj = (LLViewerObject *)params.mFace->getViewerObject(); + + if( vobj && vobj->isAttachment() ) + { + trackAttachments( vobj, params.mFace->isState(LLFace::RIGGED), &ratPtr ); + } + } + // if (LLDrawPoolBump::bindBumpMap(params)) { @@ -1523,18 +1546,6 @@ void LLDrawPoolBump::renderBump(U32 type, U32 mask) void LLDrawPoolBump::pushBatch(LLDrawInfo& params, U32 mask, BOOL texture, BOOL batch_textures) { FSZone; - // Capture render times - std::unique_ptr T{}; - if(params.mFace) - { - LLViewerObject* vobj = (LLViewerObject *)params.mFace->getViewerObject(); - - if(vobj->isAttachment()) - { - T = trackMyAttachment(vobj); - } - } - // applyModelMatrix(params); bool tex_setup = false; diff --git a/indra/newview/lldrawpoolmaterials.cpp b/indra/newview/lldrawpoolmaterials.cpp index 2b1304c9eb..34dbc350b9 100644 --- a/indra/newview/lldrawpoolmaterials.cpp +++ b/indra/newview/lldrawpoolmaterials.cpp @@ -136,19 +136,19 @@ void LLDrawPoolMaterials::renderDeferred(S32 pass) LLCullResult::drawinfo_iterator begin = gPipeline.beginRenderMap(type); LLCullResult::drawinfo_iterator end = gPipeline.endRenderMap(type); + std::unique_ptr ratPtr{}; // render time capture for (LLCullResult::drawinfo_iterator i = begin; i != end; ++i) { LLDrawInfo& params = **i; // Capture render times - std::unique_ptr T{}; if(params.mFace) { LLViewerObject* vobj = (LLViewerObject *)params.mFace->getViewerObject(); - if(vobj->isAttachment()) + if( vobj && vobj->isAttachment() ) { - T = trackMyAttachment(vobj); + trackAttachments( vobj, params.mFace->isState(LLFace::RIGGED), &ratPtr ); } } // @@ -187,18 +187,6 @@ void LLDrawPoolMaterials::bindNormalMap(LLViewerTexture* tex) void LLDrawPoolMaterials::pushBatch(LLDrawInfo& params, U32 mask, BOOL texture, BOOL batch_textures) { - // Capture render times - std::unique_ptr T{}; - if(params.mFace) - { - LLViewerObject* vobj = (LLViewerObject *)params.mFace->getViewerObject(); - - if(vobj->isAttachment()) - { - T = trackMyAttachment(vobj); - } - } - // applyModelMatrix(params); bool tex_setup = false; diff --git a/indra/newview/lldrawpoolsimple.cpp b/indra/newview/lldrawpoolsimple.cpp index b82b8571c7..05ac2fad6a 100644 --- a/indra/newview/lldrawpoolsimple.cpp +++ b/indra/newview/lldrawpoolsimple.cpp @@ -153,18 +153,6 @@ void LLDrawPoolGlow::render(S32 pass) void LLDrawPoolGlow::pushBatch(LLDrawInfo& params, U32 mask, BOOL texture, BOOL batch_textures) { - // Capture render times - std::unique_ptr T{}; - if(params.mFace) - { - LLViewerObject* vobj = (LLViewerObject *)params.mFace->getViewerObject(); - - if(vobj->isAttachment()) - { - T = trackMyAttachment(vobj); - } - } - // //gGL.diffuseColor4ubv(params.mGlowColor.mV); LLRenderPass::pushBatch(params, mask, texture, batch_textures); } @@ -237,7 +225,7 @@ void LLDrawPoolSimple::render(S32 pass) LLGLDisable blend(GL_BLEND); { //render simple - LL_RECORD_BLOCK_TIME(FTM_RENDER_SIMPLE); + LL_RECORD_BLOCK_TIME(FTM_RENDER_SIMPLE); gPipeline.enableLightsDynamic(); if (mShaderLevel > 0) diff --git a/indra/newview/llface.cpp b/indra/newview/llface.cpp index 2bb989fb4f..c28fbfc369 100644 --- a/indra/newview/llface.cpp +++ b/indra/newview/llface.cpp @@ -643,11 +643,13 @@ void renderFace(LLDrawable* drawable, LLFace *face) LLVOVolume* vobj = drawable->getVOVolume(); if (vobj) { - std::unique_ptr T{}; - if(vobj->isAttachment()) - { - T = trackMyAttachment(vobj); - } + // Placeholder - This function emits drawcalls but is only used in one place and not useful for stats. + // TODO(Beq) if we need this consider moving it to llSelectMgr loop instead to reduce overhead. + // std::unique_ptr ratPtr{}; + // if(vobj->isAttachment()) + // { + // trackAttachments(vobj, LLPipeline::sShadowRender, &ratPtr); + // } LLVolume* volume = NULL; if (drawable->isState(LLDrawable::RIGGED)) diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index 9343e9b707..5e3ec0d269 100644 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -211,7 +211,7 @@ #include "llenvironment.h" #include "llstacktrace.h" - +#include "fsperfstats.h" #if LL_WINDOWS #include "lldxhardware.h" #endif @@ -2158,6 +2158,10 @@ bool idle_startup() update_static_eyes(); // + // + gAgent.addRegionChangedCallback(boost::bind(&FSPerfStats::StatsRecorder::clearStats)); + // + // *Note: this is where gWorldMap used to be initialized. // register null callbacks for audio until the audio system is initialized @@ -4260,6 +4264,10 @@ bool process_login_success_response(U32 &first_sim_size_x, U32 &first_sim_size_y // unpack login data needed by the application text = response["agent_id"].asString(); if(!text.empty()) gAgentID.set(text); + // Performance floater initialisation + FSPerfStats::StatsRecorder::setEnabled(gSavedSettings.getBOOL("FSPerfStatsCaptureEnabled")); + FSPerfStats::StatsRecorder::setFocusAv(gAgentID); + // // gDebugInfo["AgentID"] = text; // [SL:KB] - Patch: Viewer-CrashReporting | Checked: 2010-11-16 (Catznip-2.6.0a) | Added: Catznip-2.4.0b if (gCrashSettings.getBOOL("CrashSubmitName")) diff --git a/indra/newview/llviewerdisplay.cpp b/indra/newview/llviewerdisplay.cpp index 63cd695a37..fe78e0df51 100644 --- a/indra/newview/llviewerdisplay.cpp +++ b/indra/newview/llviewerdisplay.cpp @@ -281,6 +281,7 @@ static LLTrace::BlockTimerStatHandle FTM_EEP_UPDATE("Env Update"); // Paint the display! void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot) { + FSPerfStats::RecordSceneTime T (FSPerfStats::StatType_t::RENDER_DISPLAY); // render time capture - This is the main stat for overall rendering. LL_RECORD_BLOCK_TIME(FTM_RENDER); LLViewerCamera& camera = LLViewerCamera::instance(); // Factor out calls to getInstance @@ -1193,7 +1194,7 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot) void render_hud_attachments() { - FSPerfStats::RecordSceneTime T (LLUUID{}, FSPerfStats::StatType_t::RENDER_HUDS); + FSPerfStats::RecordSceneTime T ( FSPerfStats::StatType_t::RENDER_HUDS); // render time capture - Primary contributor to HUDs (though these end up in render batches) gGL.matrixMode(LLRender::MM_PROJECTION); gGL.pushMatrix(); gGL.matrixMode(LLRender::MM_MODELVIEW); @@ -1401,7 +1402,7 @@ bool setup_hud_matrices(const LLRect& screen_region) void render_ui(F32 zoom_factor, int subfield) { - FSPerfStats::RecordSceneTime T (const LLUUID{}, FSPerfStats::StatType_t::RENDER_UI); + FSPerfStats::RecordSceneTime T ( FSPerfStats::StatType_t::RENDER_UI ); // render time capture - Primary UI stat can have HUD time overlap (TODO) LL_RECORD_BLOCK_TIME(FTM_RENDER_UI); LLGLState::checkStates(); @@ -1487,7 +1488,7 @@ static LLTrace::BlockTimerStatHandle FTM_SWAP("Swap"); void swap() { - FSPerfStats::RecordSceneTime T (const LLUUID{}, FSPerfStats::StatType_t::RENDER_SWAP); + FSPerfStats::RecordSceneTime T ( FSPerfStats::StatType_t::RENDER_SWAP ); // render time capture - Swap buffer time - can signify excessive data transfer to/from GPU LL_RECORD_BLOCK_TIME(FTM_SWAP); if (gDisplaySwapBuffers) diff --git a/indra/newview/llviewerjointmesh.cpp b/indra/newview/llviewerjointmesh.cpp index 4d98fb9aef..e873057191 100644 --- a/indra/newview/llviewerjointmesh.cpp +++ b/indra/newview/llviewerjointmesh.cpp @@ -232,14 +232,15 @@ U32 LLViewerJointMesh::drawShape( F32 pixelArea, BOOL first_pass, BOOL is_dummy) return 0; } - - std::unique_ptr T{}; + // render time capture + // TODO(Beq) This path does not appear to have attachments. Prove this then remove. + std::unique_ptr ratPtr{}; auto vobj = mFace->getViewerObject(); if( vobj && vobj->isAttachment() ) { - T = trackMyAttachment(vobj); + trackAttachments( vobj, mFace->isState(LLFace::RIGGED), &ratPtr ); } - +// U32 triangle_count = 0; S32 diffuse_channel = LLDrawPoolAvatar::sDiffuseChannel; diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp index dab506d650..55a067eae7 100644 --- a/indra/newview/llviewerwindow.cpp +++ b/indra/newview/llviewerwindow.cpp @@ -3809,13 +3809,13 @@ void append_xui_tooltip(LLView* viewp, LLToolTip::Params& params) } } -static LLTrace::BlockTimerStatHandle ftm("Update UI"); +static LLTrace::BlockTimerStatHandle FTM_UPDATE_UI("Update UI"); // rename to sensible symbol // Update UI based on stored mouse position from mouse-move // event processing. void LLViewerWindow::updateUI() { - LL_RECORD_BLOCK_TIME(ftm); + LL_RECORD_BLOCK_TIME(FTM_UPDATE_UI); // rename to sensible symbol static std::string last_handle_msg; diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp index 67f905d9f9..52ab2c0ee2 100644 --- a/indra/newview/llvoavatar.cpp +++ b/indra/newview/llvoavatar.cpp @@ -602,7 +602,7 @@ bool LLVOAvatar::sLimitNonImpostors = false; // True unless RenderAvatarMaxNonIm F32 LLVOAvatar::sRenderDistance = 256.f; S32 LLVOAvatar::sNumVisibleAvatars = 0; S32 LLVOAvatar::sNumLODChangesThisFrame = 0; -U64 LLVOAvatar::sRenderTimeCap_ns {0}; +U64 LLVOAvatar::sRenderTimeLimit_ns {0}; // time limit used for render time control // const LLUUID LLVOAvatar::sStepSoundOnLand("e8af4a28-aa83-4310-a7c4-c047e15ea0df"); - Commented out for FIRE-3169: Option to change the default footsteps sound const LLUUID LLVOAvatar::sStepSounds[LL_MCODE_END] = { @@ -2697,7 +2697,10 @@ void LLVOAvatar::idleUpdate(LLAgent &agent, const F64 &time) LL_INFOS() << "Warning! Idle on dead avatar" << LL_ENDL; return; } - + // record time and refresh "tooSlow" status + FSPerfStats::RecordAvatarTime T(getID(), FSPerfStats::StatType_t::RENDER_IDLE); // per avatar "idle" time. + updateTooSlow(); + // ; // Use LLCachedControl static LLCachedControl disable_all_render_types(gSavedSettings, "DisableAllRenderTypes"); if (!(gPipeline.hasRenderType(mIsControlAvatar ? LLPipeline::RENDER_TYPE_CONTROL_AV : LLPipeline::RENDER_TYPE_AVATAR)) @@ -2741,7 +2744,7 @@ void LLVOAvatar::idleUpdate(LLAgent &agent, const F64 &time) // } - LLScopedContextString str("avatar_idle_update " + getFullname()); + // LLScopedContextString str("avatar_idle_update " + getFullname()); // remove unused scoped string checkTextureLoading() ; @@ -4212,6 +4215,7 @@ void LLVOAvatar::slamPosition() bool LLVOAvatar::isVisuallyMuted() { + FSZone; // Tracy accounting for imposter testing. bool muted = false; // FIRE-11783: Always visually mute avatars that are muted @@ -4264,6 +4268,7 @@ bool LLVOAvatar::isVisuallyMuted() bool LLVOAvatar::isInMuteList() const { + FSZone; // Tracy accounting for imposter testing. bool muted = false; F64 now = LLFrameTimer::getTotalSeconds(); if (now < mCachedMuteListUpdateTime) @@ -4697,13 +4702,13 @@ void LLVOAvatar::updateFootstepSounds() void LLVOAvatar::computeUpdatePeriod() { bool visually_muted = isVisuallyMuted(); - bool slow = isTooSlow();// the geometry alone is forcing this to be slow so we must imposter + bool slow = isTooSlowWithoutShadows();// the geometry alone is forcing this to be slow so we must imposter if (mDrawable.notNull() && slow && isVisible() && (!isSelf() || visually_muted) && !isUIAvatar() - && (sLimitNonImpostors || visually_muted || slow) // imposter slow avatars irrespective of nonimposter setting. + && (sLimitNonImpostors || visually_muted || slow) // imposter slow avatars irrespective of nonimposter setting. && !mNeedsAnimUpdate && !sFreezeCounter) { @@ -5577,6 +5582,7 @@ bool LLVOAvatar::shouldAlphaMask() //----------------------------------------------------------------------------- U32 LLVOAvatar::renderSkinned() { + FSZone; // Tracy accounting for imposter testing. U32 num_indices = 0; if (!mIsBuilt) @@ -5813,6 +5819,7 @@ U32 LLVOAvatar::renderSkinned() U32 LLVOAvatar::renderTransparent(BOOL first_pass) { + FSZone; // Tracy accounting for render tracking U32 num_indices = 0; if( isWearingWearableType( LLWearableType::WT_SKIRT ) && (isUIAvatar() || isTextureVisible(TEX_SKIRT_BAKED)) ) { @@ -5865,6 +5872,7 @@ U32 LLVOAvatar::renderTransparent(BOOL first_pass) //----------------------------------------------------------------------------- U32 LLVOAvatar::renderRigid() { + FSZone; // Tracy accounting for render tracking U32 num_indices = 0; if (!mIsBuilt) @@ -5914,6 +5922,7 @@ U32 LLVOAvatar::renderRigid() U32 LLVOAvatar::renderImpostor(LLColor4U color, S32 diffuse_channel) { + FSZone; // Tracy accounting for render tracking if (!mImpostor.isComplete()) { return 0; @@ -9126,43 +9135,48 @@ BOOL LLVOAvatar::isFullyLoaded() const } // use Avatar Render Time as complexity metric +// markARTStale - Mark stale and set the frameupdate to now so that we can wait at least one frame to get a revised number. void LLVOAvatar::markARTStale() { - // mark stale and set the frameupdate to now so that we can wait at least one frame. mARTStale=true; mLastARTUpdateFrame = LLFrameTimer::getFrameCount(); } -// default will test only the geometry (combined=false). -// this allows us to disable shadows separately on complex avatars. -//virtual -bool LLVOAvatar::isTooSlow(bool combined) const +// Udpate Avatar state based on render time +void LLVOAvatar::updateTooSlow() { - static LLCachedControl use_render_time(gSavedSettings, "RenderAvatarUseART"); + FSZone; + static LLCachedControl autoTune(gSavedSettings, "FSAutoTuneFPS"); // auto tune enabled? auto now = LLTimer::getElapsedSeconds(); - auto abuse_constness = const_cast(this); + + // mTooSlow - Is the avatar flagged as being slow (includes shadow time) + // mTooSlowWithoutShadows - Is the avatar flagged as being slow even with shadows removed. + // mARTStale - the rendertime we have is stale because of an update. We need to force a re-render to re-assess slowness if( mARTStale ) { - if (LLFrameTimer::getFrameCount() - mLastARTUpdateFrame < 2 ) + if ( LLFrameTimer::getFrameCount() - mLastARTUpdateFrame < 5 ) { - LL_INFOS() << this->getFullname() << " marked stale " << LL_ENDL; - // we've not had a chance to update yet (allow now+1 to be certain a full frame has passed) - return false; + // LL_INFOS() << this->getFullname() << " marked stale " << LL_ENDL; + // we've not had a chance to update yet (allow a few to be certain a full frame has passed) + return; } - abuse_constness->mARTStale = false; - abuse_constness->mARTCapped = false; - LL_INFOS() << this->getFullname() << " refreshed ART combined = " << mRenderTime << " @ " << mLastARTUpdateFrame << LL_ENDL; + mARTStale = false; + mTooSlow = false; + mTooSlowWithoutShadows = false; + // LL_INFOS() << this->getFullname() << " refreshed ART combined = " << mRenderTime << " @ " << mLastARTUpdateFrame << LL_ENDL; } // Either we're not stale or we've updated. + U64 render_time_raw; U64 render_geom_time_raw; - if(!mARTCapped) + if( !mTooSlow ) { - // no cap, so we use the live values + // we are fully rendered, so we use the live values + std::lock_guard lock{FSPerfStats::bufferToggleLock}; render_time_raw = FSPerfStats::StatsRecorder::get(FSPerfStats::ObjType_t::OT_AVATAR, this->getID(), FSPerfStats::StatType_t::RENDER_COMBINED); render_geom_time_raw = FSPerfStats::StatsRecorder::get(FSPerfStats::ObjType_t::OT_AVATAR, this->getID(), FSPerfStats::StatType_t::RENDER_GEOMETRY); } @@ -9172,25 +9186,31 @@ bool LLVOAvatar::isTooSlow(bool combined) const render_time_raw = mRenderTime; render_geom_time_raw = mGeomTime; } - if( (LLVOAvatar::sRenderTimeCap_ns > 0) && (FSPerfStats::raw_to_ns(render_time_raw) >= LLVOAvatar::sRenderTimeCap_ns) ) + if( (LLVOAvatar::sRenderTimeLimit_ns > 0) && + (FSPerfStats::raw_to_ns(render_time_raw) >= LLVOAvatar::sRenderTimeLimit_ns) ) { - if(!mARTCapped) + if( !mTooSlow ) { // if we weren't capped, we are now - abuse_constness->mRenderTime = render_time_raw; - abuse_constness->mGeomTime = render_geom_time_raw; - abuse_constness->mARTStale = false; - abuse_constness->mARTCapped = true; - abuse_constness->mLastARTUpdateFrame = LLFrameTimer::getFrameCount(); - LL_INFOS() << this->getFullname() << " ("<< (combined?"combined":"geometry") << ") mLastART too high = " << FSPerfStats::raw_to_ns(render_time_raw) << " vs ("<< LLVOAvatar::sRenderTimeCap_ns << " set @ " << mLastARTUpdateFrame << LL_ENDL; + mLastARTUpdateFrame = LLFrameTimer::getFrameCount(); + mRenderTime = render_time_raw; + mGeomTime = render_geom_time_raw; + mARTStale = false; + mTooSlow = true; } - // return true only if that is the case in the context of the combined/geom_only flag. - return combined ? true : (render_geom_time_raw >= LLVOAvatar::sRenderTimeCap_ns); + // LL_INFOS() << this->getFullname() << " ("<< (combined?"combined":"geometry") << ") mLastART too high = " << FSPerfStats::raw_to_ns(render_time_raw) << " vs ("<< LLVOAvatar::sRenderTimeCap_ns << " set @ " << mLastARTUpdateFrame << LL_ENDL; + mTooSlowWithoutShadows = (FSPerfStats::raw_to_ns(render_geom_time_raw) >= LLVOAvatar::sRenderTimeLimit_ns); + } + else + { + // LL_INFOS() << this->getFullname() << " ("<< (combined?"combined":"geometry") << ") good render time = " << FSPerfStats::raw_to_ns(render_time_raw) << " vs ("<< LLVOAvatar::sRenderTimeCap_ns << " set @ " << mLastARTUpdateFrame << LL_ENDL; + mTooSlow = false; + mTooSlowWithoutShadows = false; + } + if(mTooSlow) + { + FSPerfStats::tunedAvatars++; // increment the number of avatars that have been tweaked. } - - LL_INFOS() << this->getFullname() << " ("<< (combined?"combined":"geometry") << ") good render time = " << FSPerfStats::raw_to_ns(render_time_raw) << " vs ("<< LLVOAvatar::sRenderTimeCap_ns << " set @ " << mLastARTUpdateFrame << LL_ENDL; - abuse_constness->mARTCapped = false; - return false; } // @@ -11484,11 +11504,14 @@ void LLVOAvatar::updateImpostors() // virtual BOOL LLVOAvatar::isImpostor() { +// render time handling using tooSlow() +// return isVisuallyMuted() || (sLimitNonImpostors && (mUpdatePeriod > 1)); return ( isVisuallyMuted() || - ( (sLimitNonImpostors || isTooSlow(false) ) && + ( (sLimitNonImpostors || isTooSlowWithoutShadows() ) && (mUpdatePeriod > 1) ) ); +// } BOOL LLVOAvatar::shouldImpostor(const F32 rank_factor) @@ -11501,12 +11524,14 @@ BOOL LLVOAvatar::shouldImpostor(const F32 rank_factor) { return true; } +// render time handling using tooSlow() static LLCachedControl render_jellys_As_imposters(gSavedSettings, "RenderJellyDollsAsImpostors"); - if (isTooSlow(false) && render_jellys_As_imposters) + if (isTooSlowWithoutShadows() && render_jellys_As_imposters) { return true; } +// return sLimitNonImpostors && (mVisibilityRank > sMaxNonImpostors * rank_factor); } @@ -11798,7 +11823,6 @@ void LLVOAvatar::accountRenderComplexityForObject( LLHUDComplexity hud_object_complexity; hud_object_complexity.objectName = attached_object->getAttachmentItemName(); hud_object_complexity.objectId = attached_object->getAttachmentItemID(); - hud_object_complexity.objectPtr = attached_object; std::string joint_name; gAgentAvatarp->getAttachedPointName(attached_object->getAttachmentItemID(), joint_name); hud_object_complexity.jointName = joint_name; diff --git a/indra/newview/llvoavatar.h b/indra/newview/llvoavatar.h index c034a3b5aa..a1747f890d 100644 --- a/indra/newview/llvoavatar.h +++ b/indra/newview/llvoavatar.h @@ -355,7 +355,7 @@ public: static F32 sPhysicsLODFactor; // user-settable physics LOD factor static BOOL sJointDebug; // output total number of joints being touched for each avatar static BOOL sDebugAvatarRotation; - static U64 sRenderTimeCap_ns; // nanosecond time limit for avatar rendering 0 is unlimited. + static U64 sRenderTimeLimit_ns; // nanosecond time limit for avatar rendering 0 is unlimited. static LLPartSysData sCloud; //-------------------------------------------------------------------- @@ -369,7 +369,17 @@ public: //-------------------------------------------------------------------- public: BOOL isFullyLoaded() const; - virtual bool isTooSlow(bool combined = false) const; + // check and return current state relative to limits + // default will test only the geometry (combined=false). + // this allows us to disable shadows separately on complex avatars. + inline bool isTooSlowWithShadows() const {return mTooSlow;}; + inline bool isTooSlowWithoutShadows() const {return mTooSlowWithoutShadows;}; + inline bool isTooSlow(bool combined = false) const + { + return(combined?mTooSlow:mTooSlowWithoutShadows); + } + void LLVOAvatar::updateTooSlow(); + // virtual bool isTooComplex() const; // FIRE-29012: Standalone animesh avatars get affected by complexity limit; changed to virtual bool visualParamWeightsAreDefault(); virtual bool getIsCloud() const; @@ -414,6 +424,10 @@ private: U64 mGeomTime{0}; bool mARTStale{true}; bool mARTCapped{false}; + // variables to hold "slowness" status + bool mTooSlow{false}; + bool mTooSlowWithoutShadows{false}; + // private: LLViewerStats::PhaseMap mPhases; diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp index ee0ebf1d9b..6b12004a7c 100644 --- a/indra/newview/llvovolume.cpp +++ b/indra/newview/llvovolume.cpp @@ -5762,6 +5762,7 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group) LL_RECORD_BLOCK_TIME(FTM_REBUILD_VOLUME_FACE_LIST); //get all the faces into a list + std::unique_ptr ratPtr{}; // render time capture for (LLSpatialGroup::element_iter drawable_iter = group->getDataBegin(); drawable_iter != group->getDataEnd(); ++drawable_iter) { @@ -5784,13 +5785,6 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group) continue; } - std::unique_ptr T{}; - // Capture render times - if(vobj->isAttachment()) - { - T= trackMyAttachment(vobj); - } - // // Stop doing stupid stuff we don;t need to. // Moving this inside a debug enabled check @@ -5802,6 +5796,12 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group) { continue; } + // Capture render times + if(vobj->isAttachment()) + { + trackAttachments( vobj, drawablep->isState(LLDrawable::RIGGED),&ratPtr); + } + // LLVolume* volume = vobj->getVolume(); if (volume) @@ -6384,6 +6384,7 @@ void LLVolumeGeometryManager::rebuildMesh(LLSpatialGroup* group) U32 buffer_count = 0; + std::unique_ptr ratPtr{}; // capture render times for (LLSpatialGroup::element_iter drawable_iter = group->getDataBegin(); drawable_iter != group->getDataEnd(); ++drawable_iter) { LLDrawable* drawablep = (LLDrawable*)(*drawable_iter)->getDrawable(); @@ -6392,12 +6393,12 @@ void LLVolumeGeometryManager::rebuildMesh(LLSpatialGroup* group) { FSZoneN("Rebuild all non-Rigged") LLVOVolume* vobj = drawablep->getVOVolume(); - std::unique_ptr T{}; - - if(vobj->isAttachment()) + // capture render times + if( vobj && vobj->isAttachment() ) { - T = trackMyAttachment(vobj); + trackAttachments( vobj, drawablep->isState(LLDrawable::RIGGED), &ratPtr ); } + // // avoid unfortunate sleep during trylock by static check //if(debugLoggingEnabled("AnimatedObjectsLinkset")) static auto debug_logging_on = debugLoggingEnabled("AnimatedObjectsLinkset"); @@ -6810,18 +6811,18 @@ U32 LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, LLFace U32 indices_index = 0; U16 index_offset = 0; - std::unique_ptr T{}; - LLViewerObject * lastVObj{nullptr}; + std::unique_ptr ratPtr; // capture render times while (face_iter < i) { //update face indices for new buffer facep = *face_iter; LLViewerObject* vobj = facep->getViewerObject(); - if(vobj && vobj != lastVObj && vobj->isAttachment()) + // capture render times + if(vobj && vobj->isAttachment()) { - T = trackMyAttachment(vobj); - lastVObj = vobj; - } + trackAttachments(vobj, LLPipeline::sShadowRender, &ratPtr); + } + // if (buffer.isNull()) { // Bulk allocation failed diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp index 4946bfabd4..49be260468 100644 --- a/indra/newview/pipeline.cpp +++ b/indra/newview/pipeline.cpp @@ -11266,7 +11266,7 @@ void LLPipeline::generateImpostor(LLVOAvatar* avatar) << " is " << ( too_complex ? "" : "not ") << "too complex" << LL_ENDL; - bool too_slow = avatar->isTooSlow(); + bool too_slow = avatar->isTooSlowWithoutShadows(); // only if we really have to do we imposter. pushRenderTypeMask(); From feab5f9bf9a51ebe5aeeb28126299b4c782fe1b9 Mon Sep 17 00:00:00 2001 From: Beq Date: Wed, 3 Nov 2021 19:34:34 +0000 Subject: [PATCH 198/256] rename llfloaterperformance.cpp as it will not appear in current form Adds the various controls and other supporting settings. --- indra/newview/CMakeLists.txt | 6 +- indra/newview/app_settings/settings.xml | 36 +- ...rformance.cpp => fsfloaterperformance.cpp} | 486 +++++++++++++----- ...erperformance.h => fsfloaterperformance.h} | 5 + indra/newview/llfloaterpreference.cpp | 26 +- indra/newview/llfloaterpreference.h | 4 +- indra/newview/llviewercontrol.cpp | 45 +- .../default/xui/en/floater_performance.xml | 194 ++++--- .../menu_perf_avatar_rendering_settings.xml | 40 ++ .../xui/en/panel_performance_complexity.xml | 104 ++-- .../default/xui/en/panel_performance_huds.xml | 2 +- .../xui/en/panel_performance_nearby.xml | 51 +- .../xui/en/panel_performance_preferences.xml | 11 - 13 files changed, 700 insertions(+), 310 deletions(-) rename indra/newview/{llfloaterperformance.cpp => fsfloaterperformance.cpp} (56%) rename indra/newview/{llfloaterperformance.h => fsfloaterperformance.h} (93%) create mode 100644 indra/newview/skins/default/xui/en/menu_perf_avatar_rendering_settings.xml diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index 0bcdd48710..87b2a38b01 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -397,7 +397,8 @@ set(viewer_SOURCE_FILES llfloaterpathfindinglinksets.cpp llfloaterpathfindingobjects.cpp llfloaterpay.cpp - llfloaterperformance.cpp + # llfloaterperformance.cpp replaced with fs version due to large changes and likelihood that LL version will not release. + fsfloaterperformance.cpp llfloaterperms.cpp llfloaterpostprocess.cpp llfloaterpreference.cpp @@ -1178,7 +1179,8 @@ set(viewer_HEADER_FILES llfloaterpathfindinglinksets.h llfloaterpathfindingobjects.h llfloaterpay.h - llfloaterperformance.h + # llfloaterperformance.h replaced with fs version due to large changes and likelihood that LL version will not release. + fsfloaterperformance.h llfloaterperms.h llfloaterpostprocess.h llfloaterpreference.h diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index 87ad1598c3..d9330f424c 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -8171,7 +8171,7 @@ Comment Duration in seconds of the login SRV request timeout Persist - 0 + 1 Type F32 Value @@ -25717,12 +25717,23 @@ Change of this parameter will affect the layout of buttons in notification toast Comment Allow the viewer to adjust your settings to achieve target FPS Persist - 1 + 0 Type Boolean Value 0 + FSPerfFloaterSmoothingPeriods + + Comment + Number of periods to smooth the stats over + Persist + 1 + Type + U32 + Value + 50 + FSAutoUnmuteSounds Comment @@ -25756,10 +25767,10 @@ Change of this parameter will affect the layout of buttons in notification toast Value 1 - RenderAvatarUseART + FSPerfStatsCaptureEnabled Comment - Use Avatar Render Time (ART) instead of complexity (ARC) (true) + Enable/disable render time data to support autotune. Persist 1 Type @@ -25767,16 +25778,27 @@ Change of this parameter will affect the layout of buttons in notification toast Value 1 - RenderAvatarMaxART + FSRenderAvatarMaxART Comment Render Time Limit in microseconds (0.0 = no limit) Persist 1 Type - F32 + U32 Value - 0.0 + 50 + + FSTuningFPSStrategy + + Comment + Stategy to use when tuning FPS. 0=Tune avatar rendering only, 1=Tune both avatar and global scene settings. + Persist + 1 + Type + U32 + Value + 0 diff --git a/indra/newview/llfloaterperformance.cpp b/indra/newview/fsfloaterperformance.cpp similarity index 56% rename from indra/newview/llfloaterperformance.cpp rename to indra/newview/fsfloaterperformance.cpp index 4ab2d562b8..f21d9dfad1 100644 --- a/indra/newview/llfloaterperformance.cpp +++ b/indra/newview/fsfloaterperformance.cpp @@ -35,12 +35,17 @@ #include "llfeaturemanager.h" #include "llfloaterpreference.h" // LLAvatarComplexityControls #include "llfloaterreg.h" +#include "llmoveview.h" // for LLPanelStandStopFlying #include "llnamelistctrl.h" #include "llradiogroup.h" +#include "llselectmgr.h" #include "llsliderctrl.h" #include "lltextbox.h" +#include "llcombobox.h" #include "lltrans.h" #include "llviewerobjectlist.h" +#include "llviewerjoystick.h" +#include "llviewermediafocus.h" #include "llvoavatar.h" #include "llvoavatarself.h" #include "pipeline.h" @@ -70,7 +75,8 @@ protected: 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"); + registrar.add("Avatar.Extended", boost::bind(&LLFloaterPerformance::onExtendedAction, mFloaterPerformance, _2, mUUIDs.front())); + LLContextMenu* menu = createFromFile("menu_perf_avatar_rendering_settings.xml"); return menu; } @@ -78,6 +84,8 @@ protected: LLFloaterPerformance* mFloaterPerformance; }; + + LLFloaterPerformance::LLFloaterPerformance(const LLSD& key) : LLFloater(key), mUpdateTimer(new LLTimer()), @@ -100,16 +108,26 @@ BOOL LLFloaterPerformance::postBuild() mComplexityPanel = getChild("panel_performance_complexity"); mSettingsPanel = getChild("panel_performance_preferences"); mHUDsPanel = getChild("panel_performance_huds"); + mAutoTunePanel = getChild("panel_performance_autotune"); getChild("nearby_subpanel")->setMouseDownCallback(boost::bind(&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)); + auto tgt_panel = getChild("target_subpanel"); + if(tgt_panel) + { + tgt_panel->getChild("target_button")->setCommitCallback(boost::bind(&LLFloaterPerformance::showSelectedPanel, this, mAutoTunePanel)); + // tgt_panel->getChild("fwd_lbl")->setShowCursorHand(false); + // tgt_panel->getChild("fwd_lbl")->setSoundFlags(LLView::MOUSE_UP); + // tgt_panel->getChild("fwd_lbl")->setClickedCallback(boost::bind(&LLFloaterPerformance::showSelectedPanel, this, mAutoTunePanel)); + } initBackBtn(mNearbyPanel); initBackBtn(mComplexityPanel); initBackBtn(mSettingsPanel); initBackBtn(mHUDsPanel); + initBackBtn(mAutoTunePanel); mHUDList = mHUDsPanel->getChild("hud_list"); mHUDList->setNameListType(LLNameListCtrl::SPECIAL); @@ -129,15 +147,18 @@ BOOL LLFloaterPerformance::postBuild() 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)); + + mNearbyCombo = mComplexityPanel->getChild("avatar_name_combo"); + mNearbyCombo->setCommitCallback(boost::bind(&LLFloaterPerformance::onClickFocusAvatar, this)); updateComplexityText(); mComplexityChangedSignal = gSavedSettings.getControl("RenderAvatarMaxComplexity")->getCommitSignal()->connect(boost::bind(&LLFloaterPerformance::updateComplexityText, this)); mNearbyPanel->getChild("IndirectMaxComplexity")->setCommitCallback(boost::bind(&LLFloaterPerformance::updateMaxComplexity, this)); updateMaxRenderTime(); - updateMaxRenderTimeText(); - mMaxARTChangedSignal = gSavedSettings.getControl("RenderAvatarMaxART")->getCommitSignal()->connect(boost::bind(&LLFloaterPerformance::updateMaxRenderTimeText, this)); - mNearbyPanel->getChild("RenderAvatarMaxART")->setCommitCallback(boost::bind(&LLFloaterPerformance::updateMaxRenderTime, this)); + // updateMaxRenderTimeText(); + mMaxARTChangedSignal = gSavedSettings.getControl("FSRenderAvatarMaxART")->getCommitSignal()->connect(boost::bind(&LLFloaterPerformance::updateMaxRenderTime, this)); + mNearbyPanel->getChild("FSRenderAvatarMaxART")->setCommitCallback(boost::bind(&LLFloaterPerformance::updateMaxRenderTime, this)); LLAvatarComplexityControls::setIndirectMaxArc(); @@ -173,41 +194,67 @@ void LLFloaterPerformance::draw() constexpr auto MILLIS = 1000; - static LLCachedControl fps_cap(gSavedSettings, "FramePerSecondLimit"); // user limited FPS - static LLCachedControl target_fps(gSavedSettings, "FSTargetFPS"); // desired FPS - static LLCachedControl auto_tune(gSavedSettings, "FSAutoTuneFPS"); // auto tune enabled? - static LLCachedControl max_render_cost(gSavedSettings, "RenderAvatarMaxART", 0); + static LLCachedControl fpsCap(gSavedSettings, "FramePerSecondLimit"); // user limited FPS + static LLCachedControl targetFPS(gSavedSettings, "FSTargetFPS"); // desired FPS + // static LLCachedControl autoTune(gSavedSettings, "FSAutoTuneFPS"); // auto tune enabled? + static LLCachedControl maxRenderCost(gSavedSettings, "FSRenderAvatarMaxART"); + if(maxRenderCost != FSPerfStats::renderAvatarMaxART) + { + gSavedSettings.setU32("FSRenderAvatarMaxART", FSPerfStats::renderAvatarMaxART); + } static auto freq_divisor = get_timer_info().mClockFrequencyInv; if (mUpdateTimer->hasExpired()) { + + LLStringUtil::format_map_t args; auto fps = LLTrace::get_frame_recording().getPeriodMedianPerSec(LLStatViewer::FPS, NUM_PERIODS); getChild("fps_value")->setValue((S32)llround(fps)); auto tot_frame_time_ns = NANOS/fps; - auto target_frame_time_ns = NANOS/(target_fps==0?1:target_fps); + auto target_frame_time_ns = NANOS/(targetFPS==0?1:targetFPS); + + FSPerfStats::bufferToggleLock.lock(); // prevent toggle for a moment + + // cumulative avatar time (includes idle processing, attachments and base av) auto tot_avatar_time_raw = FSPerfStats::StatsRecorder::getSum(AvType, FSPerfStats::StatType_t::RENDER_COMBINED); - auto tot_huds_time_raw = FSPerfStats::StatsRecorder::getSceneStat(FSPerfStats::StatType_t::RENDER_HUDS); + // cumulative avatar render specific time (a bit arbitrary as the processing is too.) + auto tot_avatar_render_time_raw = tot_avatar_time_raw - FSPerfStats::StatsRecorder::getSum(AvType, FSPerfStats::StatType_t::RENDER_IDLE); + // the time spent this frame on the "display()" call. Treated as "tot time rendering" + auto tot_render_time_raw = FSPerfStats::StatsRecorder::getSceneStat(FSPerfStats::StatType_t::RENDER_DISPLAY); + // sleep time is basically forced sleep when window out of focus auto tot_sleep_time_raw = FSPerfStats::StatsRecorder::getSceneStat(FSPerfStats::StatType_t::RENDER_SLEEP); + // time spent on UI auto tot_ui_time_raw = FSPerfStats::StatsRecorder::getSceneStat(FSPerfStats::StatType_t::RENDER_UI); + // cumulative time spent rendering HUDS + auto tot_huds_time_raw = FSPerfStats::StatsRecorder::getSceneStat(FSPerfStats::StatType_t::RENDER_HUDS); + // "idle" time. This is the time spent in the idle poll section of the main loop, we DO 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); + // similar to sleep time, induced by FPS limit auto tot_limit_time_raw = FSPerfStats::StatsRecorder::getSceneStat(FSPerfStats::StatType_t::RENDER_FPSLIMIT); + // swap time is time spent in swap buffer auto tot_swap_time_raw = FSPerfStats::StatsRecorder::getSceneStat(FSPerfStats::StatType_t::RENDER_SWAP); - auto tot_avatar_time_ns = FSPerfStats::raw_to_ns( tot_avatar_time_raw ); - auto tot_huds_time_ns = FSPerfStats::raw_to_ns( tot_huds_time_raw ); - auto tot_sleep_time_ns = FSPerfStats::raw_to_ns( tot_sleep_time_raw ); - auto tot_ui_time_ns = FSPerfStats::raw_to_ns( tot_ui_time_raw ); - auto tot_idle_time_ns = FSPerfStats::raw_to_ns( tot_idle_time_raw ); - auto tot_limit_time_ns = FSPerfStats::raw_to_ns( tot_limit_time_raw ); - auto tot_swap_time_ns = FSPerfStats::raw_to_ns( tot_swap_time_raw ); + FSPerfStats::bufferToggleLock.unlock(); - // once the rest is extracted what is left is the scene cost - auto tot_scene_time_ns = tot_frame_time_ns - tot_avatar_time_ns - tot_huds_time_ns - tot_ui_time_ns - tot_sleep_time_ns - tot_limit_time_ns - tot_swap_time_ns - tot_idle_time_ns; - // remove time spent sleeping for fps limit or out of focus. - tot_frame_time_ns -= tot_limit_time_ns; - tot_frame_time_ns -= tot_sleep_time_ns; + + auto unreliable = false; // if there is something to skew the stats such as sleep of fps cap + auto tot_avatar_time_ns = FSPerfStats::raw_to_ns( tot_avatar_time_raw ); + auto tot_huds_time_ns = FSPerfStats::raw_to_ns( tot_huds_time_raw ); + auto tot_ui_time_ns = FSPerfStats::raw_to_ns( tot_ui_time_raw ); + + // auto tot_sleep_time_ns = FSPerfStats::raw_to_ns( tot_sleep_time_raw ); + // auto tot_limit_time_ns = FSPerfStats::raw_to_ns( tot_limit_time_raw ); + + // auto tot_render_time_ns = FSPerfStats::raw_to_ns( tot_render_time_raw ); + auto tot_idle_time_ns = FSPerfStats::raw_to_ns( tot_idle_time_raw ); + auto tot_swap_time_ns = FSPerfStats::raw_to_ns( tot_swap_time_raw ); + auto tot_non_av_render_time_ns = FSPerfStats::raw_to_ns( tot_render_time_raw - tot_avatar_render_time_raw); + + // // remove time spent sleeping for fps limit or out of focus. + // tot_frame_time_ns -= tot_limit_time_ns; + // tot_frame_time_ns -= tot_sleep_time_ns; if(tot_frame_time_ns == 0) { @@ -219,16 +266,23 @@ void LLFloaterPerformance::draw() auto pct_ui_time = (tot_ui_time_ns * 100)/tot_frame_time_ns; auto pct_idle_time = (tot_idle_time_ns * 100)/tot_frame_time_ns; auto pct_swap_time = (tot_swap_time_ns * 100)/tot_frame_time_ns; - auto pct_scene_time = (tot_scene_time_ns * 100)/tot_frame_time_ns; + auto pct_non_av_render_time = (tot_non_av_render_time_ns * 100)/tot_frame_time_ns; + pct_avatar_time = llclamp(pct_avatar_time,0.,100.); + pct_huds_time = llclamp(pct_huds_time,0.,100.); + pct_ui_time = llclamp(pct_ui_time,0.,100.); + pct_idle_time = llclamp(pct_idle_time,0.,100.); + pct_swap_time = llclamp(pct_swap_time,0.,100.); + pct_non_av_render_time = llclamp(pct_non_av_render_time,0.,100.); args["AV_FRAME_PCT"] = llformat("%02u", (U32)llround(pct_avatar_time)); args["HUDS_FRAME_PCT"] = llformat("%02u", (U32)llround(pct_huds_time)); args["UI_FRAME_PCT"] = llformat("%02u", (U32)llround(pct_ui_time)); args["IDLE_FRAME_PCT"] = llformat("%02u", (U32)llround(pct_idle_time)); args["SWAP_FRAME_PCT"] = llformat("%02u", (U32)llround(pct_swap_time)); - args["SCENE_FRAME_PCT"] = llformat("%02u", (U32)llround(pct_scene_time)); - args["FPSCAP"] = llformat("%02u", (U32)fps_cap); - args["FPSTARGET"] = llformat("%02u", (U32)target_fps); + args["SCENERY_FRAME_PCT"] = llformat("%02u", (U32)llround(pct_non_av_render_time)); + args["TOT_FRAME_TIME"] = llformat("%02u", (U32)llround(tot_frame_time_ns/1000000)); + args["FPSCAP"] = llformat("%02u", (U32)fpsCap); + args["FPSTARGET"] = llformat("%02u", (U32)targetFPS); getChild("av_frame_stats")->setText(getString("av_frame_pct", args)); getChild("huds_frame_stats")->setText(getString("huds_frame_pct", args)); @@ -240,14 +294,16 @@ void LLFloaterPerformance::draw() textbox->setVisible(true); textbox->setText(getString("focus_fps")); textbox->setColor(LLUIColorTable::instance().getColor("DrYellow")); + unreliable = true; } else if (tot_limit_time_raw > 0) { textbox->setVisible(true); textbox->setText(getString("limit_fps", args)); textbox->setColor(LLUIColorTable::instance().getColor("DrYellow")); + unreliable = true; } - else if(auto_tune) + else if(FSPerfStats::autoTune) { textbox->setVisible(true); textbox->setText(getString("tuning_fps", args)); @@ -258,59 +314,32 @@ void LLFloaterPerformance::draw() textbox->setVisible(false); } - if( auto_tune ) + if( FSPerfStats::autoTune && !unreliable ) { - auto av_render_max_raw = FSPerfStats::StatsRecorder::getMax(AvType, FSPerfStats::StatType_t::RENDER_COMBINED); - - // if( target_frame_time_ns <= tot_frame_time_ns ) - // { - // U32 non_avatar_time_ns = tot_frame_time_ns - tot_avatar_time_raw; - // if( non_avatar_time_ns < target_frame_time_ns ) - // { - // F32 target_avatar_time_ms {F32(target_frame_time_ns-non_avatar_time_ns)/1000000}; - // gSavedSettings.setF32( "RenderAvatarMaxART", target_avatar_time_ms / LLVOAvatar::sMaxNonImpostors ); - // LL_INFOS() << "AUTO_TUNE: Target frame time:"<= max_render_cost) - { - // we caught a bad frame possibly with a forced refresh render. - new_render_limit_ms = max_render_cost - 0.1; - } - gSavedSettings.setF32( "RenderAvatarMaxART", new_render_limit_ms); - LL_INFOS() << "AUTO_TUNE: avatar_budget adjusted to:" << new_render_limit_ms << LL_ENDL; - } - LL_INFOS() << "AUTO_TUNE: Target frame time:"<setColor(LLUIColorTable::instance().getColor("red")); } } - else - if( target_frame_time_ns > (tot_frame_time_ns + max_render_cost)) + else if( target_frame_time_ns > (tot_frame_time_ns + FSPerfStats::renderAvatarMaxART)) { // if we have more time to spare let's shift up little in the hope we'll restore an avatar. - gSavedSettings.setF32( "RenderAvatarMaxART", max_render_cost + 0.5 ); + textbox->setColor(LLUIColorTable::instance().getColor("green")); } } + if (mHUDsPanel->getVisible()) { populateHUDList(); @@ -342,6 +371,7 @@ void LLFloaterPerformance::hidePanels() mComplexityPanel->setVisible(FALSE); mHUDsPanel->setVisible(FALSE); mSettingsPanel->setVisible(FALSE); + mAutoTunePanel->setVisible(FALSE); } void LLFloaterPerformance::initBackBtn(LLPanel* panel) @@ -377,8 +407,7 @@ void LLFloaterPerformance::populateHUDList() for (iter = complexity_list.begin(); iter != end; ++iter) { LLHUDComplexity hud_object_complexity = *iter; - auto hud_ptr = hud_object_complexity.objectPtr; - auto hud_render_time_raw = FSPerfStats::StatsRecorder::get(HudType, hud_ptr->getID(), FSPerfStats::StatType_t::RENDER_GEOMETRY); + auto hud_render_time_raw = FSPerfStats::StatsRecorder::get(HudType, hud_object_complexity.objectId, FSPerfStats::StatType_t::RENDER_GEOMETRY); LLSD item; item["special_id"] = hud_object_complexity.objectId; item["target"] = LLNameListCtrl::SPECIAL; @@ -393,7 +422,7 @@ void LLFloaterPerformance::populateHUDList() row[1]["column"] = "complex_value"; row[1]["type"] = "text"; - LL_INFOS() << "HUD : hud[" << hud_ptr << " time:" << hud_render_time_raw <<" total_time:" << huds_max_render_time_raw << LL_ENDL; + // LL_INFOS() << "HUD : hud[" << hud_ptr << " time:" << hud_render_time_raw <<" total_time:" << huds_max_render_time_raw << LL_ENDL; row[1]["value"] = llformat( "%.3f",FSPerfStats::raw_to_us(hud_render_time_raw) ); row[1]["font"]["name"] = "SANSSERIF"; @@ -419,8 +448,14 @@ void LLFloaterPerformance::populateHUDList() void LLFloaterPerformance::populateObjectList() { + static auto freq_divisor = get_timer_info().mClockFrequencyInv; + S32 prev_pos = mObjectList->getScrollPos(); - LLUUID prev_selected_id = mObjectList->getSelectedSpecialId(); + auto prev_selected_id = mObjectList->getSelectedSpecialId(); + + std::string current_sort_col = mObjectList->getSortColumnName(); + BOOL current_sort_asc = mObjectList->getSortAscending(); + mObjectList->clearRows(); mObjectList->updateColumns(true); @@ -429,7 +464,6 @@ void LLFloaterPerformance::populateObjectList() object_complexity_list_t::iterator iter = complexity_list.begin(); object_complexity_list_t::iterator end = complexity_list.end(); - static auto freq_divisor = get_timer_info().mClockFrequencyInv; U32 max_complexity = 0; for (; iter != end; ++iter) @@ -437,52 +471,60 @@ void LLFloaterPerformance::populateObjectList() max_complexity = llmax(max_complexity, (*iter).objectCost); } - auto att_max_render_time_raw = FSPerfStats::StatsRecorder::getMax(AttType, FSPerfStats::StatType_t::RENDER_COMBINED); - - for (iter = complexity_list.begin(); iter != end; ++iter) { - LLObjectComplexity object_complexity = *iter; - S32 obj_cost_short = llmax((S32)object_complexity.objectCost / 1000, 1); - auto attach_render_time_raw = FSPerfStats::StatsRecorder::get(AttType, object_complexity.objectId, FSPerfStats::StatType_t::RENDER_COMBINED); - LLSD item; - item["special_id"] = object_complexity.objectId; - item["target"] = LLNameListCtrl::SPECIAL; - LLSD& row = item["columns"]; - row[0]["column"] = "art_visual"; - row[0]["type"] = "bar"; - LLSD& value = row[0]["value"]; - value["ratio"] = (F32)attach_render_time_raw / att_max_render_time_raw; - value["bottom"] = BAR_BOTTOM_PAD; - value["left_pad"] = BAR_LEFT_PAD; - value["right_pad"] = BAR_RIGHT_PAD; - - row[1]["column"] = "art_value"; - row[1]["type"] = "text"; - // row[1]["value"] = std::to_string(obj_cost_short); - row[1]["value"] = llformat( "%.4f", FSPerfStats::raw_to_us(attach_render_time_raw) ); - row[1]["font"]["name"] = "SANSSERIF"; - - row[2]["column"] = "complex_value"; - row[2]["type"] = "text"; - row[2]["value"] = std::to_string(obj_cost_short); - row[2]["font"]["name"] = "SANSSERIF"; - - row[3]["column"] = "name"; - row[3]["type"] = "text"; - row[3]["value"] = object_complexity.objectName; - row[3]["font"]["name"] = "SANSSERIF"; - - LLScrollListItem* obj = mObjectList->addElement(item); - if (obj) + std::lock_guard guard{FSPerfStats::bufferToggleLock}; + auto att_max_render_time_raw = FSPerfStats::StatsRecorder::getMax(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) { - LLScrollListText* value_text = dynamic_cast(obj->getColumn(1)); - if (value_text) + LLObjectComplexity object_complexity = *iter; + S32 obj_cost_short = llmax((S32)object_complexity.objectCost / 1000, 1); + + auto& attID{object_complexity.objectId}; + auto& attName{object_complexity.objectName}; + auto attach_render_time_raw = FSPerfStats::StatsRecorder::get(AttType, attID, FSPerfStats::StatType_t::RENDER_COMBINED); + LL_DEBUGS("PerfFloater") << "Att: " << attName << " (" << attID.asString() << ") Cost: " << FSPerfStats::raw_to_us(attach_render_time_raw) << LL_ENDL; + LLSD item; + item["special_id"] = attID; + item["target"] = LLNameListCtrl::SPECIAL; + LLSD& row = item["columns"]; + row[0]["column"] = "art_visual"; + row[0]["type"] = "bar"; + LLSD& value = row[0]["value"]; + value["ratio"] = ((F32)attach_render_time_raw) / att_max_render_time_raw; + value["bottom"] = BAR_BOTTOM_PAD; + value["left_pad"] = BAR_LEFT_PAD; + value["right_pad"] = BAR_RIGHT_PAD; + + row[1]["column"] = "art_value"; + row[1]["type"] = "text"; + // row[1]["value"] = std::to_string(obj_cost_short); + row[1]["value"] = llformat( "%.4f", FSPerfStats::raw_to_us(attach_render_time_raw) ); + row[1]["font"]["name"] = "SANSSERIF"; + + row[2]["column"] = "complex_value"; + row[2]["type"] = "text"; + row[2]["value"] = std::to_string(obj_cost_short); + row[2]["font"]["name"] = "SANSSERIF"; + + row[3]["column"] = "name"; + row[3]["type"] = "text"; + row[3]["value"] = attName; + row[3]["font"]["name"] = "SANSSERIF"; + + LLScrollListItem* obj = mObjectList->addElement(item); + if (obj) { - value_text->setAlignment(LLFontGL::HCENTER); + LLScrollListText* value_text = dynamic_cast(obj->getColumn(1)); + if (value_text) + { + value_text->setAlignment(LLFontGL::HCENTER); + } } } } - mObjectList->sortByColumnIndex(1, FALSE); + 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); } @@ -491,18 +533,33 @@ void LLFloaterPerformance::populateNearbyList() { S32 prev_pos = mNearbyList->getScrollPos(); LLUUID prev_selected_id = mNearbyList->getStringUUIDSelectedItem(); + std::string current_sort_col = mNearbyList->getSortColumnName(); + BOOL current_sort_asc = mNearbyList->getSortAscending(); + if(current_sort_col == "art_visual") + { + current_sort_col = "art_value"; + current_sort_asc = false; + } + mNearbyList->clearRows(); mNearbyList->updateColumns(true); - static LLCachedControl max_render_cost(gSavedSettings, "RenderAvatarMaxART", 0); + static LLCachedControl maxRenderCost(gSavedSettings, "FSRenderAvatarMaxART", 0); updateMaxRenderTime(); - updateMaxRenderTimeText(); + // updateMaxRenderTimeText(); std::vector valid_nearby_avs; getNearbyAvatars(valid_nearby_avs); std::vector::iterator char_iter = valid_nearby_avs.begin(); + + FSPerfStats::bufferToggleLock.lock(); auto av_render_max_raw = FSPerfStats::StatsRecorder::getMax(AvType, FSPerfStats::StatType_t::RENDER_COMBINED); + FSPerfStats::bufferToggleLock.unlock(); + + FSPlot("max ART", (int64_t)av_render_max_raw); + FSPlot("Num av", (int64_t)valid_nearby_avs.size()); + while (char_iter != valid_nearby_avs.end()) { LLVOAvatar* avatar = dynamic_cast(*char_iter); @@ -513,9 +570,12 @@ void LLFloaterPerformance::populateNearbyList() continue; S32 complexity_short = llmax((S32)avatar->getVisualComplexity() / 1000, 1); + + FSPerfStats::bufferToggleLock.lock(); auto render_av_raw = FSPerfStats::StatsRecorder::get(AvType, avatar->getID(),FSPerfStats::StatType_t::RENDER_COMBINED); - auto is_slow = avatar->isTooSlow(true); - // auto is_slow_without_shadows = avatar->isTooSlow(); + FSPerfStats::bufferToggleLock.unlock(); + + auto is_slow = avatar->isTooSlowWithShadows(); LLSD item; item["id"] = avatar->getID(); @@ -523,6 +583,8 @@ void LLFloaterPerformance::populateNearbyList() row[0]["column"] = "art_visual"; row[0]["type"] = "bar"; LLSD& value = row[0]["value"]; + // The ratio used in the bar is the current cost, as soon as we take action this changes so we keep the + // pre-tune value for the numerical column and sorting. value["ratio"] = (double)render_av_raw / av_render_max_raw; value["bottom"] = BAR_BOTTOM_PAD; value["left_pad"] = BAR_LEFT_PAD; @@ -532,11 +594,11 @@ void LLFloaterPerformance::populateNearbyList() row[1]["type"] = "text"; if(is_slow) { - row[1]["value"] = llformat( "%.2f", FSPerfStats::raw_to_ms( avatar->getLastART() ) ); + row[1]["value"] = llformat( "%.2f", FSPerfStats::raw_to_us( avatar->getLastART() ) ); } else { - row[1]["value"] = llformat( "%.2f", FSPerfStats::raw_to_ms( render_av_raw ) ); + row[1]["value"] = llformat( "%.2f", FSPerfStats::raw_to_us( render_av_raw ) ); } row[1]["font"]["name"] = "SANSSERIF"; row[1]["width"] = "50"; @@ -547,21 +609,47 @@ void LLFloaterPerformance::populateNearbyList() row[2]["font"]["name"] = "SANSSERIF"; row[2]["width"] = "50"; - - row[3]["column"] = "name"; + row[3]["column"] = "state"; row[3]["type"] = "text"; - row[3]["value"] = avatar->getFullname(); + if(is_slow) + { + if( avatar->isTooSlowWithoutShadows() ) + { + row[3]["value"] = std::string{"I"}; + } + else + { + row[3]["value"] = std::string{"S"}; + } + } + else + { + row[3]["value"] = std::string{" "}; + } + row[3]["font"]["name"] = "SANSSERIF"; + row[4]["column"] = "name"; + LLScrollListItem* av_item = mNearbyList->addElement(item); if(av_item) { - LLScrollListText* value_text = dynamic_cast(av_item->getColumn(1)); + LLScrollListText* art_text = dynamic_cast(av_item->getColumn(1)); + if (art_text) + { + art_text->setAlignment(LLFontGL::RIGHT); + } + LLScrollListText* value_text = dynamic_cast(av_item->getColumn(2)); if (value_text) { - value_text->setAlignment(LLFontGL::HCENTER); + value_text->setAlignment(LLFontGL::RIGHT); } - LLScrollListText* name_text = dynamic_cast(av_item->getColumn(2)); + LLScrollListText* state_text = dynamic_cast(av_item->getColumn(3)); + if (state_text) + { + state_text->setAlignment(LLFontGL::HCENTER); + } + LLScrollListText* name_text = dynamic_cast(av_item->getColumn(4)); if (name_text) { if (avatar->isSelf()) @@ -591,7 +679,7 @@ void LLFloaterPerformance::populateNearbyList() } char_iter++; } - mNearbyList->sortByColumnIndex(1, FALSE); + mNearbyList->sortByColumn(current_sort_col, current_sort_asc); mNearbyList->setScrollPos(prev_pos); mNearbyList->selectByID(prev_selected_id); } @@ -650,6 +738,11 @@ void LLFloaterPerformance::onClickHideAvatars() LLPipeline::toggleRenderTypeControl(LLPipeline::RENDER_TYPE_AVATAR); } +void LLFloaterPerformance::onClickFocusAvatar() +{ + FSPerfStats::StatsRecorder::setFocusAv(mNearbyCombo->getSelectedValue().asUUID()); +} + void LLFloaterPerformance::onClickExceptions() { // [FS Persisted Avatar Render Settings] @@ -669,16 +762,16 @@ void LLFloaterPerformance::updateMaxComplexity() void LLFloaterPerformance::updateMaxRenderTime() { LLAvatarComplexityControls::updateMaxRenderTime( - mNearbyPanel->getChild("RenderAvatarMaxART"), - mNearbyPanel->getChild("RenderAvatarMaxARTText"), + mNearbyPanel->getChild("FSRenderAvatarMaxART"), + mNearbyPanel->getChild("FSRenderAvatarMaxARTText"), true); } void LLFloaterPerformance::updateMaxRenderTimeText() { LLAvatarComplexityControls::setRenderTimeText( - gSavedSettings.getF32("RenderAvatarMaxART"), - mNearbyPanel->getChild("RenderAvatarMaxARTText", true), + gSavedSettings.getU32("FSRenderAvatarMaxART"), + mNearbyPanel->getChild("FSRenderAvatarMaxARTText", true), true); } @@ -781,4 +874,153 @@ void LLFloaterPerformance::onAvatarListRightClick(LLUICtrl* ctrl, S32 x, S32 y) } } + +void LLFloaterPerformance::onExtendedAction(const LLSD& userdata, const LLUUID& av_id) +{ + const std::string command_name = userdata.asString(); + + LLViewerObject* objectp = gObjectList.findObject(av_id); + if (!objectp) + { + return; + } + auto avp = objectp->asAvatar(); + if ("inspect" == command_name) + { + for (LLVOAvatar::attachment_map_t::iterator iter = avp->mAttachmentPoints.begin(); + iter != avp->mAttachmentPoints.end(); + ++iter) + { + LLViewerJointAttachment* attachment = iter->second; + + if (!attachment) + { + continue; + } + + for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin(); + attachment_iter != attachment->mAttachedObjects.end(); + ++attachment_iter) + { + LLViewerObject* attached_object = attachment_iter->get(); + + if ( attached_object && !attached_object->isDead() ) + { + LLSelectMgr::getInstance()->selectObjectAndFamily(attached_object); + } + } + } + LLFloaterReg::showInstance("inspect"); + } + else if ("zoom" == command_name) + { + // Disable flycam if active. Without this, the requested look-at doesn't happen because the flycam code overrides all other camera motion. + bool fly_cam_status(LLViewerJoystick::getInstance()->getOverrideCamera()); + if (fly_cam_status) + { + LLViewerJoystick::getInstance()->setOverrideCamera(false); + LLPanelStandStopFlying::clearStandStopFlyingMode(LLPanelStandStopFlying::SSFM_FLYCAM); + // *NOTE: Above may not be the proper way to disable flycam. What I really want to do is just be able to move the camera and then leave the flycam in the the same state it was in, just moved to the new location. ~Cron + } + + LLViewerJoystick::getInstance()->setCameraNeedsUpdate(true); // Fixes an edge case where if the user has JUST disabled flycam themselves, the camera gets stuck waiting for input. + + gAgentCamera.setFocusOnAvatar(FALSE, ANIMATE); + + gAgentCamera.setLookAt(LOOKAT_TARGET_SELECT, objectp); + + // Place the camera looking at the object, along the line from the camera to the object, + // and sufficiently far enough away for the object to fill 3/4 of the screen, + // but not so close that the bbox's nearest possible vertex goes inside the near clip. + // Logic C&P'd from LLViewerMediaFocus::setCameraZoom() and then edited as needed + + LLBBox bbox = objectp->getBoundingBoxAgent(); + LLVector3d center(gAgent.getPosGlobalFromAgent(bbox.getCenterAgent())); + F32 height; + F32 width; + F32 depth; + F32 angle_of_view; + F32 distance; + + LLVector3d target_pos(center); + LLVector3d camera_dir(gAgentCamera.getCameraPositionGlobal() - target_pos); + camera_dir.normalize(); + + // We need the aspect ratio, and the 3 components of the bbox as height, width, and depth. + F32 aspect_ratio(LLViewerMediaFocus::getBBoxAspectRatio(bbox, LLVector3(camera_dir), &height, &width, &depth)); + F32 camera_aspect(LLViewerCamera::getInstance()->getAspect()); + + // We will normally use the side of the volume aligned with the short side of the screen (i.e. the height for + // a screen in a landscape aspect ratio), however there is an edge case where the aspect ratio of the object is + // more extreme than the screen. In this case we invert the logic, using the longer component of both the object + // and the screen. + bool invert((camera_aspect > 1.0f && aspect_ratio > camera_aspect) || (camera_aspect < 1.0f && aspect_ratio < camera_aspect)); + + // To calculate the optimum viewing distance we will need the angle of the shorter side of the view rectangle. + // In portrait mode this is the width, and in landscape it is the height. + // We then calculate the distance based on the corresponding side of the object bbox (width for portrait, height for landscape) + // We will add half the depth of the bounding box, as the distance projection uses the center point of the bbox. + if (camera_aspect < 1.0f || invert) + { + angle_of_view = llmax(0.1f, LLViewerCamera::getInstance()->getView() * LLViewerCamera::getInstance()->getAspect()); + distance = width * 0.5 * 1.1 / tanf(angle_of_view * 0.5f); + } + else + { + angle_of_view = llmax(0.1f, LLViewerCamera::getInstance()->getView()); + distance = height * 0.5 * 1.1 / tanf(angle_of_view * 0.5f); + } + + distance += depth * 0.5; + + // Verify that the bounding box isn't inside the near clip. Using OBB-plane intersection to check if the + // near-clip plane intersects with the bounding box, and if it does, adjust the distance such that the + // object doesn't clip. + LLVector3d bbox_extents(bbox.getExtentLocal()); + LLVector3d axis_x = LLVector3d(1, 0, 0) * bbox.getRotation(); + LLVector3d axis_y = LLVector3d(0, 1, 0) * bbox.getRotation(); + LLVector3d axis_z = LLVector3d(0, 0, 1) * bbox.getRotation(); + //Normal of nearclip plane is camera_dir. + F32 min_near_clip_dist = bbox_extents.mdV[0] * (camera_dir * axis_x) + bbox_extents.mdV[1] * (camera_dir * axis_y) + bbox_extents.mdV[2] * (camera_dir * axis_z); // http://www.gamasutra.com/view/feature/131790/simple_intersection_tests_for_games.php?page=7 + F32 camera_to_near_clip_dist(LLViewerCamera::getInstance()->getNear()); + F32 min_camera_dist(min_near_clip_dist + camera_to_near_clip_dist); + if (distance < min_camera_dist) + { + // Camera is too close to object, some parts MIGHT clip. Move camera away to the position where clipping barely doesn't happen. + distance = min_camera_dist; + } + + LLVector3d camera_pos(target_pos + camera_dir * distance); + + if (camera_dir == LLVector3d::z_axis || camera_dir == LLVector3d::z_axis_neg) + { + // If the direction points directly up, the camera will "flip" around. + // We try to avoid this by adjusting the target camera position a + // smidge towards current camera position + // *NOTE: this solution is not perfect. All it attempts to solve is the + // "looking down" problem where the camera flips around when it animates + // to that position. You still are not guaranteed to be looking at the + // object in the correct orientation. What this solution does is it will + // put the camera into position keeping as best it can the current + // orientation with respect to the direction wanted. In other words, if + // before zoom the object appears "upside down" from the camera, after + /// zooming it will still be upside down, but at least it will not flip. + LLVector3d cur_camera_pos = LLVector3d(gAgentCamera.getCameraPositionGlobal()); + LLVector3d delta = (cur_camera_pos - camera_pos); + F64 len = delta.length(); + delta.normalize(); + // Move 1% of the distance towards original camera location + camera_pos += 0.01 * len * delta; + } + + gAgentCamera.setCameraPosAndFocusGlobal(camera_pos, target_pos, objectp->getID()); + + // *TODO: Re-enable joystick flycam if we disabled it earlier... Have to find some form of callback as re-enabling at this point causes the camera motion to not happen. ~Cron + //if (fly_cam_status) + //{ + // LLViewerJoystick::getInstance()->toggleFlycam(); + //} + } +} + // EOF diff --git a/indra/newview/llfloaterperformance.h b/indra/newview/fsfloaterperformance.h similarity index 93% rename from indra/newview/llfloaterperformance.h rename to indra/newview/fsfloaterperformance.h index 0e1289df23..1fdbe4686f 100644 --- a/indra/newview/llfloaterperformance.h +++ b/indra/newview/fsfloaterperformance.h @@ -31,6 +31,7 @@ class LLCharacter; class LLNameListCtrl; +class LLComboBox; class LLFloaterPerformance : public LLFloater { @@ -51,6 +52,7 @@ public: void onCustomAction (const LLSD& userdata, const LLUUID& av_id); bool isActionChecked(const LLSD& userdata, const LLUUID& av_id); + void onExtendedAction(const LLSD& userdata, const LLUUID& av_id); private: void initBackBtn(LLPanel* panel); @@ -62,6 +64,7 @@ private: void onChangeQuality(const LLSD& data); void onClickHideAvatars(); void onClickExceptions(); + void onClickFocusAvatar(); void updateMaxComplexity(); void updateComplexityText(); @@ -75,9 +78,11 @@ private: LLPanel* mComplexityPanel; LLPanel* mHUDsPanel; LLPanel* mSettingsPanel; + LLPanel* mAutoTunePanel; LLNameListCtrl* mHUDList; LLNameListCtrl* mObjectList; LLNameListCtrl* mNearbyList; + LLComboBox* mNearbyCombo; LLListContextMenu* mContextMenu; diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp index 2cc8d63343..b631cf74bc 100644 --- a/indra/newview/llfloaterpreference.cpp +++ b/indra/newview/llfloaterpreference.cpp @@ -2874,36 +2874,30 @@ void LLAvatarComplexityControls::setText(U32 value, LLTextBox* text_box, bool sh } } +// redner time controls void LLAvatarComplexityControls::updateMaxRenderTime(LLSliderCtrl* slider, LLTextBox* value_label, bool short_val) { // Called when the IndirectMaxComplexity control changes // Responsible for fixing the slider label (IndirectMaxComplexityText) and setting RenderAvatarMaxComplexity - auto indirect_value = slider->getValue().asReal(); - gSavedSettings.setF32("RenderAvatarMaxART", indirect_value); - if(indirect_value == slider->getMaxValue()) - { - LLVOAvatar::sRenderTimeCap_ns = 0; - setRenderTimeText(0.0, value_label, short_val); - } - else - { - LLVOAvatar::sRenderTimeCap_ns = llround(indirect_value * 1000000); - setRenderTimeText(indirect_value, value_label, short_val); - } + auto indirect_value = slider->getValue().asInteger(); + gSavedSettings.setU32("FSRenderAvatarMaxART", indirect_value); + + LLVOAvatar::sRenderTimeLimit_ns = indirect_value * 1000; + setRenderTimeText(indirect_value, value_label, short_val); } -void LLAvatarComplexityControls::setRenderTimeText(F32 value, LLTextBox* text_box, bool short_val) +void LLAvatarComplexityControls::setRenderTimeText(U32 value, LLTextBox* text_box, bool short_val) { - if (0.0 == value) + if (0 == value) { text_box->setText(LLTrans::getString("no_limit")); } else { - text_box->setText(llformat("%.2f", value)); + text_box->setText(llformat("%u", value)); } } - +// void LLFloaterPreference::updateMaxComplexity() { // Called when the IndirectMaxComplexity control changes diff --git a/indra/newview/llfloaterpreference.h b/indra/newview/llfloaterpreference.h index 008551f356..e8cc8c3a59 100644 --- a/indra/newview/llfloaterpreference.h +++ b/indra/newview/llfloaterpreference.h @@ -479,8 +479,10 @@ class LLAvatarComplexityControls public: static void updateMax(LLSliderCtrl* slider, LLTextBox* value_label, bool short_val = false); static void setText(U32 value, LLTextBox* text_box, bool short_val = false); + // for render time support static void updateMaxRenderTime(LLSliderCtrl* slider, LLTextBox* value_label, bool short_val = false); - static void setRenderTimeText(F32 value, LLTextBox* text_box, bool short_val = false); + static void setRenderTimeText(U32 value, LLTextBox* text_box, bool short_val = false); + // static void setIndirectControls(); static void setIndirectMaxNonImpostors(); static void setIndirectMaxArc(); diff --git a/indra/newview/llviewercontrol.cpp b/indra/newview/llviewercontrol.cpp index fe175bcaf2..7893b557f6 100644 --- a/indra/newview/llviewercontrol.cpp +++ b/indra/newview/llviewercontrol.cpp @@ -107,7 +107,7 @@ #include "llviewerregion.h" #include "NACLantispam.h" #include "nd/ndlogthrottle.h" - +#include "fsperfstats.h" // Run Prio 0 default bento pose in the background to fix splayed hands, open mouths, etc. #include "llanimationstates.h" @@ -1059,6 +1059,41 @@ void handleDiskCacheSizeChanged(const LLSD& newValue) } // +// perrf floater stuffs +void handleTargetFPSChanged(const LLSD& newValue) +{ + const auto targetFPS = gSavedSettings.getU32("FSTargetFPS"); + FSPerfStats::targetFPS = targetFPS; +} + +// perrf floater stuffs +void handleAutoTuneFPSChanged(const LLSD& newValue) +{ + const auto newval = gSavedSettings.getBOOL("FSAutoTuneFPS"); + FSPerfStats::autoTune = newval; + if(gSavedSettings.getU32("FSRenderAvatarMaxART") == 0) + { + gSavedSettings.setU32("FSRenderAvatarMaxART",50000); + } +} + +void handleRenderAvatarMaxARTChanged(const LLSD& newValue) +{ + const auto newval = gSavedSettings.getU32("FSRenderAvatarMaxART"); + FSPerfStats::renderAvatarMaxART = newval; +} +void handlePerfSmoothingPeriodsChanged(const LLSD& newValue) +{ + const auto newval = gSavedSettings.getU32("FSPerfFloaterSmoothingPeriods"); + FSPerfStats::smoothingPeriods = newval; +} +void handleFPSTuningStrategyChanged(const LLSD& newValue) +{ + const auto newval = gSavedSettings.getU32("FSTuningFPSStrategy"); + FSPerfStats::fpsTuningStrategy = newval; +} +// + //////////////////////////////////////////////////////////////////////////// void settings_setup_listeners() @@ -1313,6 +1348,14 @@ void settings_setup_listeners() // Better asset cache size control gSavedSettings.getControl("FSDiskCacheSize")->getSignal()->connect(boost::bind(&handleDiskCacheSizeChanged, _2)); + + // perf floater controls + gSavedSettings.getControl("FSTargetFPS")->getSignal()->connect(boost::bind(&handleTargetFPSChanged, _2)); + gSavedSettings.getControl("FSAutoTuneFPS")->getSignal()->connect(boost::bind(&handleAutoTuneFPSChanged, _2)); + gSavedSettings.getControl("FSRenderAvatarMaxART")->getSignal()->connect(boost::bind(&handleRenderAvatarMaxARTChanged, _2)); + gSavedSettings.getControl("FSRenderAvatarMaxART")->getSignal()->connect(boost::bind(&handlePerfSmoothingPeriodsChanged, _2)); + gSavedSettings.getControl("FSTuningFPSStrategy")->getSignal()->connect(boost::bind(&handleFPSTuningStrategyChanged, _2)); + // } #if TEST_CACHED_CONTROL diff --git a/indra/newview/skins/default/xui/en/floater_performance.xml b/indra/newview/skins/default/xui/en/floater_performance.xml index 30be14a0ab..5ca24181e3 100644 --- a/indra/newview/skins/default/xui/en/floater_performance.xml +++ b/indra/newview/skins/default/xui/en/floater_performance.xml @@ -1,13 +1,13 @@ - Scenery:[SCENE_FRAME_PCT]% Avatars:[AV_FRAME_PCT]% UI:[UI_FRAME_PCT]% HUDS:[HUDS_FRAME_PCT]% SWAP:[SWAP_FRAME_PCT]% TASKS:[IDLE_FRAME_PCT]% + 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]% FPS capped at [FPSCAP] fps @@ -27,14 +27,14 @@ - Frame breakdown will appear here. - + + + + Auto-Tune Frame Rate + + + + + Automatically adjust settings to maintain FPS + + + + + + + + - - - 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 199/256] 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 200/256] 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 201/256] 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 202/256] 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 203/256] 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 204/256] 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 205/256] 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 211/256] 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 212/256] 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 213/256] 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 214/256] 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 215/256] 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 216/256] 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 217/256] 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 223/256] 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 224/256] 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 235/256] 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 240/256] 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 241/256] 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 242/256] 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 243/256] 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 244/256] 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 245/256] 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 @@