Ansariel 2021-11-16 13:54:22 +01:00
commit be25e64888
320 changed files with 14831 additions and 2821 deletions

View File

@ -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 ####

View File

@ -656,9 +656,9 @@
<key>archive</key>
<map>
<key>hash</key>
<string>51d9ce98279709854b0be5d0f450ba63</string>
<string>96dd770f246917589b776300a2d07f9e</string>
<key>url</key>
<string>http://3p.firestormviewer.org/curl-7.54.1.180841943-linux64-180841943.tar.bz2</string>
<string>http://3p.firestormviewer.org/curl-7.54.1.212891029-linux64-212891029.tar.bz2</string>
</map>
<key>name</key>
<string>linux64</string>
@ -814,9 +814,9 @@
<key>archive</key>
<map>
<key>hash</key>
<string>45dedb5b09995cd794304150e94fcf21</string>
<string>2653c3627fd8687ff9e003425fd14834</string>
<key>url</key>
<string>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</string>
<string>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</string>
</map>
<key>name</key>
<string>darwin64</string>
@ -826,9 +826,9 @@
<key>archive</key>
<map>
<key>hash</key>
<string>d0fd9d7086699da4bb5ccc935622a717</string>
<string>b4003772562a5dd40bc112eec7cba5f5</string>
<key>url</key>
<string>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</string>
<string>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</string>
</map>
<key>name</key>
<string>windows</string>
@ -838,9 +838,9 @@
<key>archive</key>
<map>
<key>hash</key>
<string>7e8c3ccd420ff5aef24ff72d609ba394</string>
<string>d9030d7a7390b3bda7de2adcc27e535a</string>
<key>url</key>
<string>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</string>
<string>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</string>
</map>
<key>name</key>
<string>windows64</string>
@ -859,7 +859,7 @@
</map>
</map>
<key>version</key>
<string>1.12.2.202109230751_91.1.21_g9dd45fe_chromium-91.0.4472.114</string>
<string>1.12.3.202111032221_91.1.21_g9dd45fe_chromium-91.0.4472.114</string>
</map>
<key>elfio</key>
<map>
@ -2315,18 +2315,18 @@
<key>archive</key>
<map>
<key>hash</key>
<string>0a6349b11c8e9d34f0c80b8081736e75</string>
<string>35f42f538f4dc3abdfc2b2c4a915d004</string>
<key>hash_algorithm</key>
<string>md5</string>
<key>url</key>
<string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/79438/751815/llca-202104010215.557744-common-557744.tar.bz2</string>
<string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/87228/802959/llca-202109010216.563493-common-563493.tar.bz2</string>
</map>
<key>name</key>
<string>common</string>
</map>
</map>
<key>version</key>
<string>202104010215.557744</string>
<string>202109010216.563493</string>
</map>
<key>llphysicsextensions_source</key>
<map>
@ -2968,9 +2968,9 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
<key>archive</key>
<map>
<key>hash</key>
<string>7920fce93d9addf63a420d86f91c5749</string>
<string>ea82e634334bccf088daf3d15eab07b7</string>
<key>url</key>
<string>http://3p.firestormviewer.org/openssl-1.0.2l.180841936-linux64-180841936.tar.bz2</string>
<string>http://3p.firestormviewer.org/openssl-1.1.1l.212872015-linux64-212872015.tar.bz2</string>
</map>
<key>name</key>
<string>linux64</string>
@ -3310,9 +3310,9 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
<key>archive</key>
<map>
<key>hash</key>
<string>6989053898b8e81e904e75553e378820</string>
<string>97fac6d88480445c856083ed20d78093</string>
<key>url</key>
<string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/77523/735051/viewer_manager-2.0.556340-darwin64-556340.tar.bz2</string>
<string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/85206/790666/viewer_manager-2.0.562101-darwin64-562101.tar.bz2</string>
</map>
<key>name</key>
<string>darwin64</string>
@ -3346,9 +3346,9 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
<key>archive</key>
<map>
<key>hash</key>
<string>3446c1e54bb32542677caad0ec0d42ac</string>
<string>3f6271ec0e2e2f0cc1067d4c4102bb4c</string>
<key>url</key>
<string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/77525/735058/viewer_manager-2.0.556340-windows-556340.tar.bz2</string>
<string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/85208/790681/viewer_manager-2.0.562101-windows-562101.tar.bz2</string>
</map>
<key>name</key>
<string>windows</string>
@ -3359,7 +3359,7 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
<key>source_type</key>
<string>hg</string>
<key>version</key>
<string>2.0.556340</string>
<string>2.0.562101</string>
</map>
<key>vlc-bin</key>
<map>
@ -3378,9 +3378,9 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
<key>archive</key>
<map>
<key>hash</key>
<string>b639d0035f4a8c9b4973be428a1b7e61</string>
<string>738688816ebd76958e49772712a6b972</string>
<key>url</key>
<string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/69569/671323/vlc_bin-3.0.9.549888-darwin64-549888.tar.bz2</string>
<string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/90004/820701/vlc_bin-3.0.16.565299-darwin64-565299.tar.bz2</string>
</map>
<key>name</key>
<string>darwin64</string>
@ -3414,9 +3414,9 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
<key>archive</key>
<map>
<key>hash</key>
<string>4f50b0c47daa081dd4fcb83763d5b0b2</string>
<string>6801f91f3f27e626898bab90d40fc1c3</string>
<key>url</key>
<string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/69567/671314/vlc_bin-3.0.9.549888-windows-549888.tar.bz2</string>
<string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/90005/820712/vlc_bin-3.0.16.565299-windows-565299.tar.bz2</string>
</map>
<key>name</key>
<string>windows</string>
@ -3426,16 +3426,16 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
<key>archive</key>
<map>
<key>hash</key>
<string>c2f8c01fb6c261b72beb07f0c4cd423f</string>
<string>7f66982d6edf3c38f3493e28826d58e8</string>
<key>url</key>
<string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/69568/671315/vlc_bin-3.0.9.549888-windows64-549888.tar.bz2</string>
<string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/90006/820713/vlc_bin-3.0.16.565299-windows64-565299.tar.bz2</string>
</map>
<key>name</key>
<string>windows64</string>
</map>
</map>
<key>version</key>
<string>3.0.9.549888</string>
<string>2.2.8.538966</string>
</map>
<key>xmlrpc-epi</key>
<map>

View File

@ -298,6 +298,22 @@ python_cmd "$helpers/codeticket.py" addinput "Viewer Channel" "${viewer_channel}
initialize_version # provided by buildscripts build.sh; sets version id
begin_section "coding policy check"
# On our TC Windows build hosts, the GitPython library underlying our
# coding_policy_git.py script fails to run git for reasons we have not tried
# to diagnose. Clearly git works fine on those hosts, or we would never get
# this far. Running coding policy checks on one platform *should* suffice...
if [[ "$arch" == "Darwin" ]]
then
# install the git-hooks dependencies
pip install -r "$(native_path "$git_hooks_checkout/requirements.txt")" || \
fatal "pip install git-hooks failed"
# validate the branch we're about to build
python_cmd "$git_hooks_checkout/coding_policy_git.py" --all_files || \
fatal "coding policy check failed"
fi
end_section "coding policy check"
# Now run the build
succeeded=true
last_built_variant=

18
debian/changelog vendored
View File

@ -1,18 +0,0 @@
secondlife-viewer (0.3) unstable; urgency=low
* Initial debian configuration
-- Don Kjer <don@lindenlab.com> Wed, 04 Jul 2012 00:43:03 +0000
secondlife-viewer (0.2) unstable; urgency=low
* Adding default LSB headers for squeeze
-- Tyler Kohler <tyler@lindenlab.com> Thu, 24 Mar 2011 09:43:36 -0700
secondlife-viewer (0.1) unstable; urgency=low
* Cloned from debian package skeleton.
-- Lex Linden <lex@lindenlab.com> Mon, 20 Sep 2010 08:01:59 -0700

1
debian/compat vendored
View File

@ -1 +0,0 @@
5

16
debian/control vendored
View File

@ -1,16 +0,0 @@
Source: secondlife-viewer
Section: unknown
Priority: extra
Maintainer: Don Linden <don@lindenlab.com>
Build-Depends: debhelper (>= 5)
Homepage: http://secondlife.com
Standards-Version: 3.7.2
Package: secondlife-viewer
Architecture: any
Depends: ${shlibs:Depends}, ${misc:Depends},
ia32-libs,
ia32-libs-gtk
Description: Second Life Viewer
Second Life is an online virtual world developed by Linden Lab.

32
debian/copyright vendored
View File

@ -1,32 +0,0 @@
Second Life Viewer Copyright: 2000-2012 Linden Research, Inc.
License:
3Dconnexion SDK Copyright (C) 1992-2009 3Dconnexion
APR Copyright (C) 2011 The Apache Software Foundation
Collada DOM Copyright 2006 Sony Computer Entertainment Inc.
cURL Copyright (C) 1996-2010, Daniel Stenberg, (daniel@haxx.se)
DBus/dbus-glib Copyright (C) 2002, 2003 CodeFactory AB / Copyright (C) 2003, 2004 Red Hat, Inc.
expat Copyright (C) 1998, 1999, 2000 Thai Open Source Software Center Ltd.
FreeType Copyright (C) 1996-2002, 2006 David Turner, Robert Wilhelm, and Werner Lemberg.
GL Copyright (C) 1999-2004 Brian Paul.
GLOD Copyright (C) 2003-04 Jonathan Cohen, Nat Duca, Chris Niski, Johns Hopkins University and David Luebke, Brenden Schubert, University of Virginia.
google-perftools Copyright (c) 2005, Google Inc.
Havok.com(TM) Copyright (C) 1999-2001, Telekinesys Research Limited.
jpeg2000 Copyright (C) 2001, David Taubman, The University of New South Wales (UNSW)
jpeglib Copyright (C) 1991-1998, Thomas G. Lane.
ogg/vorbis Copyright (C) 2002, Xiphophorus
OpenSSL Copyright (C) 1998-2008 The OpenSSL Project.
PCRE Copyright (c) 1997-2012 University of Cambridge
SDL Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002 Sam Lantinga
SSLeay Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
xmlrpc-epi Copyright (C) 2000 Epinions, Inc.
zlib Copyright (C) 1995-2012 Jean-loup Gailly and Mark Adler.
Second Life Viewer uses Havok (TM) Physics. (c)Copyright 1999-2010 Havok.com Inc. (and its Licensors). All Rights Reserved. See www.havok.com for details.
This software contains source code provided by NVIDIA Corporation.
All rights reserved. See licenses.txt for details.
Voice chat Audio coding: Polycom(R) Siren14(TM) (ITU-T Rec. G.722.1 Annex C)

43
debian/postinst vendored
View File

@ -1,43 +0,0 @@
#!/bin/sh
# postinst script for secondlife-viewer
#
# Delete this file if you don't need it.
#
# see: dh_installdeb(1)
set -e
# summary of how this script can be called:
# * <postinst> `configure' <most-recently-configured-version>
# * <old-postinst> `abort-upgrade' <new version>
# * <conflictor's-postinst> `abort-remove' `in-favour' <package>
# <new-version>
# * <postinst> `abort-remove'
# * <deconfigured's-postinst> `abort-deconfigure' `in-favour'
# <failed-install-package> <version> `removing'
# <conflicting-package> <version>
# for details, see http://www.debian.org/doc/debian-policy/ or
# the debian-policy package
case "$1" in
configure)
;;
abort-upgrade|abort-remove|abort-deconfigure)
;;
*)
echo "postinst called with unknown argument \`$1'" >&2
exit 1
;;
esac
# dh_installdeb will replace this with shell code automatically
# generated by other debhelper scripts. Don't delete this!
#DEBHELPER#
exit 0

41
debian/postrm vendored
View File

@ -1,41 +0,0 @@
#!/bin/sh
# postrm script for secondlife-viewer
#
# Delete this file if you don't need it.
#
# see: dh_installdeb(1)
set -e
# summary of how this script can be called:
# * <postrm> `remove'
# * <postrm> `purge'
# * <old-postrm> `upgrade' <new-version>
# * <new-postrm> `failed-upgrade' <old-version>
# * <new-postrm> `abort-install'
# * <new-postrm> `abort-install' <old-version>
# * <new-postrm> `abort-upgrade' <old-version>
# * <disappearer's-postrm> `disappear' <overwriter>
# <overwriter-version>
# for details, see http://www.debian.org/doc/debian-policy/ or
# the debian-policy package
case "$1" in
purge|remove|upgrade|failed-upgrade|abort-install|abort-upgrade|disappear)
;;
*)
echo "postrm called with unknown argument \`$1'" >&2
exit 1
;;
esac
# dh_installdeb will replace this with shell code automatically
# generated by other debhelper scripts. Don't delete this!
#DEBHELPER#
exit 0

39
debian/preinst vendored
View File

@ -1,39 +0,0 @@
#!/bin/sh
# preinst script for secondlife-viewer
#
# Delete this file if you don't need it.
#
# see: dh_installdeb(1)
set -e
# summary of how this script can be called:
# * <new-preinst> `install'
# * <new-preinst> `install' <old-version>
# * <new-preinst> `upgrade' <old-version>
# * <old-preinst> `abort-upgrade' <new-version>
# for details, see http://www.debian.org/doc/debian-policy/ or
# the debian-policy package
case "$1" in
install|upgrade)
;;
abort-upgrade)
;;
*)
echo "preinst called with unknown argument \`$1'" >&2
exit 1
;;
esac
# dh_installdeb will replace this with shell code automatically
# generated by other debhelper scripts. Don't delete this!
#DEBHELPER#
exit 0

42
debian/prerm vendored
View File

@ -1,42 +0,0 @@
#!/bin/sh
# prerm script for secondlife-viewer
#
# Delete this file if you don't need it.
#
# see: dh_installdeb(1)
set -e
# summary of how this script can be called:
# * <prerm> `remove'
# * <old-prerm> `upgrade' <new-version>
# * <new-prerm> `failed-upgrade' <old-version>
# * <conflictor's-prerm> `remove' `in-favour' <package> <new-version>
# * <deconfigured's-prerm> `deconfigure' `in-favour'
# <package-being-installed> <version> `removing'
# <conflicting-package> <version>
# for details, see http://www.debian.org/doc/debian-policy/ or
# the debian-policy package
case "$1" in
remove|upgrade|deconfigure)
;;
failed-upgrade)
;;
*)
echo "prerm called with unknown argument \`$1'" >&2
exit 1
;;
esac
# dh_installdeb will replace this with shell code automatically
# generated by other debhelper scripts. Don't delete this!
#DEBHELPER#
exit 0

118
debian/rules vendored
View File

@ -1,118 +0,0 @@
#!/usr/bin/make -f
# -*- makefile -*-
# Sample debian/rules that uses debhelper.
# This file was originally written by Joey Hess and Craig Small.
# As a special exception, when this file is copied by dh-make into a
# dh-make output file, you may use that output file without restriction.
# This special exception was added by Craig Small in version 0.37 of dh-make.
# Uncomment this to turn on verbose mode.
#export DH_VERBOSE=1
BASEDIR=opt/linden
VIEWER_PKG=secondlife-viewer
VIEWER_PACKAGEDIR=build-linux-i686/newview/packaged
VIEWER_DESTDIR=$(CURDIR)/debian/$(VIEWER_PKG)
VIEWER_VERSION:=$(shell dpkg-parsechangelog | grep ^Version | sed 's/^Version: //')
VIEWER_INSTALLDIR:=$(BASEDIR)/viewer/SecondLife-i686-$(VIEWER_VERSION)
configure: configure-stamp
configure-stamp:
dh_testdir
# Add here commands to configure the package.
touch configure-stamp
build: build-stamp
build-stamp: configure-stamp
dh_testdir
# Add here commands to compile the package.
#$(MAKE)
#docbook-to-man debian/secondlife-viewer.sgml > secondlife-viewer.1
touch $@
clean:
dh_testdir
dh_testroot
rm -f build-stamp configure-stamp
# Add here commands to clean up after the build process.
#-$(MAKE) clean
dh_clean
install: build
dh_testdir
dh_testroot
dh_clean -k
dh_installdirs
# Add here commands to install the package into debian/secondlife-viewer.
for file in $$(find $(VIEWER_PACKAGEDIR) -type f -o -type l | sed 's~$(VIEWER_PACKAGEDIR)/~~'); do \
# create containing directory \
install -v -m 755 -o root -g root -d "$$(dirname "$(VIEWER_DESTDIR)/$(VIEWER_INSTALLDIR)/$$file")"; \
PERM=644; \
if [ -x "$(VIEWER_PACKAGEDIR)/$$file" ]; then \
PERM=755; \
fi; \
if [ -L "$(VIEWER_PACKAGEDIR)/$$file" ]; then \
REAL="$$( readlink -f $(VIEWER_PACKAGEDIR)/$$file )"; \
RELATIVE="$$( echo $$REAL | sed 's~$(CURDIR)/$(VIEWER_PACKAGEDIR)/~~' )"; \
echo dh_link -p $(VIEWER_PKG) "$(VIEWER_INSTALLDIR)/$$RELATIVE" "$(VIEWER_INSTALLDIR)/$$file" ; \
dh_link -p $(VIEWER_PKG) "$(VIEWER_INSTALLDIR)/$$RELATIVE" "$(VIEWER_INSTALLDIR)/$$file" ; \
else \
install -v -m $$PERM -o root -g root "$(VIEWER_PACKAGEDIR)/$$file" "$(VIEWER_DESTDIR)/$(VIEWER_INSTALLDIR)/$$file"; \
fi; \
done
dh_link -p $(VIEWER_PKG) /$(VIEWER_INSTALLDIR)/secondlife /usr/bin/secondlife
dh_link -p $(VIEWER_PKG) $(BASEDIR)/viewer/SecondLife-i686-$(VIEWER_VERSION) $(BASEDIR)/viewer/SecondLife
# Build architecture-independent files here.
binary-indep: build install
# We have nothing to do by default.
# Build architecture-dependent files here.
binary-arch: build install
dh_testdir
dh_testroot
dh_installchangelogs
dh_installdocs
dh_installexamples
# dh_install
# dh_installmenu
# dh_installdebconf
# dh_installlogrotate
# dh_installemacsen
# dh_installpam
# dh_installmime
# dh_python
# To add an init script, uncomment this line and edit debian/init.d and
# customize debian/secondlife-viewer.default to suit your needs.
# dh_installinit
# To add cron jobs, uncomment this line and make a crontab file named
# debian/cron.d, and it will be installed in /etc/cron.d/
# dh_installcron
# dh_installinfo
dh_installman
dh_link
# dh_strip
dh_compress
# dh_fixperms
# dh_perl
# dh_makeshlibs
dh_installdeb
# dh_shlibdeps
dh_gencontrol
dh_md5sums
dh_builddeb
binary: binary-indep binary-arch
.PHONY: build clean binary-indep binary-arch binary install configure

View File

@ -1,8 +0,0 @@
# Linden packages install in opt/linden
secondlife-viewer: dir-or-file-in-opt
secondlife-viewer: section-is-dh_make-template
secondlife-viewer: binary-without-manpage
secondlife-viewer: maintainer-script-empty postrm
secondlife-viewer: maintainer-script-empty preinst
secondlife-viewer: maintainer-script-empty prerm
secondlife-viewer: unstripped-binary-or-object

View File

@ -273,6 +273,7 @@ Beq Janus
SL-13583
SL-14766
SL-14927
SL-11300
Beth Walcher
Bezilon Kasei
Biancaluce Robbiani
@ -813,6 +814,7 @@ Jonathan Yap
STORM-2142
STORM-2145
SL-10089
BUG-229818
Kadah Coba
STORM-1060
STORM-1843

BIN
doc/sl-logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.4 KiB

View File

@ -82,7 +82,7 @@ if (WINDOWS)
# CP changed to only append the flag for 32bit builds - on 64bit builds,
# locally at least, the build output is spammed with 1000s of 'D9002'
# warnings about this switch being ignored.
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /MP")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /MP")
# <FS:ND> Remove this, it's no option to cl.exe and causes a massive amount of warnings.
#if( ADDRESS_SIZE EQUAL 32 )
#set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /p:PreferredToolArchitecture=x64")
@ -165,6 +165,11 @@ endif (WINDOWS)
if (LINUX)
set(CMAKE_SKIP_RPATH TRUE)
if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 10.0.0 )
message( FATAL_ERROR "GCC greater 9.4.0 is not supported. Recompile boost for support of GCC 10.0.0 and up." )
endif()
# <FS:ND/>
# 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.

View File

@ -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)

View File

@ -60,7 +60,7 @@ if (EXISTS ${CMAKE_SOURCE_DIR}/Server.cmake)
set(INSTALL_PROPRIETARY ON CACHE BOOL "Install proprietary binaries")
endif (EXISTS ${CMAKE_SOURCE_DIR}/Server.cmake)
set(TEMPLATE_VERIFIER_OPTIONS "" CACHE STRING "Options for scripts/template_verifier.py")
set(TEMPLATE_VERIFIER_MASTER_URL "https://bitbucket.org/lindenlab/master-message-template-git/raw/HEAD/message_template.msg" CACHE STRING "Location of the master message template")
set(TEMPLATE_VERIFIER_MASTER_URL "https://bitbucket.org/lindenlab/master-message-template-git/raw/master/message_template.msg" CACHE STRING "Location of the master message template")
if (NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE RelWithDebInfo CACHE STRING

View File

@ -1,3 +1,3 @@
euclid 5/29/2020
euclid 7/23/2020
euclid 4/29/2021
euclid 4/29/2021

View File

@ -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");

View File

@ -76,17 +76,17 @@ LLWearable::~LLWearable()
const std::string& LLWearable::getTypeLabel() const
{
return LLWearableType::getTypeLabel(mType);
return LLWearableType::getInstance()->getTypeLabel(mType);
}
const std::string& LLWearable::getTypeName() const
{
return LLWearableType::getTypeName(mType);
return LLWearableType::getInstance()->getTypeName(mType);
}
LLAssetType::EType LLWearable::getAssetType() const
{
return LLWearableType::getAssetType(mType);
return LLWearableType::getInstance()->getAssetType(mType);
}
BOOL LLWearable::exportFile(const std::string& filename) const

View File

@ -241,10 +241,11 @@ BOOL LLWearableData::getWearableIndex(const LLWearable *wearable, U32& index_fou
U32 LLWearableData::getClothingLayerCount() const
{
U32 count = 0;
LLWearableType *wr_inst = LLWearableType::getInstance();
for (S32 i = 0; i < LLWearableType::WT_COUNT; i++)
{
LLWearableType::EType type = (LLWearableType::EType)i;
if (LLWearableType::getAssetType(type)==LLAssetType::AT_CLOTHING)
if (wr_inst->getAssetType(type)==LLAssetType::AT_CLOTHING)
{
count += getWearableCount(type);
}
@ -254,7 +255,7 @@ U32 LLWearableData::getClothingLayerCount() const
BOOL LLWearableData::canAddWearable(const LLWearableType::EType type) const
{
LLAssetType::EType a_type = LLWearableType::getAssetType(type);
LLAssetType::EType a_type = LLWearableType::getInstance()->getAssetType(type);
if (a_type==LLAssetType::AT_CLOTHING)
{
if (type == LLWearableType::WT_PHYSICS) return (getWearableCount(type) < 1); // <FS:Ansariel> Don't add physics layer

View File

@ -30,162 +30,101 @@
#include "llinventorydefines.h"
struct WearableEntry : public LLDictionaryEntry
LLWearableType::LLWearableDictionary::LLWearableDictionary(LLTranslationBridge::ptr_t& trans)
{
WearableEntry(LLWearableType& wtype,
const std::string &name,
const std::string& default_new_name,
LLAssetType::EType assetType,
LLInventoryType::EIconName iconName,
BOOL disable_camera_switch = FALSE,
BOOL allow_multiwear = TRUE) :
LLDictionaryEntry(name),
mAssetType(assetType),
mDefaultNewName(default_new_name),
mLabel(wtype.mTrans->getString(name)),
mIconName(iconName),
mDisableCameraSwitch(disable_camera_switch),
mAllowMultiwear(allow_multiwear)
{
}
const LLAssetType::EType mAssetType;
const std::string mLabel;
const std::string mDefaultNewName; //keep mLabel for backward compatibility
LLInventoryType::EIconName mIconName;
BOOL mDisableCameraSwitch;
BOOL mAllowMultiwear;
};
class LLWearableDictionary : public LLParamSingleton<LLWearableDictionary>,
public LLDictionary<LLWearableType::EType, WearableEntry>
{
LLSINGLETON(LLWearableDictionary, LLWearableType&);
// [RLVa:KB] - Checked: 2010-03-03 (RLVa-1.2.0a) | Added: RLVa-1.2.0a
protected:
// The default implementation asserts on 'notFound()' and returns -1 which isn't a valid EWearableType
virtual LLWearableType::EType notFound() const { return LLWearableType::WT_INVALID; }
// [/RLVa:KB]
};
LLWearableDictionary::LLWearableDictionary(LLWearableType& wtype)
{
addEntry(LLWearableType::WT_SHAPE, new WearableEntry(wtype, "shape", "New Shape", LLAssetType::AT_BODYPART, LLInventoryType::ICONNAME_BODYPART_SHAPE, FALSE, FALSE));
addEntry(LLWearableType::WT_SKIN, new WearableEntry(wtype, "skin", "New Skin", LLAssetType::AT_BODYPART, LLInventoryType::ICONNAME_BODYPART_SKIN, FALSE, FALSE));
addEntry(LLWearableType::WT_HAIR, new WearableEntry(wtype, "hair", "New Hair", LLAssetType::AT_BODYPART, LLInventoryType::ICONNAME_BODYPART_HAIR, FALSE, FALSE));
addEntry(LLWearableType::WT_EYES, new WearableEntry(wtype, "eyes", "New Eyes", LLAssetType::AT_BODYPART, LLInventoryType::ICONNAME_BODYPART_EYES, FALSE, FALSE));
addEntry(LLWearableType::WT_SHIRT, new WearableEntry(wtype, "shirt", "New Shirt", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_SHIRT, FALSE, TRUE));
addEntry(LLWearableType::WT_PANTS, new WearableEntry(wtype, "pants", "New Pants", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_PANTS, FALSE, TRUE));
addEntry(LLWearableType::WT_SHOES, new WearableEntry(wtype, "shoes", "New Shoes", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_SHOES, FALSE, TRUE));
addEntry(LLWearableType::WT_SOCKS, new WearableEntry(wtype, "socks", "New Socks", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_SOCKS, FALSE, TRUE));
addEntry(LLWearableType::WT_JACKET, new WearableEntry(wtype, "jacket", "New Jacket", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_JACKET, FALSE, TRUE));
addEntry(LLWearableType::WT_GLOVES, new WearableEntry(wtype, "gloves", "New Gloves", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_GLOVES, FALSE, TRUE));
addEntry(LLWearableType::WT_UNDERSHIRT, new WearableEntry(wtype, "undershirt", "New Undershirt", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_UNDERSHIRT, FALSE, TRUE));
addEntry(LLWearableType::WT_UNDERPANTS, new WearableEntry(wtype, "underpants", "New Underpants", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_UNDERPANTS, FALSE, TRUE));
addEntry(LLWearableType::WT_SKIRT, new WearableEntry(wtype, "skirt", "New Skirt", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_SKIRT, FALSE, TRUE));
addEntry(LLWearableType::WT_ALPHA, new WearableEntry(wtype, "alpha", "New Alpha", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_ALPHA, FALSE, TRUE));
addEntry(LLWearableType::WT_TATTOO, new WearableEntry(wtype, "tattoo", "New Tattoo", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_TATTOO, FALSE, TRUE));
addEntry(LLWearableType::WT_UNIVERSAL, new WearableEntry(wtype, "universal", "New Universal", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_UNIVERSAL, FALSE, TRUE));
addEntry(LLWearableType::WT_SHAPE, new WearableEntry(trans, "shape", "New Shape", LLAssetType::AT_BODYPART, LLInventoryType::ICONNAME_BODYPART_SHAPE, FALSE, FALSE));
addEntry(LLWearableType::WT_SKIN, new WearableEntry(trans, "skin", "New Skin", LLAssetType::AT_BODYPART, LLInventoryType::ICONNAME_BODYPART_SKIN, FALSE, FALSE));
addEntry(LLWearableType::WT_HAIR, new WearableEntry(trans, "hair", "New Hair", LLAssetType::AT_BODYPART, LLInventoryType::ICONNAME_BODYPART_HAIR, FALSE, FALSE));
addEntry(LLWearableType::WT_EYES, new WearableEntry(trans, "eyes", "New Eyes", LLAssetType::AT_BODYPART, LLInventoryType::ICONNAME_BODYPART_EYES, FALSE, FALSE));
addEntry(LLWearableType::WT_SHIRT, new WearableEntry(trans, "shirt", "New Shirt", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_SHIRT, FALSE, TRUE));
addEntry(LLWearableType::WT_PANTS, new WearableEntry(trans, "pants", "New Pants", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_PANTS, FALSE, TRUE));
addEntry(LLWearableType::WT_SHOES, new WearableEntry(trans, "shoes", "New Shoes", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_SHOES, FALSE, TRUE));
addEntry(LLWearableType::WT_SOCKS, new WearableEntry(trans, "socks", "New Socks", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_SOCKS, FALSE, TRUE));
addEntry(LLWearableType::WT_JACKET, new WearableEntry(trans, "jacket", "New Jacket", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_JACKET, FALSE, TRUE));
addEntry(LLWearableType::WT_GLOVES, new WearableEntry(trans, "gloves", "New Gloves", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_GLOVES, FALSE, TRUE));
addEntry(LLWearableType::WT_UNDERSHIRT, new WearableEntry(trans, "undershirt", "New Undershirt", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_UNDERSHIRT, FALSE, TRUE));
addEntry(LLWearableType::WT_UNDERPANTS, new WearableEntry(trans, "underpants", "New Underpants", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_UNDERPANTS, FALSE, TRUE));
addEntry(LLWearableType::WT_SKIRT, new WearableEntry(trans, "skirt", "New Skirt", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_SKIRT, FALSE, TRUE));
addEntry(LLWearableType::WT_ALPHA, new WearableEntry(trans, "alpha", "New Alpha", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_ALPHA, FALSE, TRUE));
addEntry(LLWearableType::WT_TATTOO, new WearableEntry(trans, "tattoo", "New Tattoo", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_TATTOO, FALSE, TRUE));
addEntry(LLWearableType::WT_UNIVERSAL, new WearableEntry(trans, "universal", "New Universal", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_UNIVERSAL, FALSE, TRUE));
// [SL:KB] - Patch: Appearance-Misc | Checked: 2011-05-29 (Catznip-2.6)
addEntry(LLWearableType::WT_PHYSICS, new WearableEntry(wtype, "physics", "New Physics", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_PHYSICS, TRUE, FALSE));
addEntry(LLWearableType::WT_PHYSICS, new WearableEntry(trans, "physics", "New Physics", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_PHYSICS, TRUE, FALSE));
// [/SL:KB]
// addEntry(LLWearableType::WT_PHYSICS, new WearableEntry(wtype, "physics", "New Physics", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_PHYSICS, TRUE, TRUE));
// addEntry(LLWearableType::WT_PHYSICS, new WearableEntry(trans, "physics", "New Physics", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_PHYSICS, TRUE, TRUE));
addEntry(LLWearableType::WT_INVALID, new WearableEntry(wtype, "invalid", "Invalid Wearable", LLAssetType::AT_NONE, LLInventoryType::ICONNAME_UNKNOWN, FALSE, FALSE));
addEntry(LLWearableType::WT_NONE, new WearableEntry(wtype, "none", "Invalid Wearable", LLAssetType::AT_NONE, LLInventoryType::ICONNAME_NONE, FALSE, FALSE));
addEntry(LLWearableType::WT_INVALID, new WearableEntry(trans, "invalid", "Invalid Wearable", LLAssetType::AT_NONE, LLInventoryType::ICONNAME_UNKNOWN, FALSE, FALSE));
addEntry(LLWearableType::WT_NONE, new WearableEntry(trans, "none", "Invalid Wearable", LLAssetType::AT_NONE, LLInventoryType::ICONNAME_NONE, FALSE, FALSE));
}
// class LLWearableType
LLWearableType::LLWearableType(LLTranslationBridge* trans)
LLWearableType::LLWearableType(LLTranslationBridge::ptr_t &trans)
: mDictionary(trans)
{
// LLTranslationBridge exists, but is not ready at this point in time since strings.xml is not yet loaded
mTrans = trans;
}
LLWearableType::~LLWearableType()
{
delete mTrans;
}
void LLWearableType::initSingleton()
{
// To make sure all wrapping functions will crash without initing LLWearableType;
LLWearableDictionary::initParamSingleton(*this);
// Todo: consider merging LLWearableType and LLWearableDictionary
}
// static
LLWearableType::EType LLWearableType::typeNameToType(const std::string& type_name)
{
const LLWearableDictionary *dict = LLWearableDictionary::getInstance();
const LLWearableType::EType wearable = dict->lookup(type_name);
const LLWearableType::EType wearable = mDictionary.lookup(type_name);
return wearable;
}
// static
const std::string& LLWearableType::getTypeName(LLWearableType::EType type)
{
const LLWearableDictionary *dict = LLWearableDictionary::getInstance();
const WearableEntry *entry = dict->lookup(type);
const WearableEntry *entry = mDictionary.lookup(type);
if (!entry) return getTypeName(WT_INVALID);
return entry->mName;
}
//static
const std::string& LLWearableType::getTypeDefaultNewName(LLWearableType::EType type)
{
const LLWearableDictionary *dict = LLWearableDictionary::getInstance();
const WearableEntry *entry = dict->lookup(type);
const WearableEntry *entry = mDictionary.lookup(type);
if (!entry) return getTypeDefaultNewName(WT_INVALID);
return entry->mDefaultNewName;
}
// static
const std::string& LLWearableType::getTypeLabel(LLWearableType::EType type)
{
const LLWearableDictionary *dict = LLWearableDictionary::getInstance();
const WearableEntry *entry = dict->lookup(type);
const WearableEntry *entry = mDictionary.lookup(type);
if (!entry) return getTypeLabel(WT_INVALID);
return entry->mLabel;
}
// static
LLAssetType::EType LLWearableType::getAssetType(LLWearableType::EType type)
{
const LLWearableDictionary *dict = LLWearableDictionary::getInstance();
const WearableEntry *entry = dict->lookup(type);
const WearableEntry *entry = mDictionary.lookup(type);
if (!entry) return getAssetType(WT_INVALID);
return entry->mAssetType;
}
// static
LLInventoryType::EIconName LLWearableType::getIconName(LLWearableType::EType type)
{
const LLWearableDictionary *dict = LLWearableDictionary::getInstance();
const WearableEntry *entry = dict->lookup(type);
const WearableEntry *entry = mDictionary.lookup(type);
if (!entry) return getIconName(WT_INVALID);
return entry->mIconName;
}
// static
BOOL LLWearableType::getDisableCameraSwitch(LLWearableType::EType type)
{
const LLWearableDictionary *dict = LLWearableDictionary::getInstance();
const WearableEntry *entry = dict->lookup(type);
const WearableEntry *entry = mDictionary.lookup(type);
if (!entry) return FALSE;
return entry->mDisableCameraSwitch;
}
// static
BOOL LLWearableType::getAllowMultiwear(LLWearableType::EType type)
{
const LLWearableDictionary *dict = LLWearableDictionary::getInstance();
const WearableEntry *entry = dict->lookup(type);
const WearableEntry *entry = mDictionary.lookup(type);
if (!entry) return FALSE;
return entry->mAllowMultiwear;
}

View File

@ -35,10 +35,9 @@
class LLWearableType : public LLParamSingleton<LLWearableType>
{
LLSINGLETON(LLWearableType, LLTranslationBridge* trans);
LLSINGLETON(LLWearableType, LLTranslationBridge::ptr_t &trans);
~LLWearableType();
void initSingleton();
friend struct WearableEntry;
public:
enum EType
{
@ -67,20 +66,59 @@ public:
// Most methods are wrappers for dictionary, but if LLWearableType is not initialized,
// they will crash. Whole LLWearableType is just wrapper for convinient calls.
static const std::string& getTypeName(EType type);
static const std::string& getTypeDefaultNewName(EType type);
static const std::string& getTypeLabel(EType type);
static LLAssetType::EType getAssetType(EType type);
static EType typeNameToType(const std::string& type_name);
static LLInventoryType::EIconName getIconName(EType type);
static BOOL getDisableCameraSwitch(EType type);
static BOOL getAllowMultiwear(EType type);
const std::string& getTypeName(EType type);
const std::string& getTypeDefaultNewName(EType type);
const std::string& getTypeLabel(EType type);
LLAssetType::EType getAssetType(EType type);
EType typeNameToType(const std::string& type_name);
LLInventoryType::EIconName getIconName(EType type);
BOOL getDisableCameraSwitch(EType type);
BOOL getAllowMultiwear(EType type);
static EType inventoryFlagsToWearableType(U32 flags);
protected:
private:
struct WearableEntry : public LLDictionaryEntry
{
WearableEntry(LLTranslationBridge::ptr_t& trans,
const std::string &name,
const std::string& default_new_name,
LLAssetType::EType assetType,
LLInventoryType::EIconName iconName,
BOOL disable_camera_switch = FALSE,
BOOL allow_multiwear = TRUE) :
LLDictionaryEntry(name),
mAssetType(assetType),
mDefaultNewName(default_new_name),
mLabel(trans->getString(name)),
mIconName(iconName),
mDisableCameraSwitch(disable_camera_switch),
mAllowMultiwear(allow_multiwear)
{
LLTranslationBridge* mTrans;
}
const LLAssetType::EType mAssetType;
const std::string mLabel;
const std::string mDefaultNewName;
LLInventoryType::EIconName mIconName;
BOOL mDisableCameraSwitch;
BOOL mAllowMultiwear;
};
class LLWearableDictionary : public LLDictionary<LLWearableType::EType, WearableEntry>
{
public:
LLWearableDictionary(LLTranslationBridge::ptr_t& trans);
~LLWearableDictionary() {}
// [RLVa:KB] - Checked: 2010-03-03 (RLVa-1.2.0a) | Added: RLVa-1.2.0a
protected:
// The default implementation asserts on 'notFound()' and returns -1 which isn't a valid EWearableType
virtual LLWearableType::EType notFound() const { return LLWearableType::WT_INVALID; }
// [/RLVa:KB]
};
LLWearableDictionary mDictionary;
};
#endif // LL_LLWEARABLETYPE_H

View File

@ -72,7 +72,8 @@ mSystem(system),
mCurrentInternetStreamp(NULL),
mStreamGroup(NULL),
mFMODInternetStreamChannelp(NULL),
mGain(1.0f)
mGain(1.0f),
mWasAlreadyPlaying(false)
{
// Number of milliseconds of audio to buffer for the audio card.
// Must be larger than the usual Second Life frame stutter time.
@ -158,18 +159,14 @@ void LLStreamingAudio_FMODSTUDIO::update()
if (Check_FMOD_Error(mCurrentInternetStreamp->getOpenState(open_state, &progress, &starving, &diskbusy), "FMOD::Sound::getOpenState"))
{
LL_WARNS() << "Internet stream openstate error: open_state = " << open_state << " - progress = " << progress << " - starving = " << starving << " - diskbusy = " << diskbusy << LL_ENDL;
bool was_playing = mWasAlreadyPlaying;
stop();
return;
}
else if (open_state == FMOD_OPENSTATE_ERROR)
{
// Actually we might not get into this case at all since according to the
// FMOD API doc, one should check the result of getOpenState for further
// details, which most likely means if open_state is FMOD_OPENSTATE_ERROR,
// calling getOpenState will return anything but FMOD_OK and we end up in
// the if-case above.
LL_WARNS() << "Internet stream openstate error: progress = " << progress << " - starving = " << starving << " - diskbusy = " << diskbusy << LL_ENDL;
stop();
// Try to restart previously playing stream on socket error
if (open_state == FMOD_OPENSTATE_ERROR && was_playing)
{
LL_WARNS() << "Stream was playing before - trying to restart" << LL_ENDL;
start(mURL);
}
return;
}
else if (open_state == FMOD_OPENSTATE_READY)
@ -183,6 +180,14 @@ void LLStreamingAudio_FMODSTUDIO::update()
// Reset volume to previously set volume
setGain(getGain());
Check_FMOD_Error(mFMODInternetStreamChannelp->setPaused(false), "FMOD::Channel::setPaused");
mWasAlreadyPlaying = true;
}
}
else if (open_state == FMOD_OPENSTATE_PLAYING)
{
if (!mWasAlreadyPlaying)
{
mWasAlreadyPlaying = true;
}
}
@ -317,6 +322,7 @@ void LLStreamingAudio_FMODSTUDIO::update()
void LLStreamingAudio_FMODSTUDIO::stop()
{
mPendingURL.clear();
mWasAlreadyPlaying = false;
if (mFMODInternetStreamChannelp)
{

View File

@ -80,6 +80,8 @@ private:
bool mNewMetadata;
LLSD mMetadata;
// </DKO> Streamtitle display
bool mWasAlreadyPlaying;
};

View File

@ -208,9 +208,9 @@ set(llcommon_HEADER_FILES
llqueuedthread.h
llrand.h
llrefcount.h
llregex.h
llregistry.h
llrun.h
llrefcount.h
llsafehandle.h
llsd.h
llsdjson.h
@ -256,13 +256,14 @@ set(llcommon_HEADER_FILES
StackWalker.h
)
# <FS:ND> Add all nd* files. memory pool, intrinsics, ...
# <FS:Beq> Tracy Profiler support
list(APPEND llcommon_SOURCE_FILES fstelemetry.cpp)
if (USE_TRACY_PROFILER)
list(APPEND llcommon_SOURCE_FILES fstracyclient.cpp)
endif()
# <FS:Beq> Tracy Profiler support
list(APPEND llcommon_SOURCE_FILES fstelemetry.cpp)
if (USE_TRACY_PROFILER)
list(APPEND llcommon_SOURCE_FILES fstracyclient.cpp)
endif()
# </FS:Beq> Tracy Profiler support
# <FS:ND> Add all nd* files. memory pool, intrinsics, ...
SET( llcommon_ND_SOURCE_FILES
nd/ndexceptions.cpp
nd/ndlogthrottle.cpp

View File

@ -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 <type_traits>
#include <cerrno>
#include <memory>
#include <chrono>
#include <ctime>
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<typename T, typename Traits = ConcurrentQueueDefaultTraits>
class BlockingConcurrentQueue
{
private:
typedef ::moodycamel::ConcurrentQueue<T, Traits> 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<size_t>::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<LightweightSemaphore, ssize_t, int>(0, (int)Traits::MAX_SEMA_SPINS), &BlockingConcurrentQueue::template destroy<LightweightSemaphore>)
{
assert(reinterpret_cast<ConcurrentQueue*>((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<LightweightSemaphore, ssize_t, int>(0, (int)Traits::MAX_SEMA_SPINS), &BlockingConcurrentQueue::template destroy<LightweightSemaphore>)
{
assert(reinterpret_cast<ConcurrentQueue*>((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<typename It>
inline bool enqueue_bulk(It itemFirst, size_t count)
{
if ((details::likely)(inner.enqueue_bulk(std::forward<It>(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<typename It>
inline bool enqueue_bulk(producer_token_t const& token, It itemFirst, size_t count)
{
if ((details::likely)(inner.enqueue_bulk(token, std::forward<It>(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<typename It>
inline bool try_enqueue_bulk(It itemFirst, size_t count)
{
if (inner.try_enqueue_bulk(std::forward<It>(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<typename It>
inline bool try_enqueue_bulk(producer_token_t const& token, It itemFirst, size_t count)
{
if (inner.try_enqueue_bulk(token, std::forward<It>(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<typename U>
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<typename U>
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<typename It>
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<It&>(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<typename It>
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<It&>(token, itemFirst, max - count);
}
return count;
}
// Blocks the current thread until there's something to dequeue, then
// dequeues it.
// Never allocates. Thread-safe.
template<typename U>
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<typename U>
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<typename U, typename Rep, typename Period>
inline bool wait_dequeue_timed(U& item, std::chrono::duration<Rep, Period> const& timeout)
{
return wait_dequeue_timed(item, std::chrono::duration_cast<std::chrono::microseconds>(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<typename U>
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<typename U>
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<typename U, typename Rep, typename Period>
inline bool wait_dequeue_timed(consumer_token_t& token, U& item, std::chrono::duration<Rep, Period> const& timeout)
{
return wait_dequeue_timed(token, item, std::chrono::duration_cast<std::chrono::microseconds>(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<typename It>
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<It&>(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<typename It>
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<It&>(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<typename It, typename Rep, typename Period>
inline size_t wait_dequeue_bulk_timed(It itemFirst, size_t max, std::chrono::duration<Rep, Period> const& timeout)
{
return wait_dequeue_bulk_timed<It&>(itemFirst, max, std::chrono::duration_cast<std::chrono::microseconds>(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<typename It>
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<It&>(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<typename It>
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<It&>(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<typename It, typename Rep, typename Period>
inline size_t wait_dequeue_bulk_timed(consumer_token_t& token, It itemFirst, size_t max, std::chrono::duration<Rep, Period> const& timeout)
{
return wait_dequeue_bulk_timed<It&>(token, itemFirst, max, std::chrono::duration_cast<std::chrono::microseconds>(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<typename U, typename A1, typename A2>
static inline U* create(A1&& a1, A2&& a2)
{
void* p = (Traits::malloc)(sizeof(U));
return p != nullptr ? new (p) U(std::forward<A1>(a1), std::forward<A2>(a2)) : nullptr;
}
template<typename U>
static inline void destroy(U* p)
{
if (p != nullptr) {
p->~U();
}
(Traits::free)(p);
}
private:
ConcurrentQueue inner;
std::unique_ptr<LightweightSemaphore, void (*)(LightweightSemaphore*)> sema;
};
template<typename T, typename Traits>
inline void swap(BlockingConcurrentQueue<T, Traits>& a, BlockingConcurrentQueue<T, Traits>& b) MOODYCAMEL_NOEXCEPT
{
a.swap(b);
}
} // end namespace moodycamel

File diff suppressed because it is too large Load Diff

View File

@ -28,4 +28,5 @@
namespace FSTelemetry
{
bool active{false};
}

View File

@ -43,9 +43,15 @@
#define FSZoneN( name ) ZoneNamedN( ___tracy_scoped_zone, name, FSTelemetry::active)
#define FSZoneC( color ) ZoneNamedC( ___tracy_scoped_zone, color, FSTelemetry::active)
#define FSZoneNC( name, color ) ZoneNamedNC( ___tracy_scoped_zone, name, color, FSTelemetry::active)
#define FSZoneText( text, size ) ZoneText( text, size )
#define FSZoneValue( num_uint64 ) ZoneValue( num_uint64 )
#define FSPlot( name, value ) TracyPlot( name, value)
#define FSPlotSq( name, lastval, newval ) TracyPlot( name, lastval);TracyPlot( name, newval);
#define FSFrameMark FrameMark
#define FSFrameMarkStart( name ) FrameMarkStart( name )
#define FSFrameMarkEnd( name ) FrameMarkEnd( name )
#define FSThreadName( name ) tracy::SetThreadName( name )
#define FSMessageL ( message ) tracy::Profiler::Message( message, 0 )
#define FSTelemetryIsConnected TracyIsConnected
#else // (no telemetry)
@ -57,15 +63,26 @@
#define FSZoneN( name )
#define FSZoneC( color )
#define FSZoneNC( name, color )
#define FSZoneText( text, size )
#define FSZoneValue( num_uint64 )
#define FSPlot( name, value )
#define FSPlotSq( name, lastval, newval )
#define FSFrameMark
#define FSFrameMarkStart( name )
#define FSFrameMarkEnd( name )
#define FSThreadName( name )
#define FSMessageL( message )
#define FSTelemetryIsConnected
#endif // TRACY_ENABLE
#include <chrono>
#include <array>
#include <unordered_map>
namespace FSTelemetry
{
extern bool active;
}
}// namespace FSTelemetry
#endif

View File

@ -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 <cstddef> // For std::size_t
#include <atomic>
#include <type_traits> // For std::make_signed<T>
#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 <mach/mach.h>
#elif defined(__unix__)
#include <semaphore.h>
#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<unsigned int>(timeout_usecs / 1000000);
ts.tv_nsec = static_cast<int>((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<unsigned int>(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<std::size_t>::type ssize_t;
private:
std::atomic<ssize_t> 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<std::size_t>(count) : 0;
}
};
} // end namespace moodycamel

View File

@ -134,6 +134,13 @@ LLCoros::LLCoros():
LLCoros::~LLCoros()
{
}
void LLCoros::cleanupSingleton()
{
// Some of the coroutines (like voice) will depend onto
// origin singletons, so clean coros before deleting those
printActiveCoroutines("at entry to ~LLCoros()");
// Other LLApp status-change listeners do things like close
// work queues and inject the Stop exception into pending
@ -149,6 +156,8 @@ LLCoros::~LLCoros()
{
// don't use llcoro::suspend() because that module depends
// on this one
// This will yield current(main) thread and will let active
// corutines run once
boost::this_fiber::yield();
}
printActiveCoroutines("after pumping");

View File

@ -89,6 +89,8 @@ class LL_COMMON_API LLCoros: public LLSingleton<LLCoros>
{
LLSINGLETON(LLCoros);
~LLCoros();
void cleanupSingleton();
public:
/// The viewer's use of the term "coroutine" became deeply embedded before
/// the industry term "fiber" emerged to distinguish userland threads from

View File

@ -481,6 +481,62 @@ namespace
typedef std::vector<LLError::RecorderPtr> Recorders;
typedef std::vector<LLError::CallSite*> 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<std::string, unsigned int> mUniqueLogMessages;
LLError::FatalFunction mCrashFunction;
LLError::TimeFunction mTimeFunction;
Recorders mRecorders;
LLMutex mRecorderMutex;
int mShouldLogCallCounter;
private:
SettingsConfig();
};
typedef LLPointer<SettingsConfig> SettingsConfigPtr;
SettingsConfig::SettingsConfig()
: LLRefCount(),
mDefaultLevel(LLError::LEVEL_DEBUG),
mLogAlwaysFlush(true),
mEnabledLogTypesMask(255),
mFunctionLevelMap(),
mClassLevelMap(),
mFileLevelMap(),
mTagLevelMap(),
mUniqueLogMessages(),
mCrashFunction(NULL),
mTimeFunction(NULL),
mRecorders(),
mRecorderMutex(),
mShouldLogCallCounter(0)
{
}
SettingsConfig::~SettingsConfig()
{
mRecorders.clear();
}
class Globals
{
public:
@ -488,16 +544,28 @@ namespace
protected:
Globals();
public:
std::ostringstream messageStream;
bool messageStreamInUse;
std::string mFatalMessage;
void addCallSite(LLError::CallSite&);
void invalidateCallSites();
SettingsConfigPtr getSettingsConfig();
void resetSettingsConfig();
LLError::SettingsStoragePtr saveAndResetSettingsConfig();
void restore(LLError::SettingsStoragePtr pSettingsStorage);
private:
CallSiteVector callSites;
SettingsConfigPtr mSettingsConfig;
};
Globals::Globals() {}
Globals::Globals()
: mSettingsConfig(new SettingsConfig())
{
}
Globals* Globals::getInstance()
{
@ -525,120 +593,31 @@ namespace
callSites.clear();
}
}
namespace LLError
{
class SettingsConfig : public LLRefCount
{
friend class Settings;
public:
virtual ~SettingsConfig();
LLError::ELevel mDefaultLevel;
bool mLogAlwaysFlush;
U32 mEnabledLogTypesMask;
LevelMap mFunctionLevelMap;
LevelMap mClassLevelMap;
LevelMap mFileLevelMap;
LevelMap mTagLevelMap;
std::map<std::string, unsigned int> mUniqueLogMessages;
LLError::FatalFunction mCrashFunction;
LLError::TimeFunction mTimeFunction;
Recorders mRecorders;
int mShouldLogCallCounter;
private:
SettingsConfig();
};
typedef LLPointer<SettingsConfig> SettingsConfigPtr;
class Settings
{
public:
static Settings* getInstance();
protected:
Settings();
public:
SettingsConfigPtr getSettingsConfig();
void reset();
SettingsStoragePtr saveAndReset();
void restore(SettingsStoragePtr pSettingsStorage);
private:
SettingsConfigPtr mSettingsConfig;
};
SettingsConfig::SettingsConfig()
: LLRefCount(),
mDefaultLevel(LLError::LEVEL_DEBUG),
mLogAlwaysFlush(true),
mEnabledLogTypesMask(255),
mFunctionLevelMap(),
mClassLevelMap(),
mFileLevelMap(),
mTagLevelMap(),
mUniqueLogMessages(),
mCrashFunction([](const std::string&){}),
mTimeFunction(NULL),
mRecorders(),
mShouldLogCallCounter(0)
{
}
SettingsConfig::~SettingsConfig()
{
mRecorders.clear();
}
Settings::Settings():
mSettingsConfig(new SettingsConfig())
{
}
Settings* Settings::getInstance()
SettingsConfigPtr Globals::getSettingsConfig()
{
// According to C++11 Function-Local Initialization
// of static variables is supposed to be thread safe
// without risk of deadlocks.
static Settings inst;
return &inst;
return mSettingsConfig;
}
SettingsConfigPtr Settings::getSettingsConfig()
{
return mSettingsConfig;
}
void Globals::resetSettingsConfig()
{
invalidateCallSites();
mSettingsConfig = new SettingsConfig();
}
void Settings::reset()
{
Globals::getInstance()->invalidateCallSites();
mSettingsConfig = new SettingsConfig();
}
LLError::SettingsStoragePtr Globals::saveAndResetSettingsConfig()
{
LLError::SettingsStoragePtr oldSettingsConfig(mSettingsConfig.get());
resetSettingsConfig();
return oldSettingsConfig;
}
SettingsStoragePtr Settings::saveAndReset()
{
SettingsStoragePtr oldSettingsConfig(mSettingsConfig.get());
reset();
return oldSettingsConfig;
}
void Settings::restore(SettingsStoragePtr pSettingsStorage)
{
Globals::getInstance()->invalidateCallSites();
SettingsConfigPtr newSettingsConfig(dynamic_cast<SettingsConfig *>(pSettingsStorage.get()));
mSettingsConfig = newSettingsConfig;
}
void Globals::restore(LLError::SettingsStoragePtr pSettingsStorage)
{
invalidateCallSites();
SettingsConfigPtr newSettingsConfig(dynamic_cast<SettingsConfig *>(pSettingsStorage.get()));
mSettingsConfig = newSettingsConfig;
}
}
namespace LLError
@ -768,7 +747,7 @@ namespace
void commonInit(const std::string& user_dir, const std::string& app_dir, bool log_to_stderr = true)
{
LLError::Settings::getInstance()->reset();
Globals::getInstance()->resetSettingsConfig();
LLError::setDefaultLevel(LLError::LEVEL_INFO);
LLError::setAlwaysFlush(true);
@ -809,13 +788,13 @@ namespace LLError
void setFatalFunction(const FatalFunction& f)
{
SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig();
SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig();
s->mCrashFunction = f;
}
FatalFunction getFatalFunction()
{
SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig();
SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig();
return s->mCrashFunction;
}
@ -826,72 +805,77 @@ namespace LLError
void setTimeFunction(TimeFunction f)
{
SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig();
SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig();
s->mTimeFunction = f;
}
void setDefaultLevel(ELevel level)
{
Globals::getInstance()->invalidateCallSites();
SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig();
Globals *g = Globals::getInstance();
g->invalidateCallSites();
SettingsConfigPtr s = g->getSettingsConfig();
s->mDefaultLevel = level;
}
ELevel getDefaultLevel()
{
SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig();
SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig();
return s->mDefaultLevel;
}
void setAlwaysFlush(bool flush)
{
SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig();
SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig();
s->mLogAlwaysFlush = flush;
}
bool getAlwaysFlush()
{
SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig();
SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig();
return s->mLogAlwaysFlush;
}
void setEnabledLogTypesMask(U32 mask)
{
SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig();
SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig();
s->mEnabledLogTypesMask = mask;
}
U32 getEnabledLogTypesMask()
{
SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig();
SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig();
return s->mEnabledLogTypesMask;
}
void setFunctionLevel(const std::string& function_name, ELevel level)
{
Globals::getInstance()->invalidateCallSites();
SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig();
Globals *g = Globals::getInstance();
g->invalidateCallSites();
SettingsConfigPtr s = g->getSettingsConfig();
s->mFunctionLevelMap[function_name] = level;
}
void setClassLevel(const std::string& class_name, ELevel level)
{
Globals::getInstance()->invalidateCallSites();
SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig();
Globals *g = Globals::getInstance();
g->invalidateCallSites();
SettingsConfigPtr s = g->getSettingsConfig();
s->mClassLevelMap[class_name] = level;
}
void setFileLevel(const std::string& file_name, ELevel level)
{
Globals::getInstance()->invalidateCallSites();
SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig();
Globals *g = Globals::getInstance();
g->invalidateCallSites();
SettingsConfigPtr s = g->getSettingsConfig();
s->mFileLevelMap[file_name] = level;
}
void setTagLevel(const std::string& tag_name, ELevel level)
{
Globals::getInstance()->invalidateCallSites();
SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig();
Globals *g = Globals::getInstance();
g->invalidateCallSites();
SettingsConfigPtr s = g->getSettingsConfig();
s->mTagLevelMap[tag_name] = level;
}
@ -936,8 +920,9 @@ namespace LLError
{
void configure(const LLSD& config)
{
Globals::getInstance()->invalidateCallSites();
SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig();
Globals *g = Globals::getInstance();
g->invalidateCallSites();
SettingsConfigPtr s = g->getSettingsConfig();
s->mFunctionLevelMap.clear();
s->mClassLevelMap.clear();
@ -1064,7 +1049,8 @@ namespace LLError
{
return;
}
SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig();
SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig();
LLMutexLock lock(&s->mRecorderMutex);
s->mRecorders.push_back(recorder);
}
@ -1074,7 +1060,8 @@ namespace LLError
{
return;
}
SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig();
SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig();
LLMutexLock lock(&s->mRecorderMutex);
s->mRecorders.erase(std::remove(s->mRecorders.begin(), s->mRecorders.end(), recorder),
s->mRecorders.end());
}
@ -1086,11 +1073,12 @@ namespace LLError
// with a Recorders::iterator indicating the position of that entry in
// mRecorders. The shared_ptr might be empty (operator!() returns true) if
// there was no such RECORDER subclass instance in mRecorders.
//
// NOTE!!! Requires external mutex lock!!!
template <typename RECORDER>
std::pair<boost::shared_ptr<RECORDER>, Recorders::iterator>
findRecorderPos()
findRecorderPos(SettingsConfigPtr &s)
{
SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig();
// Since we promise to return an iterator, use a classic iterator
// loop.
auto end{s->mRecorders.end()};
@ -1121,7 +1109,9 @@ namespace LLError
template <typename RECORDER>
boost::shared_ptr<RECORDER> findRecorder()
{
return findRecorderPos<RECORDER>().first;
SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig();
LLMutexLock lock(&s->mRecorderMutex);
return findRecorderPos<RECORDER>(s).first;
}
// Remove an entry from SettingsConfig::mRecorders whose RecorderPtr
@ -1130,10 +1120,11 @@ namespace LLError
template <typename RECORDER>
bool removeRecorder()
{
auto found = findRecorderPos<RECORDER>();
SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig();
LLMutexLock lock(&s->mRecorderMutex);
auto found = findRecorderPos<RECORDER>(s);
if (found.first)
{
SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig();
s->mRecorders.erase(found.second);
}
return bool(found.first);
@ -1231,10 +1222,11 @@ namespace
void writeToRecorders(const LLError::CallSite& site, const std::string& message)
{
LLError::ELevel level = site.mLevel;
LLError::SettingsConfigPtr s = LLError::Settings::getInstance()->getSettingsConfig();
SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig();
std::string escaped_message;
LLMutexLock lock(&s->mRecorderMutex);
for (Recorders::const_iterator i = s->mRecorders.begin();
i != s->mRecorders.end();
++i)
@ -1376,7 +1368,8 @@ namespace LLError
return false;
}
SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig();
Globals *g = Globals::getInstance();
SettingsConfigPtr s = g->getSettingsConfig();
s->mShouldLogCallCounter++;
@ -1406,7 +1399,7 @@ namespace LLError
: false);
site.mCached = true;
Globals::getInstance()->addCallSite(site);
g->addCallSite(site);
return site.mShouldLog = site.mLevel >= compareLevel;
}
@ -1420,7 +1413,7 @@ namespace LLError
}
Globals* g = Globals::getInstance();
SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig();
SettingsConfigPtr s = g->getSettingsConfig();
std::string message = out.str();
@ -1465,12 +1458,12 @@ namespace LLError
{
SettingsStoragePtr saveAndResetSettings()
{
return Settings::getInstance()->saveAndReset();
return Globals::getInstance()->saveAndResetSettingsConfig();
}
void restoreSettings(SettingsStoragePtr pSettingsStorage)
{
return Settings::getInstance()->restore(pSettingsStorage);
return Globals::getInstance()->restore(pSettingsStorage);
}
std::string removePrefix(std::string& s, const std::string& p)
@ -1516,7 +1509,7 @@ namespace LLError
int shouldLogCallCount()
{
SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig();
SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig();
return s->mShouldLogCallCounter;
}
@ -1628,8 +1621,8 @@ bool debugLoggingEnabled(const std::string& tag)
{
return false;
}
LLError::SettingsConfigPtr s = LLError::Settings::getInstance()->getSettingsConfig();
SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig();
LLError::ELevel level = LLError::LEVEL_DEBUG;
bool res = checkLevelMap(s->mTagLevelMap, tag, level);
return res;

View File

@ -45,7 +45,6 @@
#include <cctype>
// external library headers
#include <boost/range/iterator_range.hpp>
#include <boost/make_shared.hpp>
#if LL_WINDOWS
#pragma warning (push)
#pragma warning (disable : 4701) // compiler thinks might use uninitialized var, but no
@ -285,7 +284,7 @@ LLEventPump::LLEventPump(const std::string& name, bool tweak):
// Register every new instance with LLEventPumps
mRegistry(LLEventPumps::instance().getHandle()),
mName(mRegistry.get()->registerNew(*this, name, tweak)),
mSignal(boost::make_shared<LLStandardSignal>()),
mSignal(std::make_shared<LLStandardSignal>()),
mEnabled(true)
{}
@ -317,14 +316,24 @@ void LLEventPump::clear()
{
// Destroy the original LLStandardSignal instance, replacing it with a
// whole new one.
mSignal = boost::make_shared<LLStandardSignal>();
mSignal = std::make_shared<LLStandardSignal>();
mConnections.clear();
}
void LLEventPump::reset()
{
mSignal.reset();
// Resetting mSignal is supposed to disconnect everything on its own
// But due to crash on 'reset' added explicit cleanup to get more data
ConnectionMap::const_iterator iter = mConnections.begin();
ConnectionMap::const_iterator end = mConnections.end();
while (iter!=end)
{
iter->second.disconnect();
iter++;
}
mConnections.clear();
mSignal.reset();
//mDeps.clear();
}
@ -543,7 +552,7 @@ bool LLEventStream::post(const LLSD& event)
// *stack* instance of the shared_ptr, ensuring that our heap
// LLStandardSignal object will live at least until post() returns, even
// if 'this' gets destroyed during the call.
boost::shared_ptr<LLStandardSignal> signal(mSignal);
std::shared_ptr<LLStandardSignal> signal(mSignal);
// Let caller know if any one listener handled the event. This is mostly
// useful when using LLEventStream as a listener for an upstream
// LLEventPump.

View File

@ -49,8 +49,6 @@
#endif
#include <boost/bind.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/enable_shared_from_this.hpp>
#include <boost/utility.hpp> // noncopyable
#include <boost/optional/optional.hpp>
#include <boost/visit_each.hpp>
@ -571,7 +569,7 @@ protected:
const NameList& before);
/// implement the dispatching
boost::shared_ptr<LLStandardSignal> mSignal;
std::shared_ptr<LLStandardSignal> mSignal;
/// valve open?
bool mEnabled;
@ -745,14 +743,4 @@ private:
LL_COMMON_API bool sendReply(const LLSD& reply, const LLSD& request,
const std::string& replyKey="reply");
// Somewhat to my surprise, passing boost::bind(...boost::weak_ptr<T>...) to
// listen() fails in Boost code trying to instantiate LLEventListener (i.e.
// LLStandardSignal::slot_type) because the boost::get_pointer() utility function isn't
// specialized for boost::weak_ptr. This remedies that omission.
namespace boost
{
template <typename T>
T* get_pointer(const weak_ptr<T>& ptr) { return shared_ptr<T>(ptr).get(); }
}
#endif /* ! defined(LL_LLEVENTS_H) */

View File

@ -40,6 +40,12 @@
#define LL_BIG_ENDIAN 1
#endif
//<FS:ND> 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 <bits/pthread_stack_min.h>
#endif
// </FS:Nd>
// Per-compiler switches

89
indra/llcommon/llregex.h Normal file
View File

@ -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 <boost/regex.hpp>
template <typename S, typename M, typename R>
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 <typename S, typename R>
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 <typename S, typename M, typename R>
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 <typename S, typename R>
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

View File

@ -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 <boost/bind.hpp>
#include <boost/circular_buffer.hpp>
#include <boost/regex.hpp>
#include <boost/foreach.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/range.hpp>
@ -101,39 +101,6 @@ static const F32 MEM_INFO_THROTTLE = 20;
// dropped below the login framerate, we'd have very little additional data.
static const F32 MEM_INFO_WINDOW = 10*60;
// Wrap boost::regex_match() with a function that doesn't throw.
template <typename S, typename M, typename R>
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 <typename S, typename M, typename R>
static bool regex_search_no_exc(const S& string, M& match, const R& regex)
{
try
{
return boost::regex_search(string, match, regex);
}
catch (const std::runtime_error& e)
{
LL_WARNS("LLMemoryInfo") << "error searching with '" << regex.str() << "': "
<< e.what() << ":\n'" << string << "'" << LL_ENDL;
return false;
}
}
LLOSInfo::LLOSInfo() :
mMajorVer(0), mMinorVer(0), mBuild(0), mOSVersionString("")
{
@ -384,7 +351,7 @@ LLOSInfo::LLOSInfo() :
boost::smatch matched;
std::string glibc_version(gnu_get_libc_version());
if ( regex_match_no_exc(glibc_version, matched, os_version_parse) )
if ( ll_regex_match(glibc_version, matched, os_version_parse) )
{
LL_INFOS("AppInit") << "Using glibc version '" << glibc_version << "' as OS version" << LL_ENDL;
@ -1061,7 +1028,7 @@ LLSD LLMemoryInfo::loadStatsMap()
while (std::getline(meminfo, line))
{
LL_DEBUGS("LLMemoryInfo") << line << LL_ENDL;
if (regex_match_no_exc(line, matched, stat_rx))
if (ll_regex_match(line, matched, stat_rx))
{
// e.g. "MemTotal: 4108424 kB"
LLSD::String key(matched[1].first, matched[1].second);

View File

@ -580,6 +580,31 @@ namespace LLTrace
return typename RelatedTypes<T>::fractional_t(getPeriodMeanPerSec(static_cast<const StatType<CountAccumulator>&>(stat), num_periods));
}
template <typename T>
typename RelatedTypes<typename T::value_t>::fractional_t getPeriodMedianPerSec(const StatType<T>& stat, S32 num_periods = S32_MAX)
{
num_periods = llmin(num_periods, getNumRecordedPeriods());
std::vector <typename RelatedTypes<typename T::value_t>::fractional_t> buf;
for (S32 i = 1; i <= num_periods; i++)
{
Recording& recording = getPrevRecording(i);
if (recording.getDuration() > (F32Seconds)0.f)
{
buf.push_back(recording.getPerSec(stat));
}
}
std::sort(buf.begin(), buf.end());
return typename RelatedTypes<T>::fractional_t((buf.size() % 2 == 0) ? (buf[buf.size() / 2 - 1] + buf[buf.size() / 2]) / 2 : buf[buf.size() / 2]);
}
template<typename T>
typename RelatedTypes<T>::fractional_t getPeriodMedianPerSec(const CountStatHandle<T>& stat, S32 num_periods = S32_MAX)
{
return typename RelatedTypes<T>::fractional_t(getPeriodMedianPerSec(static_cast<const StatType<CountAccumulator>&>(stat), num_periods));
}
//
// PERIODIC STANDARD DEVIATION
//

View File

@ -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;
// <FS> 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;
// <FS> 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;

View File

@ -29,10 +29,11 @@
#include <iostream>
#include <set>
#include <vector>
#include <cstring> // <FS:Beq> for std::memmove
#include "stdtypes.h"
#include "llpreprocessor.h"
#include <boost/functional/hash.hpp>
#include "fstelemetry.h"
class LLMutex;
const S32 UUID_BYTES = 16;
@ -56,7 +57,9 @@ public:
explicit LLUUID(const char *in_string); // Convert from string.
explicit LLUUID(const std::string& in_string); // Convert from string.
LLUUID(const LLUUID &in);
LLUUID(LLUUID&& rhs) noexcept { FSZone; std::memmove(mData, rhs.mData, sizeof(mData));};
LLUUID &operator=(const LLUUID &rhs);
LLUUID &operator=(LLUUID &&rhs) noexcept {FSZone; std::memmove(mData, rhs.mData, sizeof(mData));return *this;};
~LLUUID();
@ -112,6 +115,61 @@ public:
void toString(std::string& out) const;
void toCompressedString(char *out) const; // Does not allocate memory, needs 17 characters (including \0)
void toCompressedString(std::string& out) const;
// last 4 chars for quick ref - Very lightweight, no nul-term added - provide your own, ensure min 4 bytes.
# define hexnybl(N) (N)>9?((N)-10)+'a':(N)+'0'
inline char * toShortString(char *out) const
{
FSZone;
out[0] = hexnybl(mData[14]>>4);
out[1] = hexnybl(mData[14]&15);
out[2] = hexnybl(mData[15]>>4);
out[3] = hexnybl(mData[15]&15);
return out;
}
// full uuid - Much lighterweight than default, no allocation, or nul-term added - provide your own, ensure min 36 bytes.
inline char * toStringFast(char *out) const
{
FSZone;
out[0] = hexnybl(mData[0]>>4);
out[1] = hexnybl(mData[0]&15);
out[2] = hexnybl(mData[1]>>4);
out[3] = hexnybl(mData[1]&15);
out[4] = hexnybl(mData[2]>>4);
out[5] = hexnybl(mData[2]&15);
out[6] = hexnybl(mData[3]>>4);
out[7] = hexnybl(mData[3]&15);
out[8] = '-';
out[9] = hexnybl(mData[4]>>4);
out[10] = hexnybl(mData[4]&15);
out[11] = hexnybl(mData[5]>>4);
out[12] = hexnybl(mData[5]&15);
out[13] = '-';
out[14] = hexnybl(mData[6]>>4);
out[15] = hexnybl(mData[6]&15);
out[16] = hexnybl(mData[7]>>4);
out[17] = hexnybl(mData[7]&15);
out[18] = '-';
out[19] = hexnybl(mData[8]>>4);
out[20] = hexnybl(mData[8]&15);
out[21] = hexnybl(mData[9]>>4);
out[22] = hexnybl(mData[9]&15);
out[23] = '-';
out[24] = hexnybl(mData[10]>>4);
out[25] = hexnybl(mData[10]&15);
out[26] = hexnybl(mData[11]>>4);
out[27] = hexnybl(mData[11]&15);
out[28] = hexnybl(mData[12]>>4);
out[29] = hexnybl(mData[12]&15);
out[30] = hexnybl(mData[13]>>4);
out[31] = hexnybl(mData[13]&15);
out[32] = hexnybl(mData[14]>>4);
out[33] = hexnybl(mData[14]&15);
out[34] = hexnybl(mData[15]>>4);
out[35] = hexnybl(mData[15]&15);
return out;
}
std::string asString() const;
std::string getString() const;

View File

@ -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
// <FS:Beq> - Add threadnames
LL_INFOS("THREAD") << "Started unnamed HTTP thread " << LL_ENDL;
FSThreadName( "HTTP" );
// </FS:Beq>
// Take out additional reference for the at_exit handler
addRef();

View File

@ -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);
}
}

View File

@ -343,6 +343,11 @@ const std::string &LLDir::getDumpDir() const
return LLDir::sDumpDir;
}
bool LLDir::dumpDirExists() const
{
return !sDumpDir.empty();
}
const std::string &LLDir::getPerAccountChatLogsDir() const
{
return mPerAccountChatLogsDir;
@ -953,6 +958,11 @@ std::string LLDir::getScrubbedFileName(const std::string uncleanFileName)
return name;
}
std::string LLDir::getDumpLogsDirPath(const std::string &file_name)
{
return gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "dump_logs", file_name);
}
// static
std::string LLDir::getForbiddenFileChars()
{

View File

@ -128,6 +128,7 @@ class LLDir
const std::string &getLindenUserDir() const; // Location of the Linden user dir.
const std::string &getChatLogsDir() const; // Location of the chat logs dir.
const std::string &getDumpDir() const; // Location of the per-run dump dir.
bool dumpDirExists() const;
const std::string &getPerAccountChatLogsDir() const; // Location of the per account chat logs dir.
const std::string &getTempDir() const; // Common temporary directory
const std::string getCacheDir(bool get_default = false) const; // Location of the cache.
@ -218,6 +219,8 @@ class LLDir
// random filename in common temporary directory
std::string getTempFilename() const;
static std::string getDumpLogsDirPath(const std::string &file_name = "");
// For producing safe download file names from potentially unsafe ones
static std::string getScrubbedFileName(const std::string uncleanFileName);
static std::string getForbiddenFileChars();

View File

@ -27,8 +27,8 @@
#include "lldiriterator.h"
#include "fix_macros.h"
#include "llregex.h"
#include <boost/filesystem.hpp>
#include <boost/regex.hpp>
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;

View File

@ -1498,7 +1498,7 @@ bool LLImageRaw::scale( S32 new_width, S32 new_height, bool scale_image_data )
setDataAndSize(new_data, new_width, new_height, components);
}
}
else
else try
{
// copy out existing image data
S32 temp_data_size = old_width * old_height * components;
@ -1532,6 +1532,11 @@ bool LLImageRaw::scale( S32 new_width, S32 new_height, bool scale_image_data )
}
}
}
catch (std::bad_alloc&) // for temp_buffer
{
LL_WARNS() << "Failed to allocate temporary image buffer" << LL_ENDL;
return false;
}
return true ;
}

View File

@ -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();

View File

@ -270,7 +270,7 @@ public:
public:
static const U32 VALIDATION_PARTIAL;
typedef boost::function<bool(LLSD &)> verify_pr;
typedef boost::function<bool(LLSD &, U32)> 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;

View File

@ -461,7 +461,7 @@ void LLSettingsDay::blend(const LLSettingsBase::ptr_t &other, F64 mix)
namespace
{
bool validateDayCycleTrack(LLSD &value)
bool validateDayCycleTrack(LLSD &value, U32 flags)
{
// Trim extra tracks.
while (value.size() > LLSettingsDay::TRACK_MAX)
@ -532,7 +532,7 @@ namespace
return true;
}
bool validateDayCycleFrames(LLSD &value)
bool validateDayCycleFrames(LLSD &value, U32 flags)
{
bool hasSky(false);
bool hasWater(false);
@ -545,7 +545,7 @@ namespace
if (ftype == "sky")
{
LLSettingsSky::validation_list_t valid_sky = LLSettingsSky::validationList();
LLSD res_sky = LLSettingsBase::settingValidation(frame, valid_sky);
LLSD res_sky = LLSettingsBase::settingValidation(frame, valid_sky, flags);
if (res_sky["success"].asInteger() == 0)
{
@ -558,7 +558,7 @@ namespace
else if (ftype == "water")
{
LLSettingsWater::validation_list_t valid_h2o = LLSettingsWater::validationList();
LLSD res_h2o = LLSettingsBase::settingValidation(frame, valid_h2o);
LLSD res_h2o = LLSettingsBase::settingValidation(frame, valid_h2o, flags);
if (res_h2o["success"].asInteger() == 0)
{
LL_WARNS("SETTINGS") << "Water setting named '" << (*itf).first << "' validation failed!: " << res_h2o << LL_ENDL;
@ -574,18 +574,20 @@ namespace
}
}
if (!hasSky)
if ((flags & LLSettingsBase::Validator::VALIDATION_PARTIAL) == 0)
{
LL_WARNS("SETTINGS") << "No skies defined." << LL_ENDL;
return false;
}
if (!hasSky)
{
LL_WARNS("SETTINGS") << "No skies defined." << LL_ENDL;
return false;
}
if (!hasWater)
{
LL_WARNS("SETTINGS") << "No waters defined." << LL_ENDL;
return false;
if (!hasWater)
{
LL_WARNS("SETTINGS") << "No waters defined." << LL_ENDL;
return false;
}
}
return true;
}
}

View File

@ -156,29 +156,29 @@ LLSettingsSky::validation_list_t legacyHazeValidationList()
if (legacyHazeValidation.empty())
{
legacyHazeValidation.push_back(LLSettingsBase::Validator(LLSettingsSky::SETTING_AMBIENT, false, LLSD::TypeArray,
boost::bind(&LLSettingsBase::Validator::verifyVectorMinMax, _1,
boost::bind(&LLSettingsBase::Validator::verifyVectorMinMax, _1, _2,
LLSD(LLSDArray(0.0f)(0.0f)(0.0f)("*")),
LLSD(LLSDArray(3.0f)(3.0f)(3.0f)("*")))));
legacyHazeValidation.push_back(LLSettingsBase::Validator(LLSettingsSky::SETTING_BLUE_DENSITY, false, LLSD::TypeArray,
boost::bind(&LLSettingsBase::Validator::verifyVectorMinMax, _1,
boost::bind(&LLSettingsBase::Validator::verifyVectorMinMax, _1, _2,
LLSD(LLSDArray(0.0f)(0.0f)(0.0f)("*")),
LLSD(LLSDArray(3.0f)(3.0f)(3.0f)("*")))));
legacyHazeValidation.push_back(LLSettingsBase::Validator(LLSettingsSky::SETTING_BLUE_HORIZON, false, LLSD::TypeArray,
boost::bind(&LLSettingsBase::Validator::verifyVectorMinMax, _1,
boost::bind(&LLSettingsBase::Validator::verifyVectorMinMax, _1, _2,
LLSD(LLSDArray(0.0f)(0.0f)(0.0f)("*")),
LLSD(LLSDArray(3.0f)(3.0f)(3.0f)("*")))));
legacyHazeValidation.push_back(LLSettingsBase::Validator(LLSettingsSky::SETTING_HAZE_DENSITY, false, LLSD::TypeReal,
boost::bind(&LLSettingsBase::Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.0f)(5.0f)))));
boost::bind(&LLSettingsBase::Validator::verifyFloatRange, _1, _2, LLSD(LLSDArray(0.0f)(5.0f)))));
legacyHazeValidation.push_back(LLSettingsBase::Validator(LLSettingsSky::SETTING_HAZE_HORIZON, false, LLSD::TypeReal,
boost::bind(&LLSettingsBase::Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.0f)(5.0f)))));
boost::bind(&LLSettingsBase::Validator::verifyFloatRange, _1, _2, LLSD(LLSDArray(0.0f)(5.0f)))));
// <FS:Beq> FIRE-29682 Allow full range density multipliers
// legacyHazeValidation.push_back(LLSettingsBase::Validator(LLSettingsSky::SETTING_DENSITY_MULTIPLIER, false, LLSD::TypeReal,
// boost::bind(&LLSettingsBase::Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.0001f)(2.0f)))));
// boost::bind(&LLSettingsBase::Validator::verifyFloatRange, _1, _2, LLSD(LLSDArray(0.0001f)(2.0f)))));
legacyHazeValidation.push_back(LLSettingsBase::Validator(LLSettingsSky::SETTING_DENSITY_MULTIPLIER, false, LLSD::TypeReal,
boost::bind(&LLSettingsBase::Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.0000001f)(2.0f)))));
boost::bind(&LLSettingsBase::Validator::verifyFloatRange, _1, _2, LLSD(LLSDArray(0.0000001f)(2.0f)))));
// </FS:Beq>
legacyHazeValidation.push_back(LLSettingsBase::Validator(LLSettingsSky::SETTING_DISTANCE_MULTIPLIER, false, LLSD::TypeReal,
boost::bind(&LLSettingsBase::Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.0001f)(1000.0f)))));
boost::bind(&LLSettingsBase::Validator::verifyFloatRange, _1, _2, LLSD(LLSDArray(0.0001f)(1000.0f)))));
}
return legacyHazeValidation;
}
@ -189,19 +189,19 @@ LLSettingsSky::validation_list_t rayleighValidationList()
if (rayleighValidation.empty())
{
rayleighValidation.push_back(LLSettingsBase::Validator(LLSettingsSky::SETTING_DENSITY_PROFILE_WIDTH, false, LLSD::TypeReal,
boost::bind(&LLSettingsBase::Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.0f)(32768.0f)))));
boost::bind(&LLSettingsBase::Validator::verifyFloatRange, _1, _2, LLSD(LLSDArray(0.0f)(32768.0f)))));
rayleighValidation.push_back(LLSettingsBase::Validator(LLSettingsSky::SETTING_DENSITY_PROFILE_EXP_TERM, false, LLSD::TypeReal,
boost::bind(&LLSettingsBase::Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.0f)(2.0f)))));
boost::bind(&LLSettingsBase::Validator::verifyFloatRange, _1, _2, LLSD(LLSDArray(0.0f)(2.0f)))));
rayleighValidation.push_back(LLSettingsBase::Validator(LLSettingsSky::SETTING_DENSITY_PROFILE_EXP_SCALE_FACTOR, false, LLSD::TypeReal,
boost::bind(&LLSettingsBase::Validator::verifyFloatRange, _1, LLSD(LLSDArray(-1.0f)(1.0f)))));
boost::bind(&LLSettingsBase::Validator::verifyFloatRange, _1, _2, LLSD(LLSDArray(-1.0f)(1.0f)))));
rayleighValidation.push_back(LLSettingsBase::Validator(LLSettingsSky::SETTING_DENSITY_PROFILE_LINEAR_TERM, false, LLSD::TypeReal,
boost::bind(&LLSettingsBase::Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.0f)(2.0f)))));
boost::bind(&LLSettingsBase::Validator::verifyFloatRange, _1, _2, LLSD(LLSDArray(0.0f)(2.0f)))));
rayleighValidation.push_back(LLSettingsBase::Validator(LLSettingsSky::SETTING_DENSITY_PROFILE_CONSTANT_TERM, false, LLSD::TypeReal,
boost::bind(&LLSettingsBase::Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.0f)(1.0f)))));
boost::bind(&LLSettingsBase::Validator::verifyFloatRange, _1, _2, LLSD(LLSDArray(0.0f)(1.0f)))));
}
return rayleighValidation;
}
@ -212,19 +212,19 @@ LLSettingsSky::validation_list_t absorptionValidationList()
if (absorptionValidation.empty())
{
absorptionValidation.push_back(LLSettingsBase::Validator(LLSettingsSky::SETTING_DENSITY_PROFILE_WIDTH, false, LLSD::TypeReal,
boost::bind(&LLSettingsBase::Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.0f)(32768.0f)))));
boost::bind(&LLSettingsBase::Validator::verifyFloatRange, _1, _2, LLSD(LLSDArray(0.0f)(32768.0f)))));
absorptionValidation.push_back(LLSettingsBase::Validator(LLSettingsSky::SETTING_DENSITY_PROFILE_EXP_TERM, false, LLSD::TypeReal,
boost::bind(&LLSettingsBase::Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.0f)(2.0f)))));
boost::bind(&LLSettingsBase::Validator::verifyFloatRange, _1, _2, LLSD(LLSDArray(0.0f)(2.0f)))));
absorptionValidation.push_back(LLSettingsBase::Validator(LLSettingsSky::SETTING_DENSITY_PROFILE_EXP_SCALE_FACTOR, false, LLSD::TypeReal,
boost::bind(&LLSettingsBase::Validator::verifyFloatRange, _1, LLSD(LLSDArray(-1.0f)(1.0f)))));
boost::bind(&LLSettingsBase::Validator::verifyFloatRange, _1, _2, LLSD(LLSDArray(-1.0f)(1.0f)))));
absorptionValidation.push_back(LLSettingsBase::Validator(LLSettingsSky::SETTING_DENSITY_PROFILE_LINEAR_TERM, false, LLSD::TypeReal,
boost::bind(&LLSettingsBase::Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.0f)(2.0f)))));
boost::bind(&LLSettingsBase::Validator::verifyFloatRange, _1, _2, LLSD(LLSDArray(0.0f)(2.0f)))));
absorptionValidation.push_back(LLSettingsBase::Validator(LLSettingsSky::SETTING_DENSITY_PROFILE_CONSTANT_TERM, false, LLSD::TypeReal,
boost::bind(&LLSettingsBase::Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.0f)(1.0f)))));
boost::bind(&LLSettingsBase::Validator::verifyFloatRange, _1, _2, LLSD(LLSDArray(0.0f)(1.0f)))));
}
return absorptionValidation;
}
@ -235,31 +235,31 @@ LLSettingsSky::validation_list_t mieValidationList()
if (mieValidation.empty())
{
mieValidation.push_back(LLSettingsBase::Validator(LLSettingsSky::SETTING_DENSITY_PROFILE_WIDTH, false, LLSD::TypeReal,
boost::bind(&LLSettingsBase::Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.0f)(32768.0f)))));
boost::bind(&LLSettingsBase::Validator::verifyFloatRange, _1, _2, LLSD(LLSDArray(0.0f)(32768.0f)))));
mieValidation.push_back(LLSettingsBase::Validator(LLSettingsSky::SETTING_DENSITY_PROFILE_EXP_TERM, false, LLSD::TypeReal,
boost::bind(&LLSettingsBase::Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.0f)(2.0f)))));
boost::bind(&LLSettingsBase::Validator::verifyFloatRange, _1, _2, LLSD(LLSDArray(0.0f)(2.0f)))));
mieValidation.push_back(LLSettingsBase::Validator(LLSettingsSky::SETTING_DENSITY_PROFILE_EXP_SCALE_FACTOR, false, LLSD::TypeReal,
boost::bind(&LLSettingsBase::Validator::verifyFloatRange, _1, LLSD(LLSDArray(-1.0f)(1.0f)))));
boost::bind(&LLSettingsBase::Validator::verifyFloatRange, _1, _2, LLSD(LLSDArray(-1.0f)(1.0f)))));
mieValidation.push_back(LLSettingsBase::Validator(LLSettingsSky::SETTING_DENSITY_PROFILE_LINEAR_TERM, false, LLSD::TypeReal,
boost::bind(&LLSettingsBase::Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.0f)(2.0f)))));
boost::bind(&LLSettingsBase::Validator::verifyFloatRange, _1, _2, LLSD(LLSDArray(0.0f)(2.0f)))));
mieValidation.push_back(LLSettingsBase::Validator(LLSettingsSky::SETTING_DENSITY_PROFILE_CONSTANT_TERM, false, LLSD::TypeReal,
boost::bind(&LLSettingsBase::Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.0f)(1.0f)))));
boost::bind(&LLSettingsBase::Validator::verifyFloatRange, _1, _2, LLSD(LLSDArray(0.0f)(1.0f)))));
mieValidation.push_back(LLSettingsBase::Validator(LLSettingsSky::SETTING_MIE_ANISOTROPY_FACTOR, false, LLSD::TypeReal,
boost::bind(&LLSettingsBase::Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.0f)(1.0f)))));
boost::bind(&LLSettingsBase::Validator::verifyFloatRange, _1, _2, LLSD(LLSDArray(0.0f)(1.0f)))));
}
return mieValidation;
}
bool validateLegacyHaze(LLSD &value)
bool validateLegacyHaze(LLSD &value, U32 flags)
{
LLSettingsSky::validation_list_t legacyHazeValidations = legacyHazeValidationList();
llassert(value.type() == LLSD::TypeMap);
LLSD result = LLSettingsBase::settingValidation(value, legacyHazeValidations);
LLSD result = LLSettingsBase::settingValidation(value, legacyHazeValidations, flags);
if (result["errors"].size() > 0)
{
LL_WARNS("SETTINGS") << "Legacy Haze Config Validation errors: " << result["errors"] << LL_ENDL;
@ -273,7 +273,7 @@ bool validateLegacyHaze(LLSD &value)
return true;
}
bool validateRayleighLayers(LLSD &value)
bool validateRayleighLayers(LLSD &value, U32 flags)
{
LLSettingsSky::validation_list_t rayleighValidations = rayleighValidationList();
if (value.isArray())
@ -284,24 +284,24 @@ bool validateRayleighLayers(LLSD &value)
LLSD& layerConfig = (*itf);
if (layerConfig.type() == LLSD::TypeMap)
{
if (!validateRayleighLayers(layerConfig))
if (!validateRayleighLayers(layerConfig, flags))
{
allGood = false;
}
}
else if (layerConfig.type() == LLSD::TypeArray)
{
return validateRayleighLayers(layerConfig);
return validateRayleighLayers(layerConfig, flags);
}
else
{
return LLSettingsBase::settingValidation(value, rayleighValidations);
return LLSettingsBase::settingValidation(value, rayleighValidations, flags);
}
}
return allGood;
}
llassert(value.type() == LLSD::TypeMap);
LLSD result = LLSettingsBase::settingValidation(value, rayleighValidations);
LLSD result = LLSettingsBase::settingValidation(value, rayleighValidations, flags);
if (result["errors"].size() > 0)
{
LL_WARNS("SETTINGS") << "Rayleigh Config Validation errors: " << result["errors"] << LL_ENDL;
@ -315,7 +315,7 @@ bool validateRayleighLayers(LLSD &value)
return true;
}
bool validateAbsorptionLayers(LLSD &value)
bool validateAbsorptionLayers(LLSD &value, U32 flags)
{
LLSettingsBase::validation_list_t absorptionValidations = absorptionValidationList();
if (value.isArray())
@ -326,24 +326,24 @@ bool validateAbsorptionLayers(LLSD &value)
LLSD& layerConfig = (*itf);
if (layerConfig.type() == LLSD::TypeMap)
{
if (!validateAbsorptionLayers(layerConfig))
if (!validateAbsorptionLayers(layerConfig, flags))
{
allGood = false;
}
}
else if (layerConfig.type() == LLSD::TypeArray)
{
return validateAbsorptionLayers(layerConfig);
return validateAbsorptionLayers(layerConfig, flags);
}
else
{
return LLSettingsBase::settingValidation(value, absorptionValidations);
return LLSettingsBase::settingValidation(value, absorptionValidations, flags);
}
}
return allGood;
}
llassert(value.type() == LLSD::TypeMap);
LLSD result = LLSettingsBase::settingValidation(value, absorptionValidations);
LLSD result = LLSettingsBase::settingValidation(value, absorptionValidations, flags);
if (result["errors"].size() > 0)
{
LL_WARNS("SETTINGS") << "Absorption Config Validation errors: " << result["errors"] << LL_ENDL;
@ -357,7 +357,7 @@ bool validateAbsorptionLayers(LLSD &value)
return true;
}
bool validateMieLayers(LLSD &value)
bool validateMieLayers(LLSD &value, U32 flags)
{
LLSettingsBase::validation_list_t mieValidations = mieValidationList();
if (value.isArray())
@ -368,23 +368,23 @@ bool validateMieLayers(LLSD &value)
LLSD& layerConfig = (*itf);
if (layerConfig.type() == LLSD::TypeMap)
{
if (!validateMieLayers(layerConfig))
if (!validateMieLayers(layerConfig, flags))
{
allGood = false;
}
}
else if (layerConfig.type() == LLSD::TypeArray)
{
return validateMieLayers(layerConfig);
return validateMieLayers(layerConfig, flags);
}
else
{
return LLSettingsBase::settingValidation(value, mieValidations);
return LLSettingsBase::settingValidation(value, mieValidations, flags);
}
}
return allGood;
}
LLSD result = LLSettingsBase::settingValidation(value, mieValidations);
LLSD result = LLSettingsBase::settingValidation(value, mieValidations, flags);
if (result["errors"].size() > 0)
{
LL_WARNS("SETTINGS") << "Mie Config Validation errors: " << result["errors"] << LL_ENDL;
@ -563,80 +563,80 @@ LLSettingsSky::validation_list_t LLSettingsSky::validationList()
validation.push_back(Validator(SETTING_HALO_TEXTUREID, false, LLSD::TypeUUID));
validation.push_back(Validator(SETTING_CLOUD_COLOR, true, LLSD::TypeArray,
boost::bind(&Validator::verifyVectorMinMax, _1,
boost::bind(&Validator::verifyVectorMinMax, _1, _2,
LLSD(LLSDArray(0.0f)(0.0f)(0.0f)("*")),
LLSD(LLSDArray(1.0f)(1.0f)(1.0f)("*")))));
validation.push_back(Validator(SETTING_CLOUD_POS_DENSITY1, true, LLSD::TypeArray,
boost::bind(&Validator::verifyVectorMinMax, _1,
boost::bind(&Validator::verifyVectorMinMax, _1, _2,
LLSD(LLSDArray(0.0f)(0.0f)(0.0f)("*")),
LLSD(LLSDArray(1.0f)(1.0f)(3.0f)("*")))));
validation.push_back(Validator(SETTING_CLOUD_POS_DENSITY2, true, LLSD::TypeArray,
boost::bind(&Validator::verifyVectorMinMax, _1,
boost::bind(&Validator::verifyVectorMinMax, _1, _2,
LLSD(LLSDArray(0.0f)(0.0f)(0.0f)("*")),
LLSD(LLSDArray(1.0f)(1.0f)(1.0f)("*")))));
validation.push_back(Validator(SETTING_CLOUD_SCALE, true, LLSD::TypeReal,
boost::bind(&Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.001f)(3.0f)))));
boost::bind(&Validator::verifyFloatRange, _1, _2, LLSD(LLSDArray(0.001f)(3.0f)))));
validation.push_back(Validator(SETTING_CLOUD_SCROLL_RATE, true, LLSD::TypeArray,
boost::bind(&Validator::verifyVectorMinMax, _1,
boost::bind(&Validator::verifyVectorMinMax, _1, _2,
LLSD(LLSDArray(-50.0f)(-50.0f)),
LLSD(LLSDArray(50.0f)(50.0f)))));
validation.push_back(Validator(SETTING_CLOUD_SHADOW, true, LLSD::TypeReal,
boost::bind(&Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.0f)(1.0f)))));
boost::bind(&Validator::verifyFloatRange, _1, _2, LLSD(LLSDArray(0.0f)(1.0f)))));
validation.push_back(Validator(SETTING_CLOUD_TEXTUREID, false, LLSD::TypeUUID));
validation.push_back(Validator(SETTING_CLOUD_VARIANCE, false, LLSD::TypeReal,
boost::bind(&Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.0f)(1.0f)))));
boost::bind(&Validator::verifyFloatRange, _1, _2, LLSD(LLSDArray(0.0f)(1.0f)))));
validation.push_back(Validator(SETTING_DOME_OFFSET, false, LLSD::TypeReal,
boost::bind(&Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.0f)(1.0f)))));
boost::bind(&Validator::verifyFloatRange, _1, _2, LLSD(LLSDArray(0.0f)(1.0f)))));
validation.push_back(Validator(SETTING_DOME_RADIUS, false, LLSD::TypeReal,
boost::bind(&Validator::verifyFloatRange, _1, LLSD(LLSDArray(1000.0f)(2000.0f)))));
boost::bind(&Validator::verifyFloatRange, _1, _2, LLSD(LLSDArray(1000.0f)(2000.0f)))));
validation.push_back(Validator(SETTING_GAMMA, true, LLSD::TypeReal,
boost::bind(&Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.0f)(20.0f)))));
boost::bind(&Validator::verifyFloatRange, _1, _2, LLSD(LLSDArray(0.0f)(20.0f)))));
validation.push_back(Validator(SETTING_GLOW, true, LLSD::TypeArray,
boost::bind(&Validator::verifyVectorMinMax, _1,
boost::bind(&Validator::verifyVectorMinMax, _1, _2,
LLSD(LLSDArray(0.2f)("*")(-10.0f)("*")),
LLSD(LLSDArray(40.0f)("*")(10.0f)("*")))));
validation.push_back(Validator(SETTING_MAX_Y, true, LLSD::TypeReal,
boost::bind(&Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.0f)(10000.0f)))));
boost::bind(&Validator::verifyFloatRange, _1, _2, LLSD(LLSDArray(0.0f)(10000.0f)))));
validation.push_back(Validator(SETTING_MOON_ROTATION, true, LLSD::TypeArray, &Validator::verifyQuaternionNormal));
validation.push_back(Validator(SETTING_MOON_SCALE, false, LLSD::TypeReal,
boost::bind(&Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.25f)(20.0f))), LLSD::Real(1.0)));
boost::bind(&Validator::verifyFloatRange, _1, _2, LLSD(LLSDArray(0.25f)(20.0f))), LLSD::Real(1.0)));
validation.push_back(Validator(SETTING_MOON_TEXTUREID, false, LLSD::TypeUUID));
validation.push_back(Validator(SETTING_MOON_BRIGHTNESS, false, LLSD::TypeReal,
boost::bind(&Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.0f)(1.0f)))));
boost::bind(&Validator::verifyFloatRange, _1, _2, LLSD(LLSDArray(0.0f)(1.0f)))));
validation.push_back(Validator(SETTING_STAR_BRIGHTNESS, true, LLSD::TypeReal,
boost::bind(&Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.0f)(500.0f)))));
boost::bind(&Validator::verifyFloatRange, _1, _2, LLSD(LLSDArray(0.0f)(500.0f)))));
validation.push_back(Validator(SETTING_SUNLIGHT_COLOR, true, LLSD::TypeArray,
boost::bind(&Validator::verifyVectorMinMax, _1,
boost::bind(&Validator::verifyVectorMinMax, _1, _2,
LLSD(LLSDArray(0.0f)(0.0f)(0.0f)("*")),
LLSD(LLSDArray(3.0f)(3.0f)(3.0f)("*")))));
validation.push_back(Validator(SETTING_SUN_ROTATION, true, LLSD::TypeArray, &Validator::verifyQuaternionNormal));
validation.push_back(Validator(SETTING_SUN_SCALE, false, LLSD::TypeReal,
boost::bind(&Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.25f)(20.0f))), LLSD::Real(1.0)));
boost::bind(&Validator::verifyFloatRange, _1, _2, LLSD(LLSDArray(0.25f)(20.0f))), LLSD::Real(1.0)));
validation.push_back(Validator(SETTING_SUN_TEXTUREID, false, LLSD::TypeUUID));
validation.push_back(Validator(SETTING_PLANET_RADIUS, true, LLSD::TypeReal,
boost::bind(&Validator::verifyFloatRange, _1, LLSD(LLSDArray(1000.0f)(32768.0f)))));
boost::bind(&Validator::verifyFloatRange, _1, _2, LLSD(LLSDArray(1000.0f)(32768.0f)))));
validation.push_back(Validator(SETTING_SKY_BOTTOM_RADIUS, true, LLSD::TypeReal,
boost::bind(&Validator::verifyFloatRange, _1, LLSD(LLSDArray(1000.0f)(32768.0f)))));
boost::bind(&Validator::verifyFloatRange, _1, _2, LLSD(LLSDArray(1000.0f)(32768.0f)))));
validation.push_back(Validator(SETTING_SKY_TOP_RADIUS, true, LLSD::TypeReal,
boost::bind(&Validator::verifyFloatRange, _1, LLSD(LLSDArray(1000.0f)(32768.0f)))));
boost::bind(&Validator::verifyFloatRange, _1, _2, LLSD(LLSDArray(1000.0f)(32768.0f)))));
validation.push_back(Validator(SETTING_SUN_ARC_RADIANS, true, LLSD::TypeReal,
boost::bind(&Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.0f)(0.1f)))));
boost::bind(&Validator::verifyFloatRange, _1, _2, LLSD(LLSDArray(0.0f)(0.1f)))));
validation.push_back(Validator(SETTING_SKY_MOISTURE_LEVEL, false, LLSD::TypeReal,
boost::bind(&Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.0f)(1.0f)))));
boost::bind(&Validator::verifyFloatRange, _1, _2, LLSD(LLSDArray(0.0f)(1.0f)))));
validation.push_back(Validator(SETTING_SKY_DROPLET_RADIUS, false, LLSD::TypeReal,
boost::bind(&Validator::verifyFloatRange, _1, LLSD(LLSDArray(5.0f)(1000.0f)))));
boost::bind(&Validator::verifyFloatRange, _1, _2, LLSD(LLSDArray(5.0f)(1000.0f)))));
validation.push_back(Validator(SETTING_SKY_ICE_LEVEL, false, LLSD::TypeReal,
boost::bind(&Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.0f)(1.0f)))));
boost::bind(&Validator::verifyFloatRange, _1, _2, LLSD(LLSDArray(0.0f)(1.0f)))));
validation.push_back(Validator(SETTING_RAYLEIGH_CONFIG, true, LLSD::TypeArray, &validateRayleighLayers));
validation.push_back(Validator(SETTING_ABSORPTION_CONFIG, true, LLSD::TypeArray, &validateAbsorptionLayers));

View File

@ -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)))));
}

View File

@ -172,6 +172,71 @@ BOOL LLDataPacker::unpackFixed(F32 &value, const char *name,
return success;
}
BOOL LLDataPacker::unpackU16s(U16 *values, S32 count, const char *name)
{
for (S32 idx = 0; idx < count; ++idx)
{
if (!unpackU16(values[idx], name))
{
LL_WARNS("DATAPACKER") << "Buffer overflow reading Unsigned 16s \"" << name << "\" at index " << idx << "!" << LL_ENDL;
return FALSE;
}
}
return TRUE;
}
BOOL LLDataPacker::unpackS16s(S16 *values, S32 count, const char *name)
{
for (S32 idx = 0; idx < count; ++idx)
{
if (!unpackS16(values[idx], name))
{
LL_WARNS("DATAPACKER") << "Buffer overflow reading Signed 16s \"" << name << "\" at index " << idx << "!" << LL_ENDL;
return FALSE;
}
}
return TRUE;
}
BOOL LLDataPacker::unpackF32s(F32 *values, S32 count, const char *name)
{
for (S32 idx = 0; idx < count; ++idx)
{
if (!unpackF32(values[idx], name))
{
LL_WARNS("DATAPACKER") << "Buffer overflow reading Float 32s \"" << name << "\" at index " << idx << "!" << LL_ENDL;
return FALSE;
}
}
return TRUE;
}
BOOL LLDataPacker::unpackColor4Us(LLColor4U *values, S32 count, const char *name)
{
for (S32 idx = 0; idx < count; ++idx)
{
if (!unpackColor4U(values[idx], name))
{
LL_WARNS("DATAPACKER") << "Buffer overflow reading Float 32s \"" << name << "\" at index " << idx << "!" << LL_ENDL;
return FALSE;
}
}
return TRUE;
}
BOOL LLDataPacker::unpackUUIDs(LLUUID *values, S32 count, const char *name)
{
for (S32 idx = 0; idx < count; ++idx)
{
if (!unpackUUID(values[idx], name))
{
LL_WARNS("DATAPACKER") << "Buffer overflow reading UUIDs \"" << name << "\" at index " << idx << "!" << LL_ENDL;
return FALSE;
}
}
return TRUE;
}
//---------------------------------------------------------------------------
// LLDataPackerBinaryBuffer implementation
//---------------------------------------------------------------------------
@ -339,6 +404,29 @@ BOOL LLDataPackerBinaryBuffer::unpackU16(U16 &value, const char *name)
return TRUE;
}
BOOL LLDataPackerBinaryBuffer::packS16(const S16 value, const char *name)
{
BOOL success = verifyLength(sizeof(S16), name);
if (mWriteEnabled && success)
{
htolememcpy(mCurBufferp, &value, MVT_S16, 2);
}
mCurBufferp += 2;
return success;
}
BOOL LLDataPackerBinaryBuffer::unpackS16(S16 &value, const char *name)
{
BOOL success = verifyLength(sizeof(S16), name);
if (success)
{
htolememcpy(&value, mCurBufferp, MVT_S16, 2);
}
mCurBufferp += 2;
return success;
}
BOOL LLDataPackerBinaryBuffer::packU32(const U32 value, const char *name)
{
@ -939,6 +1027,52 @@ BOOL LLDataPackerAsciiBuffer::unpackU16(U16 &value, const char *name)
return success;
}
BOOL LLDataPackerAsciiBuffer::packS16(const S16 value, const char *name)
{
BOOL success = TRUE;
writeIndentedName(name);
int numCopied = 0;
if (mWriteEnabled)
{
numCopied = snprintf(mCurBufferp, getBufferSize() - getCurrentSize(), "%d\n", value); /* Flawfinder: ignore */
}
else
{
numCopied = snprintf(DUMMY_BUFFER, sizeof(DUMMY_BUFFER), "%d\n", value); /* Flawfinder: ignore */
}
// snprintf returns number of bytes that would have been written
// had the output not being truncated. In that case, it will
// return either -1 or value >= passed in size value . So a check needs to be added
// to detect truncation, and if there is any, only account for the
// actual number of bytes written..and not what could have been
// written.
if(numCopied < 0 || numCopied > getBufferSize() - getCurrentSize())
{
numCopied = getBufferSize() - getCurrentSize();
LL_WARNS() << "LLDataPackerAsciiBuffer::packS16: val truncated: " << LL_ENDL;
}
mCurBufferp += numCopied;
return success;
}
BOOL LLDataPackerAsciiBuffer::unpackS16(S16 &value, const char *name)
{
BOOL success = TRUE;
char valuestr[DP_BUFSIZE]; /* Flawfinder: ignore */
if (!getValueStr(name, valuestr, DP_BUFSIZE))
{
return FALSE;
}
S32 in_val;
sscanf(valuestr, "%d", &in_val);
value = in_val;
return success;
}
BOOL LLDataPackerAsciiBuffer::packU32(const U32 value, const char *name)
{
@ -1642,6 +1776,36 @@ BOOL LLDataPackerAsciiFile::unpackU16(U16 &value, const char *name)
return success;
}
BOOL LLDataPackerAsciiFile::packS16(const S16 value, const char *name)
{
BOOL success = TRUE;
writeIndentedName(name);
if (mFP)
{
fprintf(mFP, "%d\n", value);
}
else if (mOutputStream)
{
*mOutputStream << "" << value << "\n";
}
return success;
}
BOOL LLDataPackerAsciiFile::unpackS16(S16 &value, const char *name)
{
BOOL success = TRUE;
char valuestr[DP_BUFSIZE]; /*Flawfinder: ignore */
if (!getValueStr(name, valuestr, DP_BUFSIZE))
{
return FALSE;
}
S32 in_val;
sscanf(valuestr, "%d", &in_val);
value = in_val;
return success;
}
BOOL LLDataPackerAsciiFile::packU32(const U32 value, const char *name)
{

View File

@ -62,6 +62,11 @@ public:
virtual BOOL packU16(const U16 value, const char *name) = 0;
virtual BOOL unpackU16(U16 &value, const char *name) = 0;
BOOL unpackU16s(U16 *value, S32 count, const char *name);
virtual BOOL packS16(const S16 value, const char *name) = 0;
virtual BOOL unpackS16(S16 &value, const char *name) = 0;
BOOL unpackS16s(S16 *value, S32 count, const char *name);
virtual BOOL packU32(const U32 value, const char *name) = 0;
virtual BOOL unpackU32(U32 &value, const char *name) = 0;
@ -71,6 +76,7 @@ public:
virtual BOOL packF32(const F32 value, const char *name) = 0;
virtual BOOL unpackF32(F32 &value, const char *name) = 0;
BOOL unpackF32s(F32 *values, S32 count, const char *name);
// Packs a float into an integer, using the given size
// and picks the right U* data type to pack into.
@ -84,6 +90,7 @@ public:
virtual BOOL packColor4U(const LLColor4U &value, const char *name) = 0;
virtual BOOL unpackColor4U(LLColor4U &value, const char *name) = 0;
BOOL unpackColor4Us(LLColor4U *values, S32 count, const char *name);
virtual BOOL packVector2(const LLVector2 &value, const char *name) = 0;
virtual BOOL unpackVector2(LLVector2 &value, const char *name) = 0;
@ -96,6 +103,7 @@ public:
virtual BOOL packUUID(const LLUUID &value, const char *name) = 0;
virtual BOOL unpackUUID(LLUUID &value, const char *name) = 0;
BOOL unpackUUIDs(LLUUID *values, S32 count, const char *name);
U32 getPassFlags() const { return mPassFlags; }
void setPassFlags(U32 flags) { mPassFlags = flags; }
protected:
@ -141,6 +149,9 @@ public:
/*virtual*/ BOOL packU16(const U16 value, const char *name);
/*virtual*/ BOOL unpackU16(U16 &value, const char *name);
/*virtual*/ BOOL packS16(const S16 value, const char *name);
/*virtual*/ BOOL unpackS16(S16 &value, const char *name);
/*virtual*/ BOOL packU32(const U32 value, const char *name);
/*virtual*/ BOOL unpackU32(U32 &value, const char *name);
@ -258,6 +269,9 @@ public:
/*virtual*/ BOOL packU16(const U16 value, const char *name);
/*virtual*/ BOOL unpackU16(U16 &value, const char *name);
/*virtual*/ BOOL packS16(const S16 value, const char *name);
/*virtual*/ BOOL unpackS16(S16 &value, const char *name);
/*virtual*/ BOOL packU32(const U32 value, const char *name);
/*virtual*/ BOOL unpackU32(U32 &value, const char *name);
@ -386,6 +400,9 @@ public:
/*virtual*/ BOOL packU16(const U16 value, const char *name);
/*virtual*/ BOOL unpackU16(U16 &value, const char *name);
/*virtual*/ BOOL packS16(const S16 value, const char *name);
/*virtual*/ BOOL unpackS16(S16 &value, const char *name);
/*virtual*/ BOOL packU32(const U32 value, const char *name);
/*virtual*/ BOOL unpackU32(U32 &value, const char *name);

View File

@ -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");

View File

@ -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;

View File

@ -285,11 +285,6 @@ const LLUUID SND_STONE_DIRT_04 ("c8091652-e04b-4a11-84ba-15dba06e7a1b");
const LLUUID SND_STONE_STONE_02 ("ba4ef5ac-7435-4240-b826-c24ba8fa5a78");
const LLUUID SND_STONE_STONE_04 ("ea296329-0f09-4993-af1b-e6784bab1dc9");
// NaCl - Antispam Registry. The following sounds will be ignored for purposes of spam protection. They have been gathered from wiki documentation of frequent official sounds.
const std::string COLLISION_SOUNDS[] ={"dce5fdd4-afe4-4ea1-822f-dd52cac46b08","51011582-fbca-4580-ae9e-1a5593f094ec","68d62208-e257-4d0c-bbe2-20c9ea9760bb","75872e8c-bc39-451b-9b0b-042d7ba36cba","6a45ba0b-5775-4ea8-8513-26008a17f873","992a6d1b-8c77-40e0-9495-4098ce539694","2de4da5a-faf8-46be-bac6-c4d74f1e5767","6e3fb0f7-6d9c-42ca-b86b-1122ff562d7d","14209133-4961-4acc-9649-53fc38ee1667","bc4a4348-cfcc-4e5e-908e-8a52a8915fe6","9e5c1297-6eed-40c0-825a-d9bcd86e3193","e534761c-1894-4b61-b20c-658a6fb68157","8761f73f-6cf9-4186-8aaa-0948ed002db1","874a26fd-142f-4173-8c5b-890cd846c74d","0e24a717-b97e-4b77-9c94-b59a5a88b2da","75cf3ade-9a5b-4c4d-bb35-f9799bda7fb2","153c8bf7-fb89-4d89-b263-47e58b1b4774","55c3e0ce-275a-46fa-82ff-e0465f5e8703","24babf58-7156-4841-9a3f-761bdbb8e237","aca261d8-e145-4610-9e20-9eff990f2c12","0642fba6-5dcf-4d62-8e7b-94dbb529d117","25a863e8-dc42-4e8a-a357-e76422ace9b5","9538f37c-456e-4047-81be-6435045608d4","8c0f84c3-9afd-4396-b5f5-9bca2c911c20","be582e5d-b123-41a2-a150-454c39e961c8","c70141d4-ba06-41ea-bcbc-35ea81cb8335","7d1826f4-24c4-4aac-8c2e-eff45df37783","063c97d3-033a-4e9b-98d8-05c8074922cb","00000000-0000-0000-0000-000000000120"};
const int COLLISION_SOUNDS_SIZE=29;
// NaCl End
// extra guids

View File

@ -286,9 +286,4 @@ extern const LLUUID SND_STONE_DIRT_04;
extern const LLUUID SND_STONE_STONE_02;
extern const LLUUID SND_STONE_STONE_04;
// NaCl - Antispam Registry
extern const std::string COLLISION_SOUNDS[];
extern const int COLLISION_SOUNDS_SIZE;
// NaCl End
#endif

View File

@ -696,6 +696,66 @@ bool LLPluginClassMedia::textInput(const std::string &text, MASK modifiers, LLSD
return true;
}
// This function injects a previously stored OpenID cookie into
// each new media instance - see SL-15867 for details. It appears
// that the way we use the cache, shared between multiple CEF
// instances means that sometimes the OpenID cookie cannot be read
// even though it appears to be there. The long term solution to
// this is to create a separate cache directory for each instance
// but that has its own set of problems. This short term approach
// "forces" each new media instance to have a copy of the cookie
// so that a page that needs it - e.g. Profiles - finds it and
// can log in successfully.
void LLPluginClassMedia::injectOpenIDCookie()
{
// can be called before we know who the user is at login
// and there is no OpenID cookie at that point so no
// need to try to set it (these values will all be empty)
if (sOIDcookieName.length() && sOIDcookieValue.length())
{
setCookie(sOIDcookieUrl, sOIDcookieName,
sOIDcookieValue, sOIDcookieHost, sOIDcookiePath, sOIDcookieHttpOnly, sOIDcookieSecure);
}
}
// We store each component of the OpenI cookie individuality here
// because previously, there was some significant parsing to
// break up the raw string into these components and we do not
// want to have to do that again here. Stored as statics because
// we want to share their value between all instances of this
// class - the ones that receive it at login and any others
// that open afterwards (e.g. the Profiles floater)
std::string LLPluginClassMedia::sOIDcookieUrl = std::string();
std::string LLPluginClassMedia::sOIDcookieName = std::string();
std::string LLPluginClassMedia::sOIDcookieValue = std::string();
std::string LLPluginClassMedia::sOIDcookieHost = std::string();
std::string LLPluginClassMedia::sOIDcookiePath = std::string();
bool LLPluginClassMedia::sOIDcookieHttpOnly = false;
bool LLPluginClassMedia::sOIDcookieSecure = false;
// Once we receive the OpenID cookie, it is parsed/processed
// in llViewerMedia::parseRawCookie() and then the component
// values are stored here so that next time a new media
// instance is created, we can use injectOpenIDCookie()
// to "insist" that the cookie store remember its value.
// One might ask why we need to go via LLViewerMedia (which
// makes this call) - this is because the raw cookie arrives
// here in this file but undergoes non-trivial processing
// in LLViewerMedia.
void LLPluginClassMedia::storeOpenIDCookie(const std::string url,
const std::string name, const std::string value,
const std::string host, const std::string path,
bool httponly, bool secure)
{
sOIDcookieUrl = url;
sOIDcookieName = name;
sOIDcookieValue = value;
sOIDcookieHost = host;
sOIDcookiePath = path;
sOIDcookieHttpOnly = httponly;
sOIDcookieSecure = secure;
}
void LLPluginClassMedia::setCookie(std::string uri, std::string name, std::string value, std::string domain, std::string path, bool httponly, bool secure)
{
LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "set_cookie");

View File

@ -135,6 +135,20 @@ public:
// Text may be unicode (utf8 encoded)
bool textInput(const std::string &text, MASK modifiers, LLSD native_key_data);
static std::string sOIDcookieUrl;
static std::string sOIDcookieName;
static std::string sOIDcookieValue;
static std::string sOIDcookieHost;
static std::string sOIDcookiePath;
static bool sOIDcookieHttpOnly;
static bool sOIDcookieSecure;
void storeOpenIDCookie(const std::string url,
const std::string name, const std::string value,
const std::string host, const std::string path,
bool httponly, bool secure);
void injectOpenIDCookie();
void setCookie(std::string uri, std::string name, std::string value, std::string domain, std::string path, bool httponly, bool secure);
void loadURI(const std::string &uri);

View File

@ -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;

View File

@ -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);

View File

@ -27,8 +27,7 @@
#include "linden_common.h"
#include "llmediaentry.h"
#include "lllslconstants.h"
#include <boost/regex.hpp>
#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

View File

@ -122,6 +122,35 @@ const char *SCULPT_DEFAULT_TEXTURE = "be293869-d0d9-0a69-5989-ad27f1946fd4"; //
// can't be divided by 2. See DEV-19108
const F32 TEXTURE_ROTATION_PACK_FACTOR = ((F32) 0x08000);
struct material_id_type // originally from llrendermaterialtable
{
material_id_type()
{
memset((void*)m_value, 0, sizeof(m_value));
}
bool operator==(const material_id_type& other) const
{
return (memcmp(m_value, other.m_value, sizeof(m_value)) == 0);
}
bool operator!=(const material_id_type& other) const
{
return !operator==(other);
}
bool isNull() const
{
return (memcmp(m_value, s_null_id, sizeof(m_value)) == 0);
}
U8 m_value[MATERIAL_ID_SIZE]; // server side this is MD5RAW_BYTES
static const U8 s_null_id[MATERIAL_ID_SIZE];
};
const U8 material_id_type::s_null_id[] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 };
//static
// LEGACY: by default we use the LLVolumeMgr::gVolumeMgr global
// TODO -- eliminate this global from the codebase!
@ -1092,50 +1121,85 @@ S32 LLPrimitive::packTEField(U8 *cur_ptr, U8 *data_ptr, U8 data_size, U8 last_fa
return (S32)(cur_ptr - start_loc);
}
S32 LLPrimitive::unpackTEField(U8 *cur_ptr, U8 *buffer_end, U8 *data_ptr, U8 data_size, U8 face_count, EMsgVariableType type)
namespace
{
U8 *start_loc = cur_ptr;
U64 i;
htolememcpy(data_ptr,cur_ptr, type,data_size);
cur_ptr += data_size;
template< typename T >
bool unpack_TEField(T dest[], U8 dest_count, U8 * &source, U8 *source_end, EMsgVariableType type)
{
const size_t size(sizeof(T));
for (i = 1; i < face_count; i++)
{
// Already unswizzled, don't need to unswizzle it again!
memcpy(data_ptr+(i*data_size),data_ptr,data_size); /* Flawfinder: ignore */
}
while ((cur_ptr < buffer_end) && (*cur_ptr != 0))
{
LL_DEBUGS("TEFieldDecode") << "TE exception" << LL_ENDL;
i = 0;
while (*cur_ptr & 0x80)
{
i |= ((*cur_ptr++) & 0x7F);
i = i << 7;
}
LL_DEBUGS("TEXTUREENTRY") << "Request to read items of size " << size << " with swizzle " << type << " froum buffer sized " << (source_end - source) << LL_ENDL;
i |= *cur_ptr++;
if ((source + size + 1) > source_end)
{
// we add 1 above to take into account the byte that we know must follow the value.
LL_WARNS("TEXTUREENTRY") << "Buffer exhausted! Requires " << size << " + 1 bytes for default, " << (source_end - source) << " bytes remaning." << LL_ENDL;
source = source_end;
return false;
}
for (S32 j = 0; j < face_count; j++)
{
if (i & 0x01)
{
htolememcpy(data_ptr+(j*data_size),cur_ptr,type,data_size);
LL_DEBUGS("TEFieldDecode") << "Assigning " ;
char foo[64];
sprintf(foo,"%x %x",*(data_ptr+(j*data_size)), *(data_ptr+(j*data_size)+1));
LL_CONT << foo << " to face " << j << LL_ENDL;
}
i = i >> 1;
}
cur_ptr += data_size;
}
llassert(cur_ptr <= buffer_end); // buffer underrun
return (S32)(cur_ptr - start_loc);
// Extract the default value and fill the array.
htolememcpy(dest, source, type, size);
source += size;
for (S32 idx = 1; idx < dest_count; ++idx)
{
dest[idx] = dest[0];
}
while (source < source_end)
{
U64 index_flags(0);
U8 sbit(0);
// Unpack the variable length bitfield. Each bit represents whether the following
// value will be placed at the corresponding array index.
do
{
if (source >= source_end)
{
LL_WARNS("TEXTUREENTRY") << "Buffer exhausted! Reading index flags." << LL_ENDL;
source = source_end;
return false;
}
sbit = *source++;
index_flags <<= 7; // original code had this after?
index_flags |= (sbit & 0x7F);
} while (sbit & 0x80);
if (!index_flags)
{ // We've hit the terminating 0 byte.
break;
}
if ((source + size + 1) > source_end)
{
// we add 1 above to take into account the byte that we know must follow the value.
LL_WARNS("TEXTUREENTRY") << "Buffer exhausted! Requires " << size << " + 1 bytes for default, " << (source_end - source) << " bytes remaning." << LL_ENDL;
source = source_end;
return false;
}
// get the value for the indexs.
T value;
htolememcpy(&value, source, type, size);
source += size;
for (S32 idx = 0; idx < dest_count; idx++)
{
if (index_flags & 1ULL << idx)
{
dest[idx] = value;
}
}
}
return true;
}
}
// Pack information about all texture entries into container:
// { TextureEntry Variable 2 }
// Includes information about image ID, color, scale S,T, offset S,T and rotation
@ -1312,9 +1376,9 @@ BOOL LLPrimitive::packTEMessage(LLDataPacker &dp) const
S32 LLPrimitive::parseTEMessage(LLMessageSystem* mesgsys, char const* block_name, const S32 block_num, LLTEContents& tec)
{
S32 retval = 0;
// temp buffer for material ID processing
// data will end up in tec.material_id[]
U8 material_data[LLTEContents::MAX_TES*16];
// temp buffer for material ID processing
// data will end up in tec.material_id[]
material_id_type material_data[LLTEContents::MAX_TES];
if (block_num < 0)
{
@ -1330,54 +1394,49 @@ S32 LLPrimitive::parseTEMessage(LLMessageSystem* mesgsys, char const* block_name
tec.face_count = 0;
return retval;
}
else if (tec.size >= LLTEContents::MAX_TE_BUFFER)
{
LL_WARNS("TEXTUREENTRY") << "Excessive buffer size detected in Texture Entry! Truncating." << LL_ENDL;
tec.size = LLTEContents::MAX_TE_BUFFER - 1;
}
if (block_num < 0)
{
mesgsys->getBinaryDataFast(block_name, _PREHASH_TextureEntry, tec.packed_buffer, 0, 0, LLTEContents::MAX_TE_BUFFER);
}
else
{
mesgsys->getBinaryDataFast(block_name, _PREHASH_TextureEntry, tec.packed_buffer, 0, block_num, LLTEContents::MAX_TE_BUFFER);
}
// if block_num < 0 ask for block 0
mesgsys->getBinaryDataFast(block_name, _PREHASH_TextureEntry, tec.packed_buffer, 0, std::max(block_num, 0), LLTEContents::MAX_TE_BUFFER - 1);
// The last field is not zero terminated.
// Rather than special case the upack functions. Just make it 0x00 terminated.
tec.packed_buffer[tec.size] = 0x00;
++tec.size;
tec.face_count = llmin((U32)getNumTEs(),(U32)LLTEContents::MAX_TES);
U8 *cur_ptr = tec.packed_buffer;
cur_ptr += unpackTEField(cur_ptr, tec.packed_buffer+tec.size, (U8 *)tec.image_data, 16, tec.face_count, MVT_LLUUID);
cur_ptr++;
cur_ptr += unpackTEField(cur_ptr, tec.packed_buffer+tec.size, (U8 *)tec.colors, 4, tec.face_count, MVT_U8);
cur_ptr++;
cur_ptr += unpackTEField(cur_ptr, tec.packed_buffer+tec.size, (U8 *)tec.scale_s, 4, tec.face_count, MVT_F32);
cur_ptr++;
cur_ptr += unpackTEField(cur_ptr, tec.packed_buffer+tec.size, (U8 *)tec.scale_t, 4, tec.face_count, MVT_F32);
cur_ptr++;
cur_ptr += unpackTEField(cur_ptr, tec.packed_buffer+tec.size, (U8 *)tec.offset_s, 2, tec.face_count, MVT_S16Array);
cur_ptr++;
cur_ptr += unpackTEField(cur_ptr, tec.packed_buffer+tec.size, (U8 *)tec.offset_t, 2, tec.face_count, MVT_S16Array);
cur_ptr++;
cur_ptr += unpackTEField(cur_ptr, tec.packed_buffer+tec.size, (U8 *)tec.image_rot, 2, tec.face_count, MVT_S16Array);
cur_ptr++;
cur_ptr += unpackTEField(cur_ptr, tec.packed_buffer+tec.size, (U8 *)tec.bump, 1, tec.face_count, MVT_U8);
cur_ptr++;
cur_ptr += unpackTEField(cur_ptr, tec.packed_buffer+tec.size, (U8 *)tec.media_flags, 1, tec.face_count, MVT_U8);
cur_ptr++;
cur_ptr += unpackTEField(cur_ptr, tec.packed_buffer+tec.size, (U8 *)tec.glow, 1, tec.face_count, MVT_U8);
LL_DEBUGS("TEXTUREENTRY") << "Texture Entry with buffere sized: " << tec.size << LL_ENDL;
U8 *buffer_end = tec.packed_buffer + tec.size;
if (cur_ptr < tec.packed_buffer + tec.size)
if (!( unpack_TEField<LLUUID>(tec.image_data, tec.face_count, cur_ptr, buffer_end, MVT_LLUUID) &&
unpack_TEField<LLColor4U>(tec.colors, tec.face_count, cur_ptr, buffer_end, MVT_U8) &&
unpack_TEField<F32>(tec.scale_s, tec.face_count, cur_ptr, buffer_end, MVT_F32) &&
unpack_TEField<F32>(tec.scale_t, tec.face_count, cur_ptr, buffer_end, MVT_F32) &&
unpack_TEField<S16>(tec.offset_s, tec.face_count, cur_ptr, buffer_end, MVT_S16) &&
unpack_TEField<S16>(tec.offset_t, tec.face_count, cur_ptr, buffer_end, MVT_S16) &&
unpack_TEField<S16>(tec.image_rot, tec.face_count, cur_ptr, buffer_end, MVT_S16) &&
unpack_TEField<U8>(tec.bump, tec.face_count, cur_ptr, buffer_end, MVT_U8) &&
unpack_TEField<U8>(tec.media_flags, tec.face_count, cur_ptr, buffer_end, MVT_U8) &&
unpack_TEField<U8>(tec.glow, tec.face_count, cur_ptr, buffer_end, MVT_U8)))
{
LL_WARNS("TEXTUREENTRY") << "Failure parsing Texture Entry Message due to malformed TE Field! Dropping changes on the floor. " << LL_ENDL;
return 0;
}
if (cur_ptr >= buffer_end || !unpack_TEField<material_id_type>(material_data, tec.face_count, cur_ptr, buffer_end, MVT_LLUUID))
{
cur_ptr++;
cur_ptr += unpackTEField(cur_ptr, tec.packed_buffer+tec.size, (U8 *)material_data, 16, tec.face_count, MVT_LLUUID);
}
else
{
memset(material_data, 0, sizeof(material_data));
memset((void*)material_data, 0, sizeof(material_data));
}
for (U32 i = 0; i < tec.face_count; i++)
{
tec.material_ids[i].set(&material_data[i * 16]);
tec.material_ids[i].set(&(material_data[i]));
}
retval = 1;
@ -1389,7 +1448,6 @@ S32 LLPrimitive::applyParsedTEMessage(LLTEContents& tec)
S32 retval = 0;
LLColor4 color;
LLColor4U coloru;
for (U32 i = 0; i < tec.face_count; i++)
{
LLUUID& req_id = ((LLUUID*)tec.image_data)[i];
@ -1402,20 +1460,15 @@ S32 LLPrimitive::applyParsedTEMessage(LLTEContents& tec)
retval |= setTEGlow(i, (F32)tec.glow[i] / (F32)0xFF);
retval |= setTEMaterialID(i, tec.material_ids[i]);
coloru = LLColor4U(tec.colors + 4*i);
// Note: This is an optimization to send common colors (1.f, 1.f, 1.f, 1.f)
// as all zeros. However, the subtraction and addition must be done in unsigned
// byte space, not in float space, otherwise off-by-one errors occur. JC
color.mV[VRED] = F32(255 - coloru.mV[VRED]) / 255.f;
color.mV[VGREEN] = F32(255 - coloru.mV[VGREEN]) / 255.f;
color.mV[VBLUE] = F32(255 - coloru.mV[VBLUE]) / 255.f;
color.mV[VALPHA] = F32(255 - coloru.mV[VALPHA]) / 255.f;
color.mV[VRED] = F32(255 - tec.colors[i].mV[VRED]) / 255.f;
color.mV[VGREEN] = F32(255 - tec.colors[i].mV[VGREEN]) / 255.f;
color.mV[VBLUE] = F32(255 - tec.colors[i].mV[VBLUE]) / 255.f;
color.mV[VALPHA] = F32(255 - tec.colors[i].mV[VALPHA]) / 255.f;
retval |= setTEColor(i, color);
}
return retval;
@ -1437,24 +1490,32 @@ S32 LLPrimitive::unpackTEMessage(LLDataPacker &dp)
const U32 MAX_TES = 45;
// Avoid construction of 32 UUIDs per call
static LLUUID image_ids[MAX_TES];
static LLMaterialID material_ids[MAX_TES];
U8 image_data[MAX_TES*16];
U8 colors[MAX_TES*4];
F32 scale_s[MAX_TES];
F32 scale_t[MAX_TES];
S16 offset_s[MAX_TES];
S16 offset_t[MAX_TES];
S16 image_rot[MAX_TES];
U8 bump[MAX_TES];
U8 media_flags[MAX_TES];
U8 glow[MAX_TES];
U8 material_data[MAX_TES*16];
const U32 MAX_TE_BUFFER = 4096;
U8 packed_buffer[MAX_TE_BUFFER];
memset((void*)packed_buffer, 0, MAX_TE_BUFFER);
const U32 MAX_TE_BUFFER = 4096;
U8 packed_buffer[MAX_TE_BUFFER];
U8 *cur_ptr = packed_buffer;
LLUUID image_data[MAX_TES];
LLColor4U colors[MAX_TES];
F32 scale_s[MAX_TES];
F32 scale_t[MAX_TES];
S16 offset_s[MAX_TES];
S16 offset_t[MAX_TES];
S16 image_rot[MAX_TES];
U8 bump[MAX_TES];
U8 media_flags[MAX_TES];
U8 glow[MAX_TES];
material_id_type material_data[MAX_TES];
memset((void*)scale_s, 0, sizeof(scale_s));
memset((void*)scale_t, 0, sizeof(scale_t));
memset((void*)offset_s, 0, sizeof(offset_s));
memset((void*)offset_t, 0, sizeof(offset_t));
memset((void*)image_rot, 0, sizeof(image_rot));
memset((void*)bump, 0, sizeof(bump));
memset((void*)media_flags, 0, sizeof(media_flags));
memset((void*)glow, 0, sizeof(glow));
S32 size;
U32 face_count = 0;
@ -1470,50 +1531,52 @@ S32 LLPrimitive::unpackTEMessage(LLDataPacker &dp)
{
return retval;
}
else if (size >= MAX_TE_BUFFER)
{
LL_WARNS("TEXTUREENTRY") << "Excessive buffer size detected in Texture Entry! Truncating." << LL_ENDL;
size = MAX_TE_BUFFER - 1;
}
// The last field is not zero terminated.
// Rather than special case the upack functions. Just make it 0x00 terminated.
packed_buffer[size] = 0x00;
++size;
face_count = llmin((U32) getNumTEs(), MAX_TES);
U32 i;
cur_ptr += unpackTEField(cur_ptr, packed_buffer+size, (U8 *)image_data, 16, face_count, MVT_LLUUID);
cur_ptr++;
cur_ptr += unpackTEField(cur_ptr, packed_buffer+size, (U8 *)colors, 4, face_count, MVT_U8);
cur_ptr++;
cur_ptr += unpackTEField(cur_ptr, packed_buffer+size, (U8 *)scale_s, 4, face_count, MVT_F32);
cur_ptr++;
cur_ptr += unpackTEField(cur_ptr, packed_buffer+size, (U8 *)scale_t, 4, face_count, MVT_F32);
cur_ptr++;
cur_ptr += unpackTEField(cur_ptr, packed_buffer+size, (U8 *)offset_s, 2, face_count, MVT_S16Array);
cur_ptr++;
cur_ptr += unpackTEField(cur_ptr, packed_buffer+size, (U8 *)offset_t, 2, face_count, MVT_S16Array);
cur_ptr++;
cur_ptr += unpackTEField(cur_ptr, packed_buffer+size, (U8 *)image_rot, 2, face_count, MVT_S16Array);
cur_ptr++;
cur_ptr += unpackTEField(cur_ptr, packed_buffer+size, (U8 *)bump, 1, face_count, MVT_U8);
cur_ptr++;
cur_ptr += unpackTEField(cur_ptr, packed_buffer+size, (U8 *)media_flags, 1, face_count, MVT_U8);
cur_ptr++;
cur_ptr += unpackTEField(cur_ptr, packed_buffer+size, (U8 *)glow, 1, face_count, MVT_U8);
if (cur_ptr < packed_buffer + size)
U8 *cur_ptr = packed_buffer;
LL_DEBUGS("TEXTUREENTRY") << "Texture Entry with buffer sized: " << size << LL_ENDL;
U8 *buffer_end = packed_buffer + size;
if (!( unpack_TEField<LLUUID>(image_data, face_count, cur_ptr, buffer_end, MVT_LLUUID) &&
unpack_TEField<LLColor4U>(colors, face_count, cur_ptr, buffer_end, MVT_U8) &&
unpack_TEField<F32>(scale_s, face_count, cur_ptr, buffer_end, MVT_F32) &&
unpack_TEField<F32>(scale_t, face_count, cur_ptr, buffer_end, MVT_F32) &&
unpack_TEField<S16>(offset_s, face_count, cur_ptr, buffer_end, MVT_S16) &&
unpack_TEField<S16>(offset_t, face_count, cur_ptr, buffer_end, MVT_S16) &&
unpack_TEField<S16>(image_rot, face_count, cur_ptr, buffer_end, MVT_S16) &&
unpack_TEField<U8>(bump, face_count, cur_ptr, buffer_end, MVT_U8) &&
unpack_TEField<U8>(media_flags, face_count, cur_ptr, buffer_end, MVT_U8) &&
unpack_TEField<U8>(glow, face_count, cur_ptr, buffer_end, MVT_U8)))
{
LL_WARNS("TEXTUREENTRY") << "Failure parsing Texture Entry Message due to malformed TE Field! Dropping changes on the floor. " << LL_ENDL;
return 0;
}
if (cur_ptr >= buffer_end || !unpack_TEField<material_id_type>(material_data, face_count, cur_ptr, buffer_end, MVT_LLUUID))
{
cur_ptr++;
cur_ptr += unpackTEField(cur_ptr, packed_buffer+size, (U8 *)material_data, 16, face_count, MVT_LLUUID);
}
else
{
memset(material_data, 0, sizeof(material_data));
memset((void*)material_data, 0, sizeof(material_data));
}
for (i = 0; i < face_count; i++)
{
memcpy( image_ids[ i ].mData, &image_data[ i*UUID_BYTES ], UUID_BYTES ); /* Flawfinder: ignore */
material_ids[ i ].set( &material_data[ i * UUID_BYTES ] );
material_ids[i].set(&(material_data[i]));
}
LLColor4 color;
LLColor4U coloru;
for (i = 0; i < face_count; i++)
{
retval |= setTETexture(i, image_ids[i]);
retval |= setTETexture(i, ((LLUUID*)image_data)[i]);
retval |= setTEScale(i, scale_s[i], scale_t[i]);
retval |= setTEOffset(i, (F32)offset_s[i] / (F32)0x7FFF, (F32) offset_t[i] / (F32) 0x7FFF);
retval |= setTERotation(i, ((F32)image_rot[i] / TEXTURE_ROTATION_PACK_FACTOR) * F_TWO_PI);
@ -1521,15 +1584,14 @@ S32 LLPrimitive::unpackTEMessage(LLDataPacker &dp)
retval |= setTEMediaTexGen(i, media_flags[i]);
retval |= setTEGlow(i, (F32)glow[i] / (F32)0xFF);
retval |= setTEMaterialID(i, material_ids[i]);
coloru = LLColor4U(colors + 4*i);
// Note: This is an optimization to send common colors (1.f, 1.f, 1.f, 1.f)
// as all zeros. However, the subtraction and addition must be done in unsigned
// byte space, not in float space, otherwise off-by-one errors occur. JC
color.mV[VRED] = F32(255 - coloru.mV[VRED]) / 255.f;
color.mV[VGREEN] = F32(255 - coloru.mV[VGREEN]) / 255.f;
color.mV[VBLUE] = F32(255 - coloru.mV[VBLUE]) / 255.f;
color.mV[VALPHA] = F32(255 - coloru.mV[VALPHA]) / 255.f;
color.mV[VRED] = F32(255 - colors[i].mV[VRED]) / 255.f;
color.mV[VGREEN] = F32(255 - colors[i].mV[VGREEN]) / 255.f;
color.mV[VBLUE] = F32(255 - colors[i].mV[VBLUE]) / 255.f;
color.mV[VALPHA] = F32(255 - colors[i].mV[VALPHA]) / 255.f;
retval |= setTEColor(i, color);
}

View File

@ -338,8 +338,8 @@ struct LLTEContents
{
static const U32 MAX_TES = 45;
U8 image_data[MAX_TES*16];
U8 colors[MAX_TES*4];
LLUUID image_data[MAX_TES];
LLColor4U colors[MAX_TES];
F32 scale_s[MAX_TES];
F32 scale_t[MAX_TES];
S16 offset_s[MAX_TES];
@ -432,7 +432,6 @@ public:
void copyTEs(const LLPrimitive *primitive);
S32 packTEField(U8 *cur_ptr, U8 *data_ptr, U8 data_size, U8 last_face_index, EMsgVariableType type) const;
S32 unpackTEField(U8 *cur_ptr, U8 *buffer_end, U8 *data_ptr, U8 data_size, U8 face_count, EMsgVariableType type);
BOOL packTEMessage(LLMessageSystem *mesgsys) const;
BOOL packTEMessage(LLDataPacker &dp) const;
S32 unpackTEMessage(LLMessageSystem* mesgsys, char const* block_name, const S32 block_num); // Variable num of blocks

View File

@ -1065,6 +1065,43 @@ void LLComboBox::prearrangeList(std::string filter)
}
}
//============================================================================
// ll::ui::SearchableControl functions
//virtual
std::string LLComboBox::_getSearchText() const
{
std::string res;
if (mList)
{
// getAllData returns a full copy of content, might be a
// better option to implement an mList->getSearchText(column)
std::vector<LLScrollListItem*> data = mList->getAllData();
std::vector<LLScrollListItem*>::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

View File

@ -44,7 +44,9 @@ class LLFontGL;
class LLViewBorder;
class LLComboBox
: public LLUICtrl, public LLCtrlListInterface
: public LLUICtrl
, public LLCtrlListInterface
, public ll::ui::SearchableControl
{
public:
typedef enum e_preferred_position
@ -101,6 +103,9 @@ protected:
void initFromParams(const Params&);
void prearrangeList(std::string filter = "");
virtual std::string _getSearchText() const;
virtual void onSetHighlight() const;
public:
// LLView interface
virtual void onFocusLost();

View File

@ -84,7 +84,6 @@
#include <sstream>
#include <boost/utility.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/type_traits.hpp>
#include <boost/signals2.hpp>
#include <boost/range.hpp>
@ -132,7 +131,7 @@ public:
typedef boost::function<void (const LLSD&, const LLSD&)> LLNotificationResponder;
typedef boost::shared_ptr<LLNotificationResponderInterface> LLNotificationResponderPtr;
typedef std::shared_ptr<LLNotificationResponderInterface> LLNotificationResponderPtr;
typedef LLFunctorRegistry<LLNotificationResponder> LLNotificationFunctorRegistry;
typedef LLFunctorRegistration<LLNotificationResponder> LLNotificationFunctorRegistration;
@ -278,19 +277,19 @@ private:
bool mInvertSetting;
};
typedef boost::shared_ptr<LLNotificationForm> LLNotificationFormPtr;
typedef std::shared_ptr<LLNotificationForm> LLNotificationFormPtr;
struct LLNotificationTemplate;
// we want to keep a map of these by name, and it's best to manage them
// with smart pointers
typedef boost::shared_ptr<LLNotificationTemplate> LLNotificationTemplatePtr;
typedef std::shared_ptr<LLNotificationTemplate> LLNotificationTemplatePtr;
struct LLNotificationVisibilityRule;
typedef boost::shared_ptr<LLNotificationVisibilityRule> LLNotificationVisibilityRulePtr;
typedef std::shared_ptr<LLNotificationVisibilityRule> LLNotificationVisibilityRulePtr;
/**
* @class LLNotification
@ -764,6 +763,10 @@ public:
{}
virtual ~LLNotificationChannelBase()
{
// explicit cleanup for easier issue detection
mChanged.disconnect_all_slots();
mPassedFilter.disconnect_all_slots();
mFailedFilter.disconnect_all_slots();
mItems.clear();
}
// you can also connect to a Channel, so you can be notified of

View File

@ -31,7 +31,6 @@
#include "lleventapi.h"
#include "llnotificationptr.h"
#include <boost/shared_ptr.hpp>
#include <map>
#include <string>
@ -61,7 +60,7 @@ private:
static LLSD asLLSD(LLNotificationPtr);
class Forwarder;
typedef std::map<std::string, boost::shared_ptr<Forwarder> > ForwarderMap;
typedef std::map<std::string, std::shared_ptr<Forwarder> > ForwarderMap;
ForwarderMap mForwarders;
LLNotifications & mNotifications;
};

View File

@ -31,7 +31,7 @@
#include "llinitparam.h"
#include "llnotifications.h"
typedef boost::shared_ptr<LLNotificationForm> LLNotificationFormPtr;
typedef std::shared_ptr<LLNotificationForm> LLNotificationFormPtr;
// This is the class of object read from the XML file (notifications.xml,
// from the appropriate local language directory).

View File

@ -54,6 +54,10 @@ LLScrollListCell* LLScrollListCell::create(const LLScrollListCell::Params& cell_
{
cell = new LLScrollListIconText(cell_p);
}
else if (cell_p.type() == "bar")
{
cell = new LLScrollListBar(cell_p);
}
else // default is "text"
{
cell = new LLScrollListText(cell_p);
@ -165,6 +169,74 @@ void LLScrollListIcon::draw(const LLColor4& color, const LLColor4& highlight_col
}
}
//
// LLScrollListBar
//
LLScrollListBar::LLScrollListBar(const LLScrollListCell::Params& p)
: LLScrollListCell(p),
mRatio(0),
mColor(p.color),
mBottom(1),
mLeftPad(1),
mRightPad(1)
{}
LLScrollListBar::~LLScrollListBar()
{
}
/*virtual*/
S32 LLScrollListBar::getHeight() const
{
return LLScrollListCell::getHeight();
}
/*virtual*/
const LLSD LLScrollListBar::getValue() const
{
return LLStringUtil::null;
}
void LLScrollListBar::setValue(const LLSD& value)
{
if (value.has("ratio"))
{
mRatio = value["ratio"].asReal();
}
if (value.has("bottom"))
{
mBottom = value["bottom"].asInteger();
}
if (value.has("left_pad"))
{
mLeftPad = value["left_pad"].asInteger();
}
if (value.has("right_pad"))
{
mRightPad = value["right_pad"].asInteger();
}
}
void LLScrollListBar::setColor(const LLColor4& color)
{
mColor = color;
}
S32 LLScrollListBar::getWidth() const
{
return LLScrollListCell::getWidth();
}
void LLScrollListBar::draw(const LLColor4& color, const LLColor4& highlight_color) const
{
S32 bar_width = getWidth() - mLeftPad - mRightPad;
S32 left = bar_width - bar_width * mRatio;
left = llclamp(left, mLeftPad, getWidth() - mRightPad - 1);
gl_rect_2d(left, mBottom, getWidth() - mRightPad, mBottom - 1, mColor);
}
//
// LLScrollListText
//

View File

@ -33,6 +33,7 @@
#include "lluistring.h"
#include "v4color.h"
#include "llui.h"
#include "llgltexture.h"
class LLCheckBoxCtrl;
class LLSD;
@ -153,6 +154,7 @@ public:
void setText(const LLStringExplicit& text);
void setFontStyle(const U8 font_style);
void setAlignment(LLFontGL::HAlign align) { mFontAlignment = align; }
protected:
LLUIString mText;
@ -192,6 +194,26 @@ private:
LLFontGL::HAlign mAlignment;
};
class LLScrollListBar : public LLScrollListCell
{
public:
LLScrollListBar(const LLScrollListCell::Params& p);
/*virtual*/ ~LLScrollListBar();
/*virtual*/ void draw(const LLColor4& color, const LLColor4& highlight_color) const;
/*virtual*/ S32 getWidth() const;
/*virtual*/ S32 getHeight() const;
/*virtual*/ const LLSD getValue() const;
/*virtual*/ void setColor(const LLColor4&);
/*virtual*/ void setValue(const LLSD& value);
private:
LLColor4 mColor;
F32 mRatio;
S32 mBottom;
S32 mRightPad;
S32 mLeftPad;
};
/*
* An interactive cell containing a check box.
*/

View File

@ -207,6 +207,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),
@ -1134,6 +1135,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;

View File

@ -760,6 +760,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 mAlwaysShowIcons;
bool mSkipLinkUnderline;

View File

@ -45,7 +45,9 @@ LLTextBox::LLTextBox(const LLTextBox::Params& p)
: LLTextBase(p),
mClickedCallback(NULL),
mShowCursorHand(true)
{}
{
mSkipTripleClick = true;
}
LLTextBox::~LLTextBox()
{}

View File

@ -35,6 +35,7 @@
#include "llavatarnamecache.h"
#include "llcachename.h"
#include "llregex.h"
#include "lltrans.h"
#include "lluicolortable.h"
#include "message.h"
@ -184,11 +185,51 @@ bool LLUrlEntryBase::isLinkDisabled() const
return globally_disabled;
}
bool LLUrlEntryBase::isWikiLinkCorrect(std::string url)
bool LLUrlEntryBase::isWikiLinkCorrect(const std::string &labeled_url) const
{
LLWString label = utf8str_to_wstring(getLabelFromWikiLink(url));
label.erase(std::remove(label.begin(), label.end(), L'\u200B'), label.end());
return (LLUrlRegistry::instance().hasUrl(wstring_to_utf8str(label))) ? false : true;
LLWString wlabel = utf8str_to_wstring(getLabelFromWikiLink(labeled_url));
wlabel.erase(std::remove(wlabel.begin(), wlabel.end(), L'\u200B'), wlabel.end());
// Unicode URL validation, see SL-15243
std::replace_if(wlabel.begin(),
wlabel.end(),
[](const llwchar &chr)
{
return (chr == L'\u2024') // "One Dot Leader"
|| (chr == L'\uFE52') // "Small Full Stop"
|| (chr == L'\uFF0E') // "Fullwidth Full Stop"
// Not a decomposition, but suficiently similar
|| (chr == L'\u05C5'); // "Hebrew Mark Lower Dot"
},
L'\u002E'); // Dot "Full Stop"
std::replace_if(wlabel.begin(),
wlabel.end(),
[](const llwchar &chr)
{
return (chr == L'\u02D0') // "Modifier Letter Colon"
|| (chr == L'\uFF1A') // "Fullwidth Colon"
|| (chr == L'\uFE55'); // "Small Colon"
},
L'\u003A'); // Colon
std::replace_if(wlabel.begin(),
wlabel.end(),
[](const llwchar &chr)
{
return (chr == L'\uFF0F'); // "Fullwidth Solidus"
},
L'\u002F'); // Solidus
std::string label = wstring_to_utf8str(wlabel);
if ((label.find(".com") != std::string::npos
|| label.find("www.") != std::string::npos)
&& label.find("://") == std::string::npos)
{
label = "http://" + label;
}
return (LLUrlRegistry::instance().hasUrl(label)) ? false : true;
}
std::string LLUrlEntryBase::urlToLabelWithGreyQuery(const std::string &url) const
@ -1603,7 +1644,7 @@ std::string LLUrlEntryIcon::getIcon(const std::string &url)
// Grep icon info between <icon>...</icon> tags
// matches[1] contains the icon name/path
boost::match_results<std::string::const_iterator> 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);

View File

@ -105,7 +105,7 @@ public:
bool isLinkDisabled() const;
bool isWikiLinkCorrect(std::string url);
bool isWikiLinkCorrect(const std::string &url) const;
virtual bool isSLURLvalid(const std::string &url) const { return TRUE; };

View File

@ -26,10 +26,10 @@
*/
#include "linden_common.h"
#include "llregex.h"
#include "llurlregistry.h"
#include "lluriparser.h"
#include <boost/regex.hpp>
#include <boost/algorithm/string/find.hpp> //for boost::ifind_first -KC
// default dummy callback that ignores any label updates from the server
@ -127,15 +127,7 @@ static bool matchRegex(const char *text, boost::regex regex, U32 &start, U32 &en
boost::cmatch result;
bool found;
// regex_search can potentially throw an exception, so check for it
try
{
found = boost::regex_search(text, result, regex);
}
catch (std::runtime_error &)
{
return false;
}
found = ll_regex_search(text, result, regex);
if (! found)
{

View File

@ -33,6 +33,7 @@
LLNonInlineTextView *inputView;
NSTimer *frameTimer;
NSString *currentInputLanguage;
std::string secondLogPath;
}
@property (assign) IBOutlet LLNSWindow *window;

View File

@ -504,7 +504,8 @@ attributedStringInfo getSegments(NSAttributedString *str)
// e.g. OS Window for upload something or Input Window...
// mModifiers instance variable is for insertText: or insertText:replacementRange: (by Pell Smit)
mModifiers = [theEvent modifierFlags];
bool acceptsText = mHasMarkedText ? false : callKeyDown(&eventData, keycode, mModifiers);
bool acceptsText = mHasMarkedText ? false : callKeyDown(&eventData, keycode, mModifiers, [[theEvent characters] characterAtIndex:0]);
unichar ch;
if (acceptsText &&
!mMarkedTextAllowed &&
@ -547,7 +548,7 @@ attributedStringInfo getSegments(NSAttributedString *str)
if (mModifiers & mask)
{
eventData.mKeyEvent = NativeKeyEventData::KEYDOWN;
callKeyDown(&eventData, [theEvent keyCode], 0);
callKeyDown(&eventData, [theEvent keyCode], 0, [[theEvent characters] characterAtIndex:0]);
}
else
{

View File

@ -132,7 +132,7 @@ void setupInputWindow(NSWindowRef window, GLViewRef view);
// These are all implemented in llwindowmacosx.cpp.
// This is largely for easier interop between Obj-C and C++ (at least in the viewer's case due to the BOOL vs. BOOL conflict)
bool callKeyUp(NSKeyEventRef event, unsigned short key, unsigned int mask);
bool callKeyDown(NSKeyEventRef event, unsigned short key, unsigned int mask);
bool callKeyDown(NSKeyEventRef event, unsigned short key, unsigned int mask, wchar_t character);
void callResetKeys();
bool callUnicodeCallback(wchar_t character, unsigned int mask);
void callRightMouseDown(float *pos, unsigned int mask);

View File

@ -217,8 +217,17 @@ bool callKeyUp(NSKeyEventRef event, unsigned short key, unsigned int mask)
return retVal;
}
bool callKeyDown(NSKeyEventRef event, unsigned short key, unsigned int mask)
bool callKeyDown(NSKeyEventRef event, unsigned short key, unsigned int mask, wchar_t character)
{
if((key == gKeyboard->inverseTranslateKey('Z')) && (character == 'y'))
{
key = gKeyboard->inverseTranslateKey('Y');
}
else if ((key == gKeyboard->inverseTranslateKey('Y')) && (character == 'z'))
{
key = gKeyboard->inverseTranslateKey('Z');
}
mRawKeyEvent = event;
bool retVal = gKeyboard->handleKeyDown(key, mask);
mRawKeyEvent = NULL;

View File

@ -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}

View File

@ -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 <functional>
#include <chrono>
#include "dullahan.h"
#include "dullahan_version.h"

View File

@ -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,14 +350,11 @@ void MediaPluginLibVLC::playMedia()
setStatus(STATUS_LOADED);
libvlc_video_set_callbacks(mLibVLCMediaPlayer, lock, unlock, display, &mLibVLCCallbackContext);
libvlc_video_set_format(mLibVLCMediaPlayer, "RV32", mWidth, mHeight, mWidth * mDepth);
// note this relies on the "set_loop" message arriving before the "start" (play) one
// but that appears to always be the case
if (mIsLooping)
{
libvlc_media_add_option(mLibVLCMedia, "input-repeat=-1");
libvlc_media_add_option(mLibVLCMedia, "input-repeat=65535");
}
libvlc_media_player_play(mLibVLCMediaPlayer);

View File

@ -397,10 +397,13 @@ set(viewer_SOURCE_FILES
llfloaterpathfindinglinksets.cpp
llfloaterpathfindingobjects.cpp
llfloaterpay.cpp
# llfloaterperformance.cpp <FS:Beq/> replaced with fs version due to large changes and likelihood that LL version will not release.
fsfloaterperformance.cpp
llfloaterperms.cpp
llfloaterpostprocess.cpp
llfloaterprofile.cpp
llfloaterpreference.cpp
# llfloaterpreferencesgraphicsadvanced.cpp
llfloaterpreferenceviewadvanced.cpp
llfloaterpreviewtrash.cpp
llfloaterproperties.cpp
@ -1176,10 +1179,13 @@ set(viewer_HEADER_FILES
llfloaterpathfindinglinksets.h
llfloaterpathfindingobjects.h
llfloaterpay.h
# llfloaterperformance.h <FS:Beq/> replaced with fs version due to large changes and likelihood that LL version will not release.
fsfloaterperformance.h
llfloaterperms.h
llfloaterpostprocess.h
llfloaterprofile.h
llfloaterpreference.h
# llfloaterpreferencesgraphicsadvanced.h
llfloaterpreferenceviewadvanced.h
llfloaterpreviewtrash.h
llfloaterproperties.h
@ -1678,6 +1684,10 @@ configure_file(
list(APPEND viewer_HEADER_FILES ${CMAKE_CURRENT_BINARY_DIR}/fsversionvalues.h)
# </FS:TS>
# <FS:Beq> Performance stast support
list(APPEND viewer_SOURCE_FILES fsperfstats.cpp)
list(APPEND viewer_HEADER_FILES fsperfstats.h)
# </FS:Beq>
source_group("CMake Rules" FILES ViewerInstall.cmake)
#build_data.json creation moved to viewer_manifest.py MAINT-6413
@ -2562,7 +2572,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
@ -2674,10 +2684,8 @@ if (DARWIN)
# SIGH, as of 2018-05-24 (cmake 3.11.1) the INSTALL_RPATH property simply
# does not work. Try this:
LINK_FLAGS "-rpath @loader_path/../Frameworks"
MACOSX_BUNDLE_INFO_PLIST
# <FS:CR> Use Firestorm plist
#"${CMAKE_CURRENT_SOURCE_DIR}/Info-SecondLife.plist"
"${CMAKE_CURRENT_SOURCE_DIR}/Info-Firestorm.plist"
MACOSX_BUNDLE_INFO_PLIST "${CMAKE_CURRENT_SOURCE_DIR}/Info-Firestorm.plist"
XCODE_ATTRIBUTE_PRODUCT_BUNDLE_IDENTIFIER "${MACOSX_BUNDLE_GUI_IDENTIFIER}"
)
set(VIEWER_APP_BUNDLE "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/${product}.app")

View File

@ -11,7 +11,7 @@
<key>CFBundleIconFile</key>
<string>${MACOSX_BUNDLE_ICON_FILE}</string>
<key>CFBundleIdentifier</key>
<string>${MACOSX_BUNDLE_GUI_IDENTIFIER}</string>
<string>${PRODUCT_BUNDLE_IDENTIFIER}</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleLongVersionString</key>

View File

@ -11,7 +11,7 @@
<key>CFBundleIconFile</key>
<string>${MACOSX_BUNDLE_ICON_FILE}</string>
<key>CFBundleIdentifier</key>
<string>${MACOSX_BUNDLE_GUI_IDENTIFIER}</string>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleLongVersionString</key>

View File

@ -10,7 +10,6 @@
#include "llviewerobjectlist.h"
#include "llviewerregion.h"
#include "llworld.h"
#include "sound_ids.h"
#include <time.h>
#include <boost/regex.hpp>
@ -207,11 +206,6 @@ NACLAntiSpamRegistry::NACLAntiSpamRegistry() :
{
mQueues[queue] = new NACLAntiSpamQueue(mGlobalTime, mGlobalAmount);
}
for (S32 i = 0; i < COLLISION_SOUNDS_SIZE; ++i)
{
mCollisionSounds.insert(LLUUID(COLLISION_SOUNDS[i]));
}
}
NACLAntiSpamRegistry::~NACLAntiSpamRegistry()
@ -640,11 +634,6 @@ void NACLAntiSpamRegistry::purgeGlobalEntries()
mGlobalEntries.clear();
}
bool NACLAntiSpamRegistry::isCollisionSound(const LLUUID& sound_id)
{
return (mCollisionSounds.find(sound_id) != mCollisionSounds.end());
}
void NACLAntiSpamRegistry::processObjectPropertiesFamily(LLMessageSystem* msg)
{
static LLCachedControl<bool> useAntiSpam(gSavedSettings, "UseAntiSpam");

View File

@ -113,8 +113,6 @@ public:
void clearAllQueues();
void purgeAllQueues();
bool isCollisionSound(const LLUUID& sound_id);
void processObjectPropertiesFamily(LLMessageSystem* msg);
private:

View File

@ -1 +1 @@
6.5.0
6.5.1

View File

@ -636,4 +636,14 @@
is_running_function="Floater.IsOpen"
is_running_parameters="my_environments"
/>
<command name="performance"
available_in_toybox="true"
icon="Command_Performance_Icon"
label_ref="Command_Performance_Label"
tooltip_ref="Command_Performance_Tooltip"
execute_function="Floater.ToggleOrBringToFront"
execute_parameters="performance"
is_running_function="Floater.IsOpen"
is_running_parameters="performance"
/>
</commands>

View File

@ -3176,10 +3176,11 @@
<key>Value</key>
<real>1.0</real>
</map>
<key>CameraPreset</key> <!-- deprecated (see SL-12429) -->
<key>CameraPreset</key>
<!-- deprecated (see SL-12429) -->
<map>
<key>Comment</key>
<string>Preset camera position - view (0 - rear, 1 - front, 2 - group)</string>
<string>(Deprecated) Preset camera position - view (0 - rear, 1 - front, 2 - group)</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
@ -4205,10 +4206,11 @@
<key>Backup</key>
<integer>0</integer>
</map>
<key>DEPRECATED: DebugShowPrivateMem</key> <!-- deprecated (see MAINT-8091) -->
<key>DebugShowPrivateMem</key>
<!-- deprecated (see MAINT-8091) -->
<map>
<key>Comment</key>
<string>Show Private Mem Info</string>
<string>(Deprecated) Show Private Mem Info</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
@ -5843,6 +5845,17 @@
<key>Value</key>
<integer>1</integer>
</map>
<key>EnableCollisionSounds</key>
<map>
<key>Comment</key>
<string>Play sounds on collision</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>Boolean</string>
<key>Value</key>
<integer>1</integer>
</map>
<key>EnableMouselook</key>
<map>
<key>Comment</key>
@ -8160,7 +8173,7 @@
<key>Comment</key>
<string>Duration in seconds of the login SRV request timeout</string>
<key>Persist</key>
<integer>0</integer>
<integer>1</integer>
<key>Type</key>
<string>F32</string>
<key>Value</key>
@ -8169,7 +8182,7 @@
<key>LoginSRVPump</key>
<map>
<key>Comment</key>
<string>Name of the message pump that handles SRV request (deprecated)</string>
<string>(Deprecated) Name of the message pump that handles SRV request)</string>
<key>Persist</key>
<integer>0</integer>
<key>Type</key>
@ -9027,10 +9040,11 @@
<key>Value</key>
<real>600.0</real>
</map>
<key>MemoryPrivatePoolEnabled</key> <!-- deprecated (see MAINT-8091) -->
<key>MemoryPrivatePoolEnabled</key>
<!-- deprecated (see MAINT-8091) -->
<map>
<key>Comment</key>
<string>DEPRECATED: Enable the private memory pool management</string>
<string>(Deprecated) Enable the private memory pool management</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
@ -9040,10 +9054,11 @@
<key>Backup</key>
<integer>0</integer>
</map>
<key>MemoryPrivatePoolSize</key> <!-- deprecated (see MAINT-8091) -->
<key>MemoryPrivatePoolSize</key>
<!-- deprecated (see MAINT-8091) -->
<map>
<key>Comment</key>
<string>DEPRECATED: Size of the private memory pool in MB (min. value is 256)</string>
<string>(Deprecated) Size of the private memory pool in MB (min. value is 256)</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
@ -11092,7 +11107,7 @@ Change of this parameter will affect the layout of buttons in notification toast
<key>Type</key>
<string>Boolean</string>
<key>Value</key>
<integer>0</integer>
<integer>1</integer>
</map>
<key>QAMode</key>
<map>
@ -11108,7 +11123,7 @@ Change of this parameter will affect the layout of buttons in notification toast
<key>QAModeEventHostPort</key>
<map>
<key>Comment</key>
<string>DEPRECATED: Port on which lleventhost should listen</string>
<string>(Deprecated) Port on which lleventhost should listen</string>
<key>Persist</key>
<integer>0</integer>
<key>Type</key>
@ -15842,6 +15857,17 @@ Change of this parameter will affect the layout of buttons in notification toast
<key>Backup</key>
<integer>0</integer>
</map>
<key>TextureSaveLocation</key>
<map>
<key>Comment</key>
<string>Current location for bulk saving textures to disk</string>
<key>Persist</key>
<integer>0</integer>
<key>Type</key>
<string>String</string>
<key>Value</key>
<string />
</map>
<key>ThrottleBandwidthKBPS</key>
<map>
<key>Comment</key>
@ -17566,10 +17592,11 @@ Change of this parameter will affect the layout of buttons in notification toast
<key>Value</key>
<string>Default</string>
</map>
<key>UseExternalBrowser</key> <!-- deprecated (see MAINT-4127) -->
<key>UseExternalBrowser</key>
<!-- deprecated (see MAINT-4127) -->
<map>
<key>Comment</key>
<string>Use default browser when opening web pages instead of in-world browser.</string>
<string>(Deprecated) Use default browser when opening web pages instead of in-world browser.</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
@ -18076,6 +18103,7 @@ Change of this parameter will affect the layout of buttons in notification toast
<integer>0</integer>
</map>
<key>VoiceCallsRejectGroup</key>
<!-- deprecated (see SL-12871) -->
<map>
<key>Comment</key>
<string>Silently reject all incoming group voice calls.</string>
@ -22493,17 +22521,6 @@ Change of this parameter will affect the layout of buttons in notification toast
<key>Value</key>
<integer>0</integer>
</map>
<key>FSPlayCollisionSounds</key>
<map>
<key>Comment</key>
<string>Play collision sounds.</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>Boolean</string>
<key>Value</key>
<integer>1</integer>
</map>
<key>FSFadeAudioStream</key>
<map>
<key>Comment</key>
@ -25712,6 +25729,39 @@ Change of this parameter will affect the layout of buttons in notification toast
<key>Value</key>
<integer>0</integer>
</map>
<key>FSTargetFPS</key>
<map>
<key>Comment</key>
<string>Desired minimum FPS</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>U32</string>
<key>Value</key>
<integer>25</integer>
</map>
<key>FSAutoTuneFPS</key>
<map>
<key>Comment</key>
<string>Allow the viewer to adjust your settings to achieve target FPS</string>
<key>Persist</key>
<integer>0</integer>
<key>Type</key>
<string>Boolean</string>
<key>Value</key>
<integer>0</integer>
</map>
<key>FSPerfFloaterSmoothingPeriods</key>
<map>
<key>Comment</key>
<string>Number of periods to smooth the stats over</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>U32</string>
<key>Value</key>
<integer>50</integer>
</map>
<key>FSAutoUnmuteSounds</key>
<map>
<key>Comment</key>
@ -25734,5 +25784,115 @@ Change of this parameter will affect the layout of buttons in notification toast
<key>Value</key>
<integer>0</integer>
</map>
<key>RenderJellyDollsAsImpostors</key>
<map>
<key>Comment</key>
<string>Use an impostor instead of a JellyDoll for better visuals (true)</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>Boolean</string>
<key>Value</key>
<integer>1</integer>
</map>
<key>FSPerfStatsCaptureEnabled</key>
<map>
<key>Comment</key>
<string>Enable/disable render time data to support autotune.</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>Boolean</string>
<key>Value</key>
<integer>1</integer>
</map>
<key>FSAutoTuneImpostorByDistEnabled</key>
<map>
<key>Comment</key>
<string>Enable/disable using MaxNonImpostor to limit avatar rendering by distance.</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>Boolean</string>
<key>Value</key>
<integer>1</integer>
</map>
<key>FSAllowSelfImpostor</key>
<map>
<key>Comment</key>
<string>Allow own render time to impostor your avatar.</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>Boolean</string>
<key>Value</key>
<integer>0</integer>
</map>
<key>FSShowTunedART</key>
<map>
<key>Comment</key>
<string>Show the tuned render time in the avatar display.</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>Boolean</string>
<key>Value</key>
<integer>0</integer>
</map>
<key>FSRenderAvatarMaxART</key>
<map>
<key>Comment</key>
<string>Render Time Limit in microseconds (0.0 = no limit)</string>
<key>Persist</key>
<integer>0</integer>
<key>Type</key>
<string>F32</string>
<key>Value</key>
<real>4.699</real>
</map>
<key>FSAutoTuneRenderFarClipMin</key>
<map>
<key>Comment</key>
<string>The lowest draw distance that auto tune is allowed to use</string>
<key>Persist</key>
<integer>0</integer>
<key>Type</key>
<string>F32</string>
<key>Value</key>
<real>32.0</real>
</map>
<key>FSAutoTuneRenderFarClipTarget</key>
<map>
<key>Comment</key>
<string>The draw distance that auto tune will try to achieve</string>
<key>Persist</key>
<integer>0</integer>
<key>Type</key>
<string>F32</string>
<key>Value</key>
<real>256.0</real>
</map>
<key>FSAutoTuneImpostorFarAwayDistance</key>
<map>
<key>Comment</key>
<string>Avatars beyond this range will automatically be optimized</string>
<key>Persist</key>
<integer>0</integer>
<key>Type</key>
<string>F32</string>
<key>Value</key>
<real>64.0</real>
</map>
<key>FSTuningFPSStrategy</key>
<map>
<key>Comment</key>
<string>Strategy to use when tuning FPS. 0=Tune avatar rendering only, 1=Tune both avatar and global scene settings.</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>U32</string>
<key>Value</key>
<integer>0</integer>
</map>
</map>
</llsd>

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,98 @@
/**
* @file fsfloaterperformance.h
*
* This is forked directly from an early access release of llfloaterperformance.h
*
* $LicenseInfo:firstyear=2021&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2021, Linden Research, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License only.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
#ifndef FS_FLOATERPERFORMANCE_H
#define FS_FLOATERPERFORMANCE_H
#include "llfloater.h"
#include "lllistcontextmenu.h"
class LLCharacter;
class LLNameListCtrl;
class LLComboBox;
class FSFloaterPerformance : public LLFloater
{
public:
FSFloaterPerformance(const LLSD& key);
virtual ~FSFloaterPerformance();
/*virtual*/ BOOL postBuild();
/*virtual*/ void draw();
void showSelectedPanel(LLPanel* selected_panel);
void showMainPanel();
void hidePanels();
void detachItem(const LLUUID& item_id);
void onAvatarListRightClick(LLUICtrl* ctrl, S32 x, S32 y);
void onCustomAction (const LLSD& userdata, const LLUUID& av_id);
bool isActionChecked(const LLSD& userdata, const LLUUID& av_id);
void onExtendedAction(const LLSD& userdata, const LLUUID& av_id);
private:
void initBackBtn(LLPanel* panel);
void populateHUDList();
void populateObjectList();
void populateNearbyList();
void onChangeQuality(const LLSD& data);
void onClickHideAvatars();
void onClickExceptions();
void onClickFocusAvatar();
void updateMaxComplexity();
void updateComplexityText();
void updateMaxRenderTime();
void updateMaxRenderTimeText();
void getNearbyAvatars(std::vector<LLCharacter*> &valid_nearby_avs);
LLPanel* mMainPanel;
LLPanel* mNearbyPanel;
LLPanel* mComplexityPanel;
LLPanel* mHUDsPanel;
LLPanel* mSettingsPanel;
LLPanel* mAutoTunePanel;
LLNameListCtrl* mHUDList;
LLNameListCtrl* mObjectList;
LLNameListCtrl* mNearbyList;
LLComboBox* mNearbyCombo;
LLListContextMenu* mContextMenu;
LLTimer* mUpdateTimer;
S32 mNearbyMaxComplexity;
boost::signals2::connection mComplexityChangedSignal;
boost::signals2::connection mMaxARTChangedSignal;
};
#endif // FS_FLOATERPERFORMANCE_H

View File

@ -0,0 +1,419 @@
/**
* @file fsperfstats.cpp
* @brief Stats collection to support perf floater and auto tune
*
* $LicenseInfo:firstyear=2021&license=fsviewerlgpl$
* Phoenix Firestorm Viewer Source Code
* Copyright (C) 2021, The Phoenix Firestorm Project, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License only.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* The Phoenix Firestorm Project, Inc., 1831 Oakwood Drive, Fairmont, Minnesota 56031-3225 USA
* http://www.firestormviewer.org
* $/LicenseInfo$
*/
#include "llviewerprecompiledheaders.h"
#include "fsperfstats.h"
#include "llcontrol.h"
#include "pipeline.h"
#include "llagentcamera.h"
#include "llvoavatar.h"
#include "llworld.h"
extern LLControlGroup gSavedSettings;
namespace FSPerfStats
{
#ifdef USAGE_TRACKING
std::atomic<int64_t> inUse{0};
std::atomic<int64_t> inUseAvatar{0};
std::atomic<int64_t> inUseScene{0};
std::atomic<int64_t> inUseAttachment{0};
std::atomic<int64_t> inUseAttachmentRigged{0};
std::atomic<int64_t> inUseAttachmentUnRigged{0};
#endif
std::atomic<int64_t> tunedAvatars{0};
U32 targetFPS; // desired FPS
U64 renderAvatarMaxART_ns{(U64)(ART_UNLIMITED_NANOS)}; // highest render time we'll allow without culling features
U32 fpsTuningStrategy{0}; // linked to FSTuningFPSStrategy
U32 lastGlobalPrefChange{0};
std::mutex bufferToggleLock{};
bool autoTune{false};
std::atomic<int> StatsRecorder::writeBuffer{0};
bool StatsRecorder::collectionEnabled{true};
LLUUID StatsRecorder::focusAv{LLUUID::null};
std::array<StatsRecorder::StatsTypeMatrix,2> StatsRecorder::statsDoubleBuffer{ {} };
std::array<StatsRecorder::StatsSummaryArray,2> StatsRecorder::max{ {} };
std::array<StatsRecorder::StatsSummaryArray,2> StatsRecorder::sum{ {} };
StatsRecorder::StatsRecorder():q(1024*16),t(&StatsRecorder::run)
{
// create a queue
// create a thread to consume from the queue
FSPerfStats::targetFPS = gSavedSettings.getU32("FSTargetFPS");
FSPerfStats::autoTune = gSavedSettings.getBOOL("FSAutoTuneFPS");
updateRenderCostLimitFromSettings();
t.detach();
}
// static
void StatsRecorder::toggleBuffer()
{
FSZone;
using ST = StatType_t;
bool unreliable{false};
static LLCachedControl<U32> smoothingPeriods(gSavedSettings, "FSPerfFloaterSmoothingPeriods");
auto& sceneStats = statsDoubleBuffer[writeBuffer][static_cast<size_t>(ObjType_t::OT_GENERAL)][LLUUID::null];
auto& lastStats = statsDoubleBuffer[writeBuffer ^ 1][static_cast<size_t>(ObjType_t::OT_GENERAL)][LLUUID::null];
static constexpr std::initializer_list<StatType_t> 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<StatType_t> avatarStatsToAvg = {
StatType_t::RENDER_GEOMETRY,
StatType_t::RENDER_SHADOWS,
StatType_t::RENDER_COMBINED,
StatType_t::RENDER_IDLE };
if( sceneStats[static_cast<size_t>(StatType_t::RENDER_FPSLIMIT)] != 0 || sceneStats[static_cast<size_t>(StatType_t::RENDER_SLEEP)] != 0 )
{
unreliable = true;
lastStats[static_cast<size_t>(StatType_t::RENDER_FPSLIMIT)] = sceneStats[static_cast<size_t>(StatType_t::RENDER_FPSLIMIT)];
lastStats[static_cast<size_t>(StatType_t::RENDER_SLEEP)] = sceneStats[static_cast<size_t>(StatType_t::RENDER_SLEEP)];
}
if(!unreliable)
{
// only use these stats when things are reliable.
for(auto & statEntry : sceneStatsToAvg)
{
auto avg = lastStats[static_cast<size_t>(statEntry)];
auto val = sceneStats[static_cast<size_t>(statEntry)];
sceneStats[static_cast<size_t>(statEntry)] = avg + (val/smoothingPeriods) - (avg/smoothingPeriods);
// LL_INFOS("scenestats") << "Scenestat: " << static_cast<size_t>(statEntry) << " before=" << avg << " new=" << val << " newavg=" << statsDoubleBuffer[writeBuffer][static_cast<size_t>(ObjType_t::OT_GENERAL)][LLUUID::null][static_cast<size_t>(statEntry)] << LL_ENDL;
}
auto& statsMap = statsDoubleBuffer[writeBuffer][static_cast<size_t>(ObjType_t::OT_ATTACHMENT)];
for(auto& stat_entry : statsMap)
{
auto val = stat_entry.second[static_cast<size_t>(ST::RENDER_COMBINED)];
if(val>smoothingPeriods){
auto avg = statsDoubleBuffer[writeBuffer ^ 1][static_cast<size_t>(ObjType_t::OT_ATTACHMENT)][stat_entry.first][static_cast<size_t>(ST::RENDER_COMBINED)];
stat_entry.second[static_cast<size_t>(ST::RENDER_COMBINED)] = avg + (val/smoothingPeriods) - (avg/smoothingPeriods);
}
}
auto& statsMapAv = statsDoubleBuffer[writeBuffer][static_cast<size_t>(ObjType_t::OT_AVATAR)];
for(auto& stat_entry : statsMapAv)
{
for(auto& stat : avatarStatsToAvg)
{
auto val = stat_entry.second[static_cast<size_t>(stat)];
if(val>smoothingPeriods)
{
auto avg = statsDoubleBuffer[writeBuffer ^ 1][static_cast<size_t>(ObjType_t::OT_AVATAR)][stat_entry.first][static_cast<size_t>(stat)];
stat_entry.second[static_cast<size_t>(stat)] = avg + (val/smoothingPeriods) - (avg/smoothingPeriods);
}
}
}
// swap the buffers
if(enabled())
{
std::lock_guard<std::mutex> 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<size_t>(ST::STATS_COUNT),0);
}
statsMap.clear();
}
for(int i=0; i< static_cast<size_t>(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<size_t>(ST::STATS_COUNT),0);
}
statsMap.clear();
}
for(int i=0; i< static_cast<size_t>(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<std::mutex> 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<size_t>(ST::STATS_COUNT),0);
}
statsMap.clear();
}
for(int i=0; i< static_cast<size_t>(ObjType_t::OT_COUNT); i++)
{
FSZoneN("clear max/sum");
max[writeBuffer][i].fill(0);
sum[writeBuffer][i].fill(0);
}
}
// static
void StatsRecorder::updateSettingsFromRenderCostLimit()
{
static LLCachedControl<F32> maxRenderCost_us(gSavedSettings, "FSRenderAvatarMaxART");
if( (F32)maxRenderCost_us != log10( ( (F32)FSPerfStats::renderAvatarMaxART_ns )/1000 ) )
{
if( FSPerfStats::renderAvatarMaxART_ns != 0 )
{
gSavedSettings.setF32( "FSRenderAvatarMaxART", log10( ( (F32)FSPerfStats::renderAvatarMaxART_ns )/1000 ) );
}
else
{
gSavedSettings.setF32( "FSRenderAvatarMaxART",log10( FSPerfStats::ART_UNLIMITED_NANOS/1000 ) );
}
}
}
// static
void StatsRecorder::updateRenderCostLimitFromSettings()
{
const auto newval = gSavedSettings.getF32("FSRenderAvatarMaxART");
if(newval < log10(FSPerfStats::ART_UNLIMITED_NANOS/1000))
{
FSPerfStats::renderAvatarMaxART_ns = pow(10,newval)*1000;
}
else
{
FSPerfStats::renderAvatarMaxART_ns = 0;
};
}
//static
int StatsRecorder::countNearbyAvatars(S32 distance)
{
const auto our_pos = gAgentCamera.getCameraPositionGlobal();
std::vector<LLVector3d> positions;
uuid_vec_t avatar_ids;
LLWorld::getInstance()->getAvatars(&avatar_ids, &positions, our_pos, distance);
return positions.size();
}
// static
void StatsRecorder::updateAvatarParams()
{
static LLCachedControl<F32> drawDistance(gSavedSettings, "RenderFarClip");
static LLCachedControl<F32> userMinDrawDistance(gSavedSettings, "FSAutoTuneRenderFarClipMin");
static LLCachedControl<F32> userTargetDrawDistance(gSavedSettings, "FSAutoTuneRenderFarClipTarget");
static LLCachedControl<F32> impostorDistance(gSavedSettings, "FSAutoTuneImpostorFarAwayDistance");
static LLCachedControl<bool> impostorDistanceTuning(gSavedSettings, "FSAutoTuneImpostorByDistEnabled");
static LLCachedControl<U32> maxNonImpostors (gSavedSettings, "IndirectMaxNonImpostors");
if(impostorDistanceTuning)
{
// if we have less than the user's "max Non-Impostors" avatars within the desired range then adjust the limit.
// also adjusts back up again for nearby crowds.
auto count = countNearbyAvatars(std::min(drawDistance, impostorDistance));
if( count != maxNonImpostors )
{
gSavedSettings.setU32("IndirectMaxNonImpostors", (count < LLVOAvatar::NON_IMPOSTORS_MAX_SLIDER)?count : LLVOAvatar::NON_IMPOSTORS_MAX_SLIDER);
LL_DEBUGS("AutoTune") << "There are " << count << "avatars within " << std::min(drawDistance, impostorDistance) << "m of the camera" << LL_ENDL;
}
}
auto av_render_max_raw = FSPerfStats::StatsRecorder::getMax(ObjType_t::OT_AVATAR, FSPerfStats::StatType_t::RENDER_COMBINED);
// Is our target frame time lower than current? If so we need to take action to reduce draw overheads.
// cumulative avatar time (includes idle processing, attachments and base av)
auto tot_avatar_time_raw = FSPerfStats::StatsRecorder::getSum(ObjType_t::OT_AVATAR, FSPerfStats::StatType_t::RENDER_COMBINED);
// sleep time is basically forced sleep when window out of focus
auto tot_sleep_time_raw = FSPerfStats::StatsRecorder::getSceneStat(FSPerfStats::StatType_t::RENDER_SLEEP);
// similar to sleep time, induced by FPS limit
auto tot_limit_time_raw = FSPerfStats::StatsRecorder::getSceneStat(FSPerfStats::StatType_t::RENDER_FPSLIMIT);
// the time spent this frame on the "doFrame" call. Treated as "tot time for frame"
auto tot_frame_time_raw = FSPerfStats::StatsRecorder::getSceneStat(FSPerfStats::StatType_t::RENDER_FRAME);
if( tot_sleep_time_raw != 0 )
{
// Note: we do not average sleep
// if at some point we need to, the averaging will need to take this into account or
// we forever think we're in the background due to residuals.
LL_DEBUGS() << "No tuning when not in focus" << LL_ENDL;
return;
}
// The frametime budget we have based on the target FPS selected
auto target_frame_time_raw = (U64)llround((F64)LLTrace::BlockTimer::countsPerSecond()/(targetFPS==0?1:targetFPS));
// LL_INFOS() << "Effective FPS(raw):" << tot_frame_time_raw << " Target:" << target_frame_time_raw << LL_ENDL;
if( tot_limit_time_raw != 0)
{
// This could be problematic.
tot_frame_time_raw -= tot_limit_time_raw;
}
// 1) Is the target frame tim lower than current?
if( target_frame_time_raw <= tot_frame_time_raw )
{
// if so we've got work to do
// how much of the frame was spent on non avatar related work?
U32 non_avatar_time_raw = tot_frame_time_raw - tot_avatar_time_raw;
// If the target frame time < non avatar frame time thne adjusting avatars is only goin gto get us so far.
U64 target_avatar_time_raw;
if(target_frame_time_raw < non_avatar_time_raw)
{
// we cannnot do this by avatar adjustment alone.
if((gFrameCount - FSPerfStats::lastGlobalPrefChange) > 10) // give changes a short time to take effect.
{
if(FSPerfStats::fpsTuningStrategy == 1)
{
// 1 - hack the water to opaque. all non opaque have a significant hit, this is a big boost for (arguably) a minor visual hit.
// the other reflection options make comparatively little change and iof this overshoots we'll be stepping back up later
if(LLPipeline::RenderReflectionDetail != -2)
{
gSavedSettings.setS32("RenderReflectionDetail", -2);
FSPerfStats::lastGlobalPrefChange = gFrameCount;
return;
}
else // deliberately "else" here so we only do these in steps
{
// step down the DD by 10m per update
auto new_dd = (drawDistance-10>userMinDrawDistance)?(drawDistance - 10) : userMinDrawDistance;
if(new_dd != drawDistance)
{
gSavedSettings.setF32("RenderFarClip", new_dd);
FSPerfStats::lastGlobalPrefChange = gFrameCount;
return;
}
}
}
}
target_avatar_time_raw = 0;
}
else
{
// desired avatar budget.
target_avatar_time_raw = target_frame_time_raw - non_avatar_time_raw;
}
if( target_avatar_time_raw < tot_avatar_time_raw )
{
// we need to spend less time drawing avatars to meet our budget
// Note: working in usecs now cos reasons.
auto new_render_limit_ns {renderAvatarMaxART_ns};
// max render this frame may be higher than the last (cos new entrants and jitter) so make sure we are heading in the right direction
if(FSPerfStats::raw_to_ns(av_render_max_raw) < renderAvatarMaxART_ns)
{
new_render_limit_ns = FSPerfStats::raw_to_ns(av_render_max_raw);
}
else
{
new_render_limit_ns = renderAvatarMaxART_ns;
}
new_render_limit_ns -= FSPerfStats::ART_MIN_ADJUST_DOWN_NANOS;
// bounce at the bottom to prevent "no limit"
new_render_limit_ns = std::max((U64)new_render_limit_ns, (U64)FSPerfStats::ART_MINIMUM_NANOS);
// assign the new value
renderAvatarMaxART_ns = new_render_limit_ns;
// LL_DEBUGS() << "AUTO_TUNE: avatar_budget adjusted to:" << new_render_limit_ns << LL_ENDL;
}
// LL_DEBUGS() << "AUTO_TUNE: Target frame time:"<< FSPerfStats::raw_to_us(target_frame_time_raw) << "usecs (non_avatar is " << FSPerfStats::raw_to_us(non_avatar_time_raw) << "usecs) Max cost limited=" << renderAvatarMaxART_ns << LL_ENDL;
}
else if( FSPerfStats::raw_to_ns(target_frame_time_raw) > (FSPerfStats::raw_to_ns(tot_frame_time_raw) + renderAvatarMaxART_ns) )
{
if( FSPerfStats::tunedAvatars >= 0 )
{
// if we have more time to spare let's shift up little in the hope we'll restore an avatar.
renderAvatarMaxART_ns += FSPerfStats::ART_MIN_ADJUST_UP_NANOS;
}
if( drawDistance < userTargetDrawDistance )
{
gSavedSettings.setF32("RenderFarClip", drawDistance + 10.);
}
if( (target_frame_time_raw * 1.5) > tot_frame_time_raw &&
FSPerfStats::tunedAvatars == 0 &&
drawDistance >= userTargetDrawDistance)
{
// if everything else is "max" and we have 50% headroom let's knock the water quality up a notch at a time.
auto water = gSavedSettings.getS32("RenderReflectionDetail");
gSavedSettings.setS32("RenderReflectionDetail", water+1);
}
}
updateSettingsFromRenderCostLimit();
}
}

498
indra/newview/fsperfstats.h Normal file
View File

@ -0,0 +1,498 @@
#pragma once
#ifndef FS_PERFSTATS_H_INCLUDED
#define FS_PERFSTATS_H_INCLUDED
/**
* @file fsperfstats.h
* @brief Statistics collection to support autotune and perf flaoter.
*
* $LicenseInfo:firstyear=2021&license=fsviewerlgpl$
* Phoenix Firestorm Viewer Source Code
* Copyright (C) 2021, The Phoenix Firestorm Project, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License only.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* The Phoenix Firestorm Project, Inc., 1831 Oakwood Drive, Fairmont, Minnesota 56031-3225 USA
* http://www.firestormviewer.org
* $/LicenseInfo$
*/
#include <atomic>
#include <chrono>
#include <array>
#include <unordered_map>
#include <mutex>
#include "lluuid.h"
#include "llfasttimer.h"
#include "blockingconcurrentqueue.h"
#include "llapp.h"
#include "fstelemetry.h"
#include "pipeline.h"
// Additional logging options. These can skew inworld numbers so onyl use for debugging and tracking issues
#ifdef FS_HAS_TELEMETRY_SUPPORT
// USAGE_TRACKING - displays overlapping stats that may imply double counting.
// ATTACHMENT_TRACKING - displays detailed tracking info for Avatar and Attachment. very heavy overhead.
// #define USAGE_TRACKING
// #define ATTACHMENT_TRACKING
#else
#undef USAGE_TRACKING
#undef ATTACHMENT_TRACKING
#endif
extern U32 gFrameCount;
extern LLUUID gAgentID;
namespace FSPerfStats
{
#ifdef USAGE_TRACKING
extern std::atomic<int64_t> inUse;
extern std::atomic<int64_t> inUseAvatar;
extern std::atomic<int64_t> inUseScene;
extern std::atomic<int64_t> inUseAttachment;
extern std::atomic<int64_t> inUseAttachmentRigged;
extern std::atomic<int64_t> inUseAttachmentUnRigged;
#endif
// Note if changing these, they should correspond with the log range of the correpsonding sliders
constexpr U64 ART_UNLIMITED_NANOS{50000000};
constexpr U64 ART_MINIMUM_NANOS{100000};
constexpr U64 ART_MIN_ADJUST_UP_NANOS{10000};
constexpr U64 ART_MIN_ADJUST_DOWN_NANOS{10000};
constexpr F32 PREFERRED_DD{180};
extern std::atomic<int64_t> tunedAvatars;
extern U32 targetFPS; // desired FPS
extern U64 renderAvatarMaxART_ns;
extern U32 fpsTuningStrategy;
extern U32 lastGlobalPrefChange;
extern std::mutex bufferToggleLock;
extern bool autoTune;
enum class ObjType_t{
OT_GENERAL=0, // Also Unknown. Used for n/a type stats such as scenery
OT_AVATAR,
OT_ATTACHMENT,
OT_HUD,
OT_COUNT
};
enum class StatType_t{
RENDER_GEOMETRY=0,
RENDER_SHADOWS,
RENDER_HUDS,
RENDER_UI,
RENDER_COMBINED,
RENDER_SWAP,
RENDER_FRAME,
RENDER_DISPLAY,
RENDER_SLEEP,
RENDER_LFS,
RENDER_MESHREPO,
RENDER_FPSLIMIT,
RENDER_FPS,
RENDER_IDLE,
RENDER_DONE, // toggle buffer & clearbuffer (see processUpdate for hackery)
STATS_COUNT
};
struct StatsRecord
{
StatType_t statType;
ObjType_t objType;
LLUUID avID;
LLUUID objID;
uint64_t time;
bool isRigged;
bool isHUD;
};
class StatsRecorder{
using Queue = moodycamel::BlockingConcurrentQueue<StatsRecord>;
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<size_t>(otype)][id][static_cast<size_t>(type)];
}
static inline uint64_t getSceneStat(StatType_t type)
{
return statsDoubleBuffer[getReadBufferIndex()][static_cast<size_t>(ObjType_t::OT_GENERAL)][LLUUID::null][static_cast<size_t>(type)];
}
static inline uint64_t getSum(ObjType_t otype, StatType_t type)
{
return sum[getReadBufferIndex()][static_cast<size_t>(otype)][static_cast<size_t>(type)];
}
static inline uint64_t getMax(ObjType_t otype, StatType_t type)
{
return max[getReadBufferIndex()][static_cast<size_t>(otype)][static_cast<size_t>(type)];
}
static void updateSettingsFromRenderCostLimit();
static void updateRenderCostLimitFromSettings();
static void updateAvatarParams();
private:
StatsRecorder();
static int countNearbyAvatars(S32 distance);
// StatsArray is a uint64_t for each possible statistic type.
using StatsArray = std::array<uint64_t, static_cast<size_t>(FSPerfStats::StatType_t::STATS_COUNT)>;
using StatsMap = std::unordered_map<LLUUID, StatsArray, FSUUIDHash>;
using StatsTypeMatrix = std::array<StatsMap, static_cast<size_t>(FSPerfStats::ObjType_t::OT_COUNT)>;
using StatsSummaryArray = std::array<StatsArray, static_cast<size_t>(FSPerfStats::ObjType_t::OT_COUNT)>;
static std::atomic<int> writeBuffer;
static LLUUID focusAv;
static std::array<StatsTypeMatrix,2> statsDoubleBuffer;
static std::array<StatsSummaryArray,2> max;
static std::array<StatsSummaryArray,2> sum;
static bool collectionEnabled;
void processUpdate(const StatsRecord& upd)
{
FSZone;
// LL_INFOS("perfstats") << "processing update:" << LL_ENDL;
using ST = StatType_t;
// Note: nullptr is used as the key for global stats
#ifdef FS_HAS_TELEMETRY_SUPPORT
static char avstr[36];
static char obstr[36];
#endif
if(upd.statType == StatType_t::RENDER_DONE && upd.objType == ObjType_t::OT_GENERAL && upd.time == 0)
{
// LL_INFOS("perfstats") << "End of Frame Toggle Buffer:" << gFrameCount << LL_ENDL;
toggleBuffer();
return;
}
if(upd.statType == StatType_t::RENDER_DONE && upd.objType == ObjType_t::OT_GENERAL && upd.time == 1)
{
// LL_INFOS("perfstats") << "New region - clear buffers:" << gFrameCount << LL_ENDL;
clearStatsBuffers();
return;
}
auto ot{upd.objType};
auto& key{upd.objID};
auto& avKey{upd.avID};
auto type {upd.statType};
auto val {upd.time};
#ifdef FS_HAS_TELEMETRY_SUPPORT
FSZoneText(key.toStringFast(obstr),36);
FSZoneText(avKey.toStringFast(avstr),36);
FSZoneValue(val);
#endif
if(ot == ObjType_t::OT_GENERAL)
{
// LL_INFOS("perfstats") << "General update:" << LL_ENDL;
doUpd(key, ot, type,val);
return;
}
if(ot == ObjType_t::OT_AVATAR)
{
// LL_INFOS("perfstats") << "Avatar update:" << LL_ENDL;
doUpd(avKey, ot, type, val);
return;
}
if(ot == ObjType_t::OT_ATTACHMENT)
{
if( !upd.isRigged && !upd.isHUD )
{
// For all attachments that are not rigged we add them to the avatar (for all avatars) cost.
doUpd(avKey, ObjType_t::OT_AVATAR, type, val);
}
if( avKey == focusAv )
{
// For attachments that are for the focusAv (self for now) we record them for the attachment/complexity view
if(upd.isHUD)
{
ot = ObjType_t::OT_HUD;
}
// LL_INFOS("perfstats") << "frame: " << gFrameCount << " Attachment update("<< (type==StatType_t::RENDER_GEOMETRY?"GEOMETRY":"SHADOW") << ": " << key.asString() << " = " << val << LL_ENDL;
doUpd(key, ot, type, val);
}
else
{
// LL_INFOS("perfstats") << "frame: " << gFrameCount << " non-self Att update("<< (type==StatType_t::RENDER_GEOMETRY?"GEOMETRY":"SHADOW") << ": " << key.asString() << " = " << val << " for av " << avKey.asString() << LL_ENDL;
}
}
}
static inline void doUpd(const LLUUID& key, ObjType_t ot, StatType_t type, uint64_t val)
{
FSZone;
using ST = StatType_t;
StatsMap& stm {statsDoubleBuffer[writeBuffer][static_cast<size_t>(ot)]};
auto& thisAsset = stm[key];
thisAsset[static_cast<size_t>(type)] += val;
thisAsset[static_cast<size_t>(ST::RENDER_COMBINED)] += val;
sum[writeBuffer][static_cast<size_t>(ot)][static_cast<size_t>(type)] += val;
sum[writeBuffer][static_cast<size_t>(ot)][static_cast<size_t>(ST::RENDER_COMBINED)] += val;
if(max[writeBuffer][static_cast<size_t>(ot)][static_cast<size_t>(type)] < thisAsset[static_cast<size_t>(type)])
{
max[writeBuffer][static_cast<size_t>(ot)][static_cast<size_t>(type)] = thisAsset[static_cast<size_t>(type)];
}
if(max[writeBuffer][static_cast<size_t>(ot)][static_cast<size_t>(ST::RENDER_COMBINED)] < thisAsset[static_cast<size_t>(ST::RENDER_COMBINED)])
{
max[writeBuffer][static_cast<size_t>(ot)][static_cast<size_t>(ST::RENDER_COMBINED)] = thisAsset[static_cast<size_t>(ST::RENDER_COMBINED)];
}
}
static void toggleBuffer();
static void clearStatsBuffers();
// thread entry
static void run()
{
StatsRecord upd[10];
auto& instance {StatsRecorder::getInstance()};
FSThreadName( "PerfStats" );
while( enabled() && !LLApp::isExiting() )
{
auto count = instance.q.wait_dequeue_bulk_timed(upd, 10, std::chrono::milliseconds(10));
if(count)
{
// LL_INFOS("perfstats") << "processing " << count << " updates." << LL_ENDL;
for(auto i =0; i < count; i++)
{
instance.processUpdate(upd[i]);
}
}
}
}
Queue q;
std::thread t;
~StatsRecorder() = default;
StatsRecorder(const StatsRecorder&) = delete;
StatsRecorder& operator=(const StatsRecorder&) = delete;
};
template <enum ObjType_t ObjTypeDiscriminator>
class RecordTime
{
private:
RecordTime(const RecordTime&) = delete;
RecordTime() = delete;
U64 start;
public:
StatsRecord stat;
RecordTime( const LLUUID& av, const LLUUID& id, StatType_t type, bool isRiggedAtt=false, bool isHUDAtt=false):
start{LLTrace::BlockTimer::getCPUClockCount64()},
stat{type, ObjTypeDiscriminator, std::move(av), std::move(id), 0, isRiggedAtt, isHUDAtt}
{
FSZoneC(tracy::Color::Orange);
#ifdef USAGE_TRACKING
if(stat.objType == FSPerfStats::ObjType_t::OT_ATTACHMENT)
{
if(!stat.isRigged && FSPerfStats::inUseAvatar){FSZoneText("OVERLAP AVATAR",14);}
FSPlotSq("InUse", (int64_t)FSPerfStats::inUse, (int64_t)FSPerfStats::inUse+1);
FSPerfStats::inUse++;
FSPlotSq("InUseAttachment", (int64_t)FSPerfStats::inUseAttachment, (int64_t)FSPerfStats::inUseAttachment+1);
FSPerfStats::inUseAttachment++;
if (stat.isRigged)
{
FSPlotSq("InUseAttachmentRigged", (int64_t)FSPerfStats::inUseAttachmentRigged,(int64_t)FSPerfStats::inUseAttachmentRigged+1);
FSPerfStats::inUseAttachmentRigged++;
}
else
{
FSPlotSq("InUseAttachmentUnRigged", (int64_t)FSPerfStats::inUseAttachmentUnRigged,(int64_t)FSPerfStats::inUseAttachmentUnRigged+1);
FSPerfStats::inUseAttachmentUnRigged++;
}
}
#endif
};
template < ObjType_t OD = ObjTypeDiscriminator,
std::enable_if_t<OD == ObjType_t::OT_GENERAL> * = nullptr>
RecordTime( StatType_t type ):RecordTime<ObjTypeDiscriminator>(LLUUID::null, LLUUID::null, type )
{
FSZone;
#ifdef USAGE_TRACKING
FSPlotSq("InUseScene", (int64_t)FSPerfStats::inUseScene, (int64_t)FSPerfStats::inUseScene+1);
FSPerfStats::inUseScene++;
FSPlotSq("InUse", (int64_t)FSPerfStats::inUse, (int64_t)FSPerfStats::inUse+1);
FSPerfStats::inUse++;
#endif
};
template < ObjType_t OD = ObjTypeDiscriminator,
std::enable_if_t<OD == ObjType_t::OT_AVATAR> * = nullptr>
RecordTime( const LLUUID & av, StatType_t type ):RecordTime<ObjTypeDiscriminator>(std::move(av), LLUUID::null, type)
{
FSZoneC(tracy::Color::Purple);
#ifdef USAGE_TRACKING
if(FSPerfStats::inUseAvatar){FSZoneText("OVERLAP AVATAR",14);}
FSPlotSq("InUseAv", (int64_t)FSPerfStats::inUseAvatar, (int64_t)FSPerfStats::inUseAvatar+1);
FSPerfStats::inUseAvatar++;
FSPlotSq("InUse", (int64_t)FSPerfStats::inUse, (int64_t)FSPerfStats::inUse+1);
FSPerfStats::inUse++;
#endif
};
~RecordTime()
{
if(!FSPerfStats::StatsRecorder::enabled())
{
return;
}
FSZoneC(tracy::Color::Red);
#ifdef USAGE_TRACKING
FSPlotSq("InUse", (int64_t)FSPerfStats::inUse,(int64_t)FSPerfStats::inUse-1);
--FSPerfStats::inUse;
if (stat.objType == FSPerfStats::ObjType_t::OT_ATTACHMENT)
{
FSPlotSq("InUseAttachment", (int64_t)FSPerfStats::inUseAttachment,(int64_t)FSPerfStats::inUseAttachment-1);
--FSPerfStats::inUseAttachment;
if (stat.isRigged)
{
FSPlotSq("InUseAttachmentRigged", (int64_t)FSPerfStats::inUseAttachmentRigged,(int64_t)FSPerfStats::inUseAttachmentRigged-1);
--FSPerfStats::inUseAttachmentRigged;
}
else
{
FSPlotSq("InUseAttachmentUnRigged", (int64_t)FSPerfStats::inUseAttachmentUnRigged,(int64_t)FSPerfStats::inUseAttachmentUnRigged-1);
--FSPerfStats::inUseAttachmentUnRigged;
}
}
if (stat.objType == FSPerfStats::ObjType_t::OT_GENERAL)
{
FSPlotSq("InUseScene", (int64_t)FSPerfStats::inUseScene,(int64_t)FSPerfStats::inUseScene-1);
--FSPerfStats::inUseScene;
}
if( stat.objType == FSPerfStats::ObjType_t::OT_AVATAR )
{
FSPlotSq("InUseAv", (int64_t)FSPerfStats::inUseAvatar, (int64_t)FSPerfStats::inUseAvatar-1);
--FSPerfStats::inUseAvatar;
}
#endif
stat.time = LLTrace::BlockTimer::getCPUClockCount64() - start;
#ifdef ATTACHMENT_TRACKING
static char obstr[36];
static char avstr[36];
FSZoneValue(static_cast<U64>(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<double>(raw) * 1000000000.0) / (F64)LLTrace::BlockTimer::countsPerSecond(); };
inline double raw_to_us(U64 raw) { return (static_cast<double>(raw) * 1000000.0) / (F64)LLTrace::BlockTimer::countsPerSecond(); };
inline double raw_to_ms(U64 raw) { return (static_cast<double>(raw) * 1000.0) / (F64)LLTrace::BlockTimer::countsPerSecond(); };
using RecordSceneTime = RecordTime<ObjType_t::OT_GENERAL>;
using RecordAvatarTime = RecordTime<ObjType_t::OT_AVATAR>;
using RecordAttachmentTime = RecordTime<ObjType_t::OT_ATTACHMENT>;
using RecordHudAttachmentTime = RecordTime<ObjType_t::OT_HUD>;
};// namespace FSPerfStats
// helper functions
using RATptr = std::unique_ptr<FSPerfStats::RecordAttachmentTime>;
template <typename T>
static inline void trackAttachments(const T * vobj, bool isRigged, RATptr* ratPtrp)
{
if( !vobj ){ ratPtrp->reset(); return;};
const T* rootAtt{vobj};
if( rootAtt->isAttachment() )
{
FSZone;
while( !rootAtt->isRootEdit() )
{
rootAtt = (T*)(rootAtt->getParent());
}
auto avPtr = (T*)(rootAtt->getParent());
if(!avPtr){ratPtrp->reset(); return;}
auto& av = avPtr->getID();
auto& obj = rootAtt->getAttachmentItemID();
if(!*ratPtrp || (*ratPtrp)->stat.objID != obj || (*ratPtrp)->stat.avID != av )
{
#if TRACY_ENABLE && defined(ATTACHMENT_TRACKING)
FSZoneNC( "trackAttachments:new", tracy::Color::Red );
auto& str = rootAtt->getAttachmentItemName();
FSZoneText(str.c_str(), str.size());
FSZoneText(isRigged?"Rigged ":"Unrigged",8);
static char avStr[36];
av.toStringFast(avStr);
static char obStr[4];
obj.toShortString(obStr);
FSZoneText( avStr, 36);
FSZoneText( obStr, 4);
#endif
if(*ratPtrp){ratPtrp->reset();}; // deliberately reset to ensure destruction before construction of replacement.
*ratPtrp = std::make_unique<FSPerfStats::RecordAttachmentTime>( av,
obj,
( (LLPipeline::sShadowRender)?FSPerfStats::StatType_t::RENDER_SHADOWS : FSPerfStats::StatType_t::RENDER_GEOMETRY ),
isRigged,
rootAtt->isHUDAttachment());
}
}
return;
};
#endif

View File

@ -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.

Some files were not shown because too many files have changed in this diff Show More