Resolved collisions of merge with siana/master
This commit is contained in:
@@ -1,4 +0,0 @@
|
||||
This is a modified version of openal-soft from GIT (56cc03860378e2758370b773b2a6f1b4e086b49a).
|
||||
The modified source which this was built from is available here:
|
||||
http://viewer-source-downloads.s3.amazonaws.com/install_pkgs/openal-soft-linden-56cc03860378e2758370b773b2a6f1b4e086b49a.tar.bz2
|
||||
|
||||
@@ -672,10 +672,10 @@
|
||||
|
||||
<key>FetchInventoryDescendents</key>
|
||||
<boolean>false</boolean>
|
||||
|
||||
|
||||
<key>WebFetchInventoryDescendents</key>
|
||||
<boolean>true</boolean>
|
||||
|
||||
<boolean>false</boolean>
|
||||
|
||||
<key>FetchInventory</key>
|
||||
<boolean>true</boolean>
|
||||
|
||||
|
||||
@@ -30,6 +30,8 @@ include(Versions)
|
||||
|
||||
include(UnixInstall)
|
||||
|
||||
set (GCC_DISABLE_FATAL_WARNINGS TRUE)
|
||||
|
||||
if (NOT CMAKE_CONFIGURATION_TYPES AND NOT CMAKE_BUILD_TYPE)
|
||||
set(CMAKE_BUILD_TYPE ReleaseSSE2 CACHE STRING
|
||||
"Build type. One of: Debug Release ReleaseSSE2 RelWithDebInfo" FORCE)
|
||||
|
||||
@@ -31,10 +31,10 @@ if (WINDOWS)
|
||||
# Don't build DLLs.
|
||||
set(BUILD_SHARED_LIBS OFF)
|
||||
|
||||
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /Od /Zi /MDd"
|
||||
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /Od /Zi /MDd /arch:SSE2"
|
||||
CACHE STRING "C++ compiler debug options" FORCE)
|
||||
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO
|
||||
"${CMAKE_CXX_FLAGS_RELWITHDEBINFO} /Od /Zi /MD /MP"
|
||||
"${CMAKE_CXX_FLAGS_RELWITHDEBINFO} /Od /Zi /MD /MP /arch:SSE2"
|
||||
CACHE STRING "C++ compiler release-with-debug options" FORCE)
|
||||
set(CMAKE_CXX_FLAGS_RELEASE
|
||||
"${CMAKE_CXX_FLAGS_RELEASE} ${LL_CXX_FLAGS} /O2 /Zi /MD /MP /arch:SSE /fp:fast"
|
||||
@@ -113,7 +113,7 @@ if (WINDOWS)
|
||||
|
||||
endif (WINDOWS)
|
||||
|
||||
set (GCC_EXTRA_OPTIMIZATION "-ffast-math -frounding-math")
|
||||
set (GCC_EXTRA_OPTIMIZATIONS "-ffast-math -frounding-math")
|
||||
|
||||
if (LINUX)
|
||||
set(CMAKE_SKIP_RPATH TRUE)
|
||||
@@ -182,53 +182,29 @@ if (LINUX)
|
||||
-pthread
|
||||
)
|
||||
|
||||
if (SERVER)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -ftemplate-depth-60")
|
||||
if (EXISTS /etc/debian_version)
|
||||
FILE(READ /etc/debian_version DEBIAN_VERSION)
|
||||
else (EXISTS /etc/debian_version)
|
||||
set(DEBIAN_VERSION "")
|
||||
endif (EXISTS /etc/debian_version)
|
||||
|
||||
if (NOT DEBIAN_VERSION STREQUAL "3.1")
|
||||
add_definitions(-DCTYPE_WORKAROUND)
|
||||
endif (NOT DEBIAN_VERSION STREQUAL "3.1")
|
||||
|
||||
if (EXISTS /usr/lib/mysql4/mysql)
|
||||
link_directories(/usr/lib/mysql4/mysql)
|
||||
endif (EXISTS /usr/lib/mysql4/mysql)
|
||||
|
||||
add_definitions(
|
||||
-msse2
|
||||
-mfpmath=sse
|
||||
)
|
||||
endif (SERVER)
|
||||
|
||||
if (VIEWER)
|
||||
add_definitions(-DAPPID=secondlife)
|
||||
add_definitions(-fvisibility=hidden)
|
||||
# don't catch SIGCHLD in our base application class for the viewer - some of our 3rd party libs may need their *own* SIGCHLD handler to work. Sigh! The viewer doesn't need to catch SIGCHLD anyway.
|
||||
add_definitions(-DLL_IGNORE_SIGCHLD)
|
||||
add_definitions(-DAPPID=secondlife)
|
||||
add_definitions(-fvisibility=hidden)
|
||||
# don't catch SIGCHLD in our base application class for the viewer - some of our 3rd party libs may need their *own* SIGCHLD handler to work. Sigh! The viewer doesn't need to catch SIGCHLD anyway.
|
||||
add_definitions(-DLL_IGNORE_SIGCHLD)
|
||||
if (NOT STANDALONE)
|
||||
# this stops us requiring a really recent glibc at runtime
|
||||
add_definitions(-fno-stack-protector)
|
||||
endif (NOT STANDALONE)
|
||||
if (${ARCH} STREQUAL "x86_64")
|
||||
add_definitions(-DLINUX64=1 -pipe)
|
||||
set(CMAKE_CXX_FLAGS_RELEASESSE2 "${CMAKE_CXX_FLAGS_RELEASESSE2} -fomit-frame-pointer -mmmx -msse -mfpmath=sse -msse2 -ffast-math -ftree-vectorize -fweb -fexpensive-optimizations -frename-registers")
|
||||
set(CMAKE_C_FLAGS_RELEASESSE2 "${CMAKE_C_FLAGS_RELEASESSE2} -fomit-frame-pointer -mmmx -msse -mfpmath=sse -msse2 -ffast-math -ftree-vectorize -fweb -fexpensive-optimizations -frename-registers")
|
||||
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} -fomit-frame-pointer -mmmx -msse -mfpmath=sse -msse2 -ffast-math -ftree-vectorize -fweb -fexpensive-optimizations -frename-registers")
|
||||
set(CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO} -fomit-frame-pointer -mmmx -msse -mfpmath=sse -msse2 -ffast-math -ftree-vectorize -fweb -fexpensive-optimizations -frename-registers")
|
||||
else (${ARCH} STREQUAL "x86_64")
|
||||
if (NOT STANDALONE)
|
||||
# this stops us requiring a really recent glibc at runtime
|
||||
add_definitions(-fno-stack-protector)
|
||||
set(MARCH_FLAG " -march=pentium4")
|
||||
endif (NOT STANDALONE)
|
||||
if (${ARCH} STREQUAL "x86_64")
|
||||
add_definitions(-DLINUX64=1 -pipe)
|
||||
set(CMAKE_CXX_FLAGS_RELEASESSE2 "${CMAKE_CXX_FLAGS_RELEASESSE2} -fomit-frame-pointer -mmmx -msse -mfpmath=sse -msse2 -ffast-math -ftree-vectorize -fweb -fexpensive-optimizations -frename-registers")
|
||||
set(CMAKE_C_FLAGS_RELEASESSE2 "${CMAKE_C_FLAGS_RELEASESSE2} -fomit-frame-pointer -mmmx -msse -mfpmath=sse -msse2 -ffast-math -ftree-vectorize -fweb -fexpensive-optimizations -frename-registers")
|
||||
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} -fomit-frame-pointer -mmmx -msse -mfpmath=sse -msse2 -ffast-math -ftree-vectorize -fweb -fexpensive-optimizations -frename-registers")
|
||||
set(CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO} -fomit-frame-pointer -mmmx -msse -mfpmath=sse -msse2 -ffast-math -ftree-vectorize -fweb -fexpensive-optimizations -frename-registers")
|
||||
else (${ARCH} STREQUAL "x86_64")
|
||||
if (NOT STANDALONE)
|
||||
set(MARCH_FLAG " -march=pentium4")
|
||||
endif (NOT STANDALONE)
|
||||
set(CMAKE_CXX_FLAGS_RELEASESSE2 "${CMAKE_CXX_FLAGS_RELEASESSE2}${MARCH_FLAG} -mfpmath=sse -msse2 ${GCC_EXTRA_OPTIMIZATIONS}")
|
||||
set(CMAKE_C_FLAGS_RELEASESSE2 "${CMAKE_C_FLAGS_RELEASESSE2}${MARCH_FLAG} -mfpmath=sse -msse2 "${GCC_EXTRA_OPTIMIZATIONS})
|
||||
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO}${MARCH_FLAG} -mfpmath=sse -msse2 ${GCC_EXTRA_OPTIMIZATIONS}")
|
||||
set(CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO}${MARCH_FLAG} -mfpmath=sse -msse2 "${GCC_EXTRA_OPTIMIZATIONS})
|
||||
endif (${ARCH} STREQUAL "x86_64")
|
||||
endif (VIEWER)
|
||||
set(CMAKE_CXX_FLAGS_RELEASESSE2 "${CMAKE_CXX_FLAGS_RELEASESSE2}${MARCH_FLAG} -mfpmath=sse -msse2 ${GCC_EXTRA_OPTIMIZATIONS}")
|
||||
set(CMAKE_C_FLAGS_RELEASESSE2 "${CMAKE_C_FLAGS_RELEASESSE2}${MARCH_FLAG} -mfpmath=sse -msse2 ${GCC_EXTRA_OPTIMIZATIONS}")
|
||||
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO}${MARCH_FLAG} -mfpmath=sse -msse2 ${GCC_EXTRA_OPTIMIZATIONS}")
|
||||
set(CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO}${MARCH_FLAG} -mfpmath=sse -msse2 ${GCC_EXTRA_OPTIMIZATIONS}")
|
||||
endif (${ARCH} STREQUAL "x86_64")
|
||||
|
||||
set(CMAKE_CXX_FLAGS_DEBUG "-fno-inline ${CMAKE_CXX_FLAGS_DEBUG} -msse2")
|
||||
set(CMAKE_CXX_FLAGS_RELEASE "-O3 ${CMAKE_CXX_FLAGS_RELEASE}")
|
||||
@@ -258,13 +234,13 @@ endif (DARWIN)
|
||||
|
||||
|
||||
if (LINUX OR DARWIN)
|
||||
set(GCC_WARNINGS "-Wall -Wno-sign-compare -Wno-trigraphs -Wno-non-virtual-dtor -Woverloaded-virtual")
|
||||
set(GCC_WARNINGS "-Wall -Wno-sign-compare -Wno-trigraphs")
|
||||
|
||||
if (NOT GCC_DISABLE_FATAL_WARNINGS)
|
||||
set(GCC_WARNINGS "${GCC_WARNINGS} -Werror")
|
||||
endif (NOT GCC_DISABLE_FATAL_WARNINGS)
|
||||
|
||||
set(GCC_CXX_WARNINGS "${GCC_WARNINGS} -Wno-reorder")
|
||||
set(GCC_CXX_WARNINGS "${GCC_WARNINGS} -Wno-reorder -Wno-non-virtual-dtor -Woverloaded-virtual")
|
||||
|
||||
set(CMAKE_C_FLAGS "${GCC_WARNINGS} ${CMAKE_C_FLAGS}")
|
||||
set(CMAKE_CXX_FLAGS "${GCC_CXX_WARNINGS} ${CMAKE_CXX_FLAGS}")
|
||||
@@ -295,12 +271,9 @@ endif (STANDALONE)
|
||||
|
||||
if(1 EQUAL 1)
|
||||
add_definitions(-DOPENSIM_RULES=1)
|
||||
add_definitions(-DMESH_ENABLED=1)
|
||||
endif(1 EQUAL 1)
|
||||
|
||||
if(SERVER)
|
||||
include_directories(${LIBS_PREBUILT_DIR}/include/havok)
|
||||
endif(SERVER)
|
||||
|
||||
SET( CMAKE_EXE_LINKER_FLAGS_RELEASESSE2
|
||||
"${CMAKE_EXE_LINKER_FLAGS_RELEASE}" CACHE STRING
|
||||
"Flags used for linking binaries under SSE2 build."
|
||||
|
||||
@@ -6,6 +6,11 @@ set(DB_FIND_REQUIRED ON)
|
||||
if (STANDALONE)
|
||||
include(FindBerkeleyDB)
|
||||
else (STANDALONE)
|
||||
set(DB_LIBRARIES db-4.2)
|
||||
if (LINUX)
|
||||
# Need to add dependency pthread explicitely to support ld.gold.
|
||||
set(DB_LIBRARIES db-4.2 pthread)
|
||||
else (LINUX)
|
||||
set(DB_LIBRARIES db-4.2)
|
||||
endif (LINUX)
|
||||
set(DB_INCLUDE_DIRS ${LIBS_PREBUILT_DIR}/include)
|
||||
endif (STANDALONE)
|
||||
|
||||
@@ -35,7 +35,7 @@ set(cmake_SOURCE_FILES
|
||||
FindNDOF.cmake
|
||||
FindOpenJPEG.cmake
|
||||
FindXmlRpcEpi.cmake
|
||||
FMOD.cmake
|
||||
FMOD.cmake
|
||||
FreeType.cmake
|
||||
GStreamer010Plugin.cmake
|
||||
GooglePerfTools.cmake
|
||||
@@ -84,6 +84,10 @@ set(cmake_SOURCE_FILES
|
||||
ZLIB.cmake
|
||||
)
|
||||
|
||||
if(FMODEX)
|
||||
list(APPEND cmake_SOURCE_FILES FMODEX.cmake)
|
||||
endif(FMODEX)
|
||||
|
||||
source_group("Shared Rules" FILES ${cmake_SOURCE_FILES})
|
||||
|
||||
set(master_SOURCE_FILES
|
||||
|
||||
@@ -243,12 +243,51 @@ set(all_targets ${all_targets} ${out_targets})
|
||||
set(release_src_dir "${CMAKE_SOURCE_DIR}/../libraries/i686-win32/lib/release")
|
||||
set(release_files
|
||||
libtcmalloc_minimal.dll
|
||||
fmod.dll
|
||||
libhunspell.dll
|
||||
libapr-1.dll
|
||||
libaprutil-1.dll
|
||||
libapriconv-1.dll
|
||||
)
|
||||
|
||||
if(FMODEX)
|
||||
find_path(FMODEX_BINARY_DIR fmodex.dll
|
||||
${release_src_dir}
|
||||
${FMODEX_SDK_DIR}/api
|
||||
${FMODEX_SDK_DIR}
|
||||
)
|
||||
|
||||
if(FMODEX_BINARY_DIR)
|
||||
copy_if_different("${FMODEX_BINARY_DIR}" "${CMAKE_CURRENT_BINARY_DIR}/Release" out_targets fmodex.dll)
|
||||
set(all_targets ${all_targets} ${out_targets})
|
||||
copy_if_different("${FMODEX_BINARY_DIR}" "${CMAKE_CURRENT_BINARY_DIR}/ReleaseSSE2" out_targets fmodex.dll)
|
||||
set(all_targets ${all_targets} ${out_targets})
|
||||
copy_if_different("${FMODEX_BINARY_DIR}" "${CMAKE_CURRENT_BINARY_DIR}/RelWithDebInfo" out_targets fmodex.dll)
|
||||
set(all_targets ${all_targets} ${out_targets})
|
||||
copy_if_different("${FMODEX_BINARY_DIR}" "${CMAKE_CURRENT_BINARY_DIR}/Debug" out_targets fmodex.dll)
|
||||
set(all_targets ${all_targets} ${out_targets})
|
||||
endif(FMODEX_BINARY_DIR)
|
||||
endif(FMODEX)
|
||||
|
||||
if(FMOD)
|
||||
find_path(FMOD_BINARY_DIR fmod.dll
|
||||
${release_src_dir}
|
||||
${FMOD_SDK_DIR}/api
|
||||
${FMOD_SDK_DIR}
|
||||
)
|
||||
|
||||
if(FMOD_BINARY_DIR)
|
||||
copy_if_different("${FMOD_BINARY_DIR}" "${CMAKE_CURRENT_BINARY_DIR}/Release" out_targets fmod.dll)
|
||||
set(all_targets ${all_targets} ${out_targets})
|
||||
copy_if_different("${FMOD_BINARY_DIR}" "${CMAKE_CURRENT_BINARY_DIR}/ReleaseSSE2" out_targets fmod.dll)
|
||||
set(all_targets ${all_targets} ${out_targets})
|
||||
copy_if_different("${FMOD_BINARY_DIR}" "${CMAKE_CURRENT_BINARY_DIR}/RelWithDebInfo" out_targets fmod.dll)
|
||||
set(all_targets ${all_targets} ${out_targets})
|
||||
copy_if_different("${FMOD_BINARY_DIR}" "${CMAKE_CURRENT_BINARY_DIR}/Debug" out_targets fmod.dll)
|
||||
set(all_targets ${all_targets} ${out_targets})
|
||||
else(FMOD_BINARY_DIR)
|
||||
list(APPEND release_files fmod.dll) #Required for compile. This will cause an error in copying binaries.
|
||||
endif(FMOD_BINARY_DIR)
|
||||
endif(FMOD)
|
||||
|
||||
copy_if_different(
|
||||
${release_src_dir}
|
||||
|
||||
@@ -6,6 +6,7 @@ set(install_dir "@CMAKE_SOURCE_DIR@/..")
|
||||
set(scp "@SCP_EXECUTABLE@")
|
||||
set(scripts_dir "@SCRIPTS_DIR@")
|
||||
set(sentinel_dir "@CMAKE_BINARY_DIR@/prepare")
|
||||
set(prebuilt_type "@PREBUILT_TYPE@")
|
||||
|
||||
# In proprietary mode we use scp for download.
|
||||
set(proprietary "@INSTALL_PROPRIETARY@")
|
||||
@@ -19,7 +20,7 @@ foreach(package ${packages})
|
||||
# This package is missing or out of date.
|
||||
message(STATUS "Obtaining${proprietary_message} prebuilt '${package}'")
|
||||
execute_process(
|
||||
COMMAND ${python} install.py --install-dir=${install_dir} ${scp_option} ${package}
|
||||
COMMAND ${python} install.py -p${prebuilt_type} --install-dir=${install_dir} ${scp_option} ${package}
|
||||
WORKING_DIRECTORY ${scripts_dir}
|
||||
RESULT_VARIABLE result
|
||||
)
|
||||
|
||||
83
indra/cmake/FMODEX.cmake
Normal file
83
indra/cmake/FMODEX.cmake
Normal file
@@ -0,0 +1,83 @@
|
||||
# -*- cmake -*-
|
||||
|
||||
include(Linking)
|
||||
|
||||
if(INSTALL_PROPRIETARY)
|
||||
include(Prebuilt)
|
||||
use_prebuilt_binary(fmodex)
|
||||
endif(INSTALL_PROPRIETARY)
|
||||
|
||||
find_library(FMODEX_LIBRARY_RELEASE
|
||||
NAMES fmodex fmodex_vc fmodexL_vc
|
||||
PATHS
|
||||
${ARCH_PREBUILT_DIRS_RELEASE}
|
||||
)
|
||||
|
||||
find_library(FMODEX_LIBRARY_DEBUG
|
||||
NAMES fmodex fmodex_vc fmodexL_vc
|
||||
PATHS
|
||||
${ARCH_PREBUILT_DIRS_DEBUG}
|
||||
)
|
||||
|
||||
if (FMODEX_LIBRARY_RELEASE AND FMODEX_LIBRARY_DEBUG)
|
||||
set(FMODEX_LIBRARY
|
||||
debug ${FMODEX_LIBRARY_DEBUG}
|
||||
optimized ${FMODEX_LIBRARY_RELEASE})
|
||||
elseif (FMODEX_LIBRARY_RELEASE)
|
||||
set(FMODEX_LIBRARY ${FMODEX_LIBRARY_RELEASE})
|
||||
endif (FMODEX_LIBRARY_RELEASE AND FMODEX_LIBRARY_DEBUG)
|
||||
|
||||
if (NOT FMODEX_LIBRARY)
|
||||
set(FMODEX_SDK_DIR CACHE PATH "Path to the FMOD Ex SDK.")
|
||||
if (FMODEX_SDK_DIR)
|
||||
find_library(FMODEX_LIBRARY
|
||||
fmodex fmodex_vc fmodexL_vc
|
||||
PATHS
|
||||
${FMODEX_SDK_DIR}/api/lib
|
||||
${FMODEX_SDK_DIR}/api
|
||||
${FMODEX_SDK_DIR}/lib
|
||||
${FMODEX_SDK_DIR}
|
||||
)
|
||||
|
||||
|
||||
endif(FMODEX_SDK_DIR)
|
||||
if(WINDOWS AND NOT FMODEX_LIBRARY)
|
||||
set(FMODEX_PROG_DIR "$ENV{PROGRAMFILES}/FMOD SoundSystem/FMOD Programmers API Windows")
|
||||
find_library(FMODEX_LIBRARY
|
||||
fmodex_vc fmodexL_vc
|
||||
PATHS
|
||||
${FMODEX_PROG_DIR}/api/lib
|
||||
${FMODEX_PROG_DIR}/api
|
||||
${FMODEX_PROG_DIR}
|
||||
)
|
||||
if(FMODEX_LIBRARY)
|
||||
message(STATUS "Found fmodex in ${FMODEX_PROG_DIR}")
|
||||
set(FMODEX_SDK_DIR ${FMODEX_PROG_DIR})
|
||||
set(FMODEX_SDK_DIR ${FMODEX_PROG_DIR} CACHE PATH "Path to the FMOD Ex SDK." FORCE)
|
||||
endif(FMODEX_LIBRARY)
|
||||
endif(WINDOWS AND NOT FMODEX_LIBRARY)
|
||||
endif (NOT FMODEX_LIBRARY)
|
||||
|
||||
find_path(FMODEX_INCLUDE_DIR fmod.h
|
||||
${LIBS_PREBUILT_DIR}/include/fmodex
|
||||
${LIBS_PREBUILT_DIR}/${LL_ARCH_DIR}/fmodex
|
||||
${FMODEX_SDK_DIR}/api/inc
|
||||
${FMODEX_SDK_DIR}/inc
|
||||
${FMODEX_SDK_DIR}
|
||||
)
|
||||
|
||||
if (FMODEX_LIBRARY AND FMODEX_INCLUDE_DIR)
|
||||
set(FMODEX ON CACHE BOOL "Use closed source FMOD Ex sound library.")
|
||||
else (FMODEX_LIBRARY AND FMODEX_INCLUDE_DIR)
|
||||
set(FMODEX_LIBRARY "")
|
||||
set(FMODEX_INCLUDE_DIR "")
|
||||
if (FMODEX)
|
||||
message(STATUS "No support for FMOD Ex audio (need to set FMODEX_SDK_DIR?)")
|
||||
endif (FMODEX)
|
||||
set(FMODEX OFF CACHE BOOL "Use closed source FMOD Ex sound library.")
|
||||
set(FMODEX OFF)
|
||||
endif (FMODEX_LIBRARY AND FMODEX_INCLUDE_DIR)
|
||||
|
||||
if (FMODEX)
|
||||
message(STATUS "Building with FMOD Ex audio support")
|
||||
endif (FMODEX)
|
||||
@@ -18,4 +18,16 @@ set(LLCOMMON_INCLUDE_DIRS
|
||||
${Boost_INCLUDE_DIRS}
|
||||
)
|
||||
|
||||
set(LLCOMMON_LIBRARIES llcommon)
|
||||
if (LINUX)
|
||||
# In order to support using ld.gold on linux, we need to explicitely
|
||||
# specify all libraries that llcommon uses.
|
||||
# llcommon uses `clock_gettime' which is provided by librt on linux.
|
||||
set(LLCOMMON_LIBRARIES llcommon rt)
|
||||
else (LINUX)
|
||||
set(LLCOMMON_LIBRARIES llcommon)
|
||||
endif (LINUX)
|
||||
|
||||
set(LLCOMMON_LINK_SHARED ON CACHE BOOL "Build the llcommon target as a shared library.")
|
||||
if(LLCOMMON_LINK_SHARED)
|
||||
add_definitions(-DLL_COMMON_LINK_SHARED=1)
|
||||
endif(LLCOMMON_LINK_SHARED)
|
||||
|
||||
@@ -5,4 +5,10 @@ set(LLPLUGIN_INCLUDE_DIRS
|
||||
${LIBS_OPEN_DIR}/llplugin
|
||||
)
|
||||
|
||||
set(LLPLUGIN_LIBRARIES llplugin)
|
||||
if (LINUX)
|
||||
# In order to support using ld.gold on linux, we need to explicitely
|
||||
# specify all libraries that llplugin uses.
|
||||
set(LLPLUGIN_LIBRARIES llplugin pthread)
|
||||
else (LINUX)
|
||||
set(LLPLUGIN_LIBRARIES llplugin)
|
||||
endif (LINUX)
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
# -*- cmake -*-
|
||||
include(Prebuilt)
|
||||
|
||||
if (NOT STANDALONE)
|
||||
use_prebuilt_binary(GL)
|
||||
if (NOT (STANDALONE OR DARWIN))
|
||||
use_prebuilt_binary(glext)
|
||||
# possible glh_linear should have its own .cmake file instead
|
||||
#use_prebuilt_binary(glh_linear)
|
||||
# actually... not any longer, it's now in git -SG
|
||||
set(GLEXT_INCLUDE_DIR ${LIBS_PREBUILT_DIR}/${LL_ARCH_DIR}/include)
|
||||
endif (NOT STANDALONE)
|
||||
set(GLEXT_INCLUDE_DIR ${LIBS_PREBUILT_DIR}/include)
|
||||
endif ()
|
||||
|
||||
@@ -76,24 +76,16 @@ endif (${CMAKE_SYSTEM_NAME} MATCHES "Linux")
|
||||
if (${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
|
||||
set(DARWIN 1)
|
||||
|
||||
# NOTE: If specifying a different SDK with CMAKE_OSX_SYSROOT at configure
|
||||
# time you should also specify CMAKE_OSX_DEPLOYMENT_TARGET explicitly,
|
||||
# otherwise CMAKE_OSX_SYSROOT will be overridden here. We can't just check
|
||||
# for it being unset, as it gets set to the system default :(
|
||||
|
||||
# Default to building against the 10.5 SDK if no deployment target is
|
||||
# specified.
|
||||
if (NOT CMAKE_OSX_DEPLOYMENT_TARGET)
|
||||
# NOTE: setting -isysroot is NOT adequate: http://lists.apple.com/archives/Xcode-users/2007/Oct/msg00696.html
|
||||
# see http://public.kitware.com/Bug/view.php?id=9959 + poppy
|
||||
#SDK Compiler and Deployment targets for XCode
|
||||
if (${XCODE_VERSION} VERSION_LESS 4.0.0)
|
||||
set(CMAKE_OSX_SYSROOT /Developer/SDKs/MacOSX10.5.sdk)
|
||||
set(CMAKE_OSX_DEPLOYMENT_TARGET 10.5)
|
||||
endif (NOT CMAKE_OSX_DEPLOYMENT_TARGET)
|
||||
set(CMAKE_XCODE_ATTIBUTE_GCC_VERSION "4.2")
|
||||
else (${XCODE_VERSION} VERSION_LESS 4.0.0)
|
||||
set(CMAKE_OSX_SYSROOT /Developer/SDKs/MacOSX10.6.sdk)
|
||||
set(CMAKE_XCODE_ATTRIBUTE_GCC_VERSION "com.apple.compilers.llvmgcc42")
|
||||
endif (${XCODE_VERSION} VERSION_LESS 4.0.0)
|
||||
|
||||
# Use GCC 4.2
|
||||
if (${CMAKE_OSX_SYSROOT} MATCHES "10.5")
|
||||
set(CMAKE_XCODE_ATTRIBUTE_GCC_VERSION "4.2")
|
||||
endif (${CMAKE_OSX_SYSROOT} MATCHES "10.5")
|
||||
set(CMAKE_OSX_DEPLOYMENT_TARGET 10.5)
|
||||
|
||||
# NOTE: To attempt an i386/PPC Universal build, add this on the configure line:
|
||||
# -DCMAKE_OSX_ARCHITECTURES:STRING='i386;ppc'
|
||||
@@ -118,6 +110,17 @@ if (${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
|
||||
endif (${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
|
||||
|
||||
|
||||
if (WINDOWS)
|
||||
set(PREBUILT_TYPE windows)
|
||||
elseif(DARWIN)
|
||||
set(PREBUILT_TYPE darwin)
|
||||
elseif(LINUX AND WORD_SIZE EQUAL 32)
|
||||
set(PREBUILT_TYPE linux)
|
||||
elseif(LINUX AND WORD_SIZE EQUAL 64)
|
||||
set(PREBUILT_TYPE linux64)
|
||||
endif(WINDOWS)
|
||||
|
||||
|
||||
# Default deploy grid
|
||||
set(GRID agni CACHE STRING "Target Grid")
|
||||
|
||||
|
||||
@@ -62,13 +62,12 @@ elseif (LINUX)
|
||||
else (STANDALONE)
|
||||
set(WEBKIT_PLUGIN_LIBRARIES
|
||||
llqtwebkit
|
||||
qgif
|
||||
qjpeg
|
||||
QtWebKit
|
||||
QtOpenGL
|
||||
QtNetwork
|
||||
QtGui
|
||||
QtCore
|
||||
jscore
|
||||
jpeg
|
||||
fontconfig
|
||||
X11
|
||||
|
||||
@@ -749,6 +749,7 @@ class CygwinSetup(WindowsSetup):
|
||||
setup_platform = {
|
||||
'darwin': DarwinSetup,
|
||||
'linux2': LinuxSetup,
|
||||
'linux3': LinuxSetup,
|
||||
'win32' : WindowsSetup,
|
||||
'cygwin' : CygwinSetup
|
||||
}
|
||||
@@ -774,9 +775,8 @@ Options:
|
||||
-p | --project=NAME set the root project name. (Doesn't effect makefiles)
|
||||
|
||||
Commands:
|
||||
build configure and build default target
|
||||
clean delete all build directories, does not affect sources
|
||||
configure configure project by running cmake (default command if none given)
|
||||
build configure and build default target
|
||||
clean delete all build directories, does not affect sources
|
||||
configure configure project by running cmake (default if none given)
|
||||
printbuilddirs print the build directory that will be used
|
||||
|
||||
|
||||
@@ -1,105 +1,84 @@
|
||||
# Main CMakeLists.txt to build the OpenJPEG project using CMake (www.cmake.org)
|
||||
# Written by Mathieu Malaterre
|
||||
# -*- cmake -*-
|
||||
|
||||
CMAKE_MINIMUM_REQUIRED(VERSION 2.6)
|
||||
project(openjpeg)
|
||||
|
||||
IF(COMMAND CMAKE_POLICY)
|
||||
CMAKE_POLICY(SET CMP0003 NEW)
|
||||
ENDIF(COMMAND CMAKE_POLICY)
|
||||
include(00-Common)
|
||||
|
||||
PROJECT(openjpeg)
|
||||
|
||||
# Do full dependency headers.
|
||||
INCLUDE_REGULAR_EXPRESSION("^.*$")
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# OPENJPEG version number, useful for packaging and doxygen doc:
|
||||
SET(OPENJPEG_VERSION_MAJOR 1)
|
||||
SET(OPENJPEG_VERSION_MINOR 4)
|
||||
SET(OPENJPEG_VERSION_BUILD 0)
|
||||
SET(OPENJPEG_VERSION
|
||||
set(OPENJPEG_VERSION_MAJOR 1)
|
||||
set(OPENJPEG_VERSION_MINOR 4)
|
||||
set(OPENJPEG_VERSION_BUILD 0)
|
||||
set(OPENJPEG_VERSION
|
||||
"${OPENJPEG_VERSION_MAJOR}.${OPENJPEG_VERSION_MINOR}.${OPENJPEG_VERSION_BUILD}")
|
||||
|
||||
set(openjpeg_SOURCE_FILES
|
||||
bio.c
|
||||
cio.c
|
||||
dwt.c
|
||||
event.c
|
||||
image.c
|
||||
j2k.c
|
||||
j2k_lib.c
|
||||
jp2.c
|
||||
jpt.c
|
||||
mct.c
|
||||
mqc.c
|
||||
openjpeg.c
|
||||
pi.c
|
||||
raw.c
|
||||
t1.c
|
||||
t2.c
|
||||
tcd.c
|
||||
tgt.c
|
||||
)
|
||||
|
||||
set(openjpeg_HEADER_FILES
|
||||
bio.h
|
||||
cio.h
|
||||
dwt.h
|
||||
event.h
|
||||
fix.h
|
||||
image.h
|
||||
int.h
|
||||
j2k.h
|
||||
j2k_lib.h
|
||||
jp2.h
|
||||
jpt.h
|
||||
mct.h
|
||||
mqc.h
|
||||
openjpeg.h
|
||||
opj_includes.h
|
||||
opj_malloc.h
|
||||
pi.h
|
||||
raw.h
|
||||
t1.h
|
||||
t1_luts.h
|
||||
t2.h
|
||||
tcd.h
|
||||
tgt.h
|
||||
)
|
||||
|
||||
IF(WINDOWS)
|
||||
add_definitions(-D_CRT_SECURE_NO_WARNINGS)
|
||||
add_definitions(-DOPJ_STATIC)
|
||||
ENDIF(WINDOWS)
|
||||
|
||||
|
||||
set_source_files_properties(${openjpeg_HEADER_FILES}
|
||||
PROPERTIES HEADER_FILE_ONLY TRUE)
|
||||
|
||||
list(APPEND openjpeg_SOURCE_FILES ${openjpeg_HEADER_FILES})
|
||||
|
||||
add_library (openjpeg ${openjpeg_SOURCE_FILES})
|
||||
|
||||
# This setting of SOVERSION assumes that any API change
|
||||
# will increment either the minor or major version number of openjpeg
|
||||
SET(OPENJPEG_LIBRARY_PROPERTIES
|
||||
set(OPENJPEG_LIBRARY_PROPERTIES
|
||||
VERSION "${OPENJPEG_VERSION_MAJOR}.${OPENJPEG_VERSION_MINOR}.${OPENJPEG_VERSION_BUILD}"
|
||||
SOVERSION "${OPENJPEG_VERSION_MAJOR}.${OPENJPEG_VERSION_MINOR}"
|
||||
)
|
||||
|
||||
# On Visual Studio 8 MS deprecated C. This removes all 1.276E1265 security
|
||||
# warnings
|
||||
IF(WIN32)
|
||||
IF(NOT BORLAND)
|
||||
IF(NOT CYGWIN)
|
||||
IF(NOT MINGW)
|
||||
IF(NOT ITK_ENABLE_VISUAL_STUDIO_DEPRECATED_C_WARNINGS)
|
||||
ADD_DEFINITIONS(
|
||||
-D_CRT_FAR_MAPPINGS_NO_DEPRECATE
|
||||
-D_CRT_IS_WCTYPE_NO_DEPRECATE
|
||||
-D_CRT_MANAGED_FP_NO_DEPRECATE
|
||||
-D_CRT_NONSTDC_NO_DEPRECATE
|
||||
-D_CRT_SECURE_NO_DEPRECATE
|
||||
-D_CRT_SECURE_NO_DEPRECATE_GLOBALS
|
||||
-D_CRT_SETERRORMODE_BEEP_SLEEP_NO_DEPRECATE
|
||||
-D_CRT_TIME_FUNCTIONS_NO_DEPRECATE
|
||||
-D_CRT_VCCLRIT_NO_DEPRECATE
|
||||
-D_SCL_SECURE_NO_DEPRECATE
|
||||
)
|
||||
ENDIF(NOT ITK_ENABLE_VISUAL_STUDIO_DEPRECATED_C_WARNINGS)
|
||||
ENDIF(NOT MINGW)
|
||||
ENDIF(NOT CYGWIN)
|
||||
ENDIF(NOT BORLAND)
|
||||
ENDIF(WIN32)
|
||||
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# Test for some required system information.
|
||||
# INCLUDE (${CMAKE_ROOT}/Modules/CMakeBackwardCompatibilityC.cmake)
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# Compiler specific flags:
|
||||
IF(CMAKE_COMPILER_IS_GNUCC)
|
||||
# For all builds, make sure openjpeg is std99 compliant:
|
||||
# SET(CMAKE_C_FLAGS "-Wall -std=c99 ${CMAKE_C_FLAGS}") # FIXME: this setting prevented us from setting a coverage build.
|
||||
# Do not use ffast-math for all build, it would produce incorrect results, only set for release:
|
||||
SET(CMAKE_C_FLAGS_RELEASE "-ffast-math ${CMAKE_C_FLAGS_RELEASE}")
|
||||
ENDIF(CMAKE_COMPILER_IS_GNUCC)
|
||||
|
||||
# Defines the source code for the library
|
||||
SET(OPENJPEG_SRCS
|
||||
bio.c
|
||||
cio.c
|
||||
dwt.c
|
||||
event.c
|
||||
image.c
|
||||
j2k.c
|
||||
j2k_lib.c
|
||||
jp2.c
|
||||
jpt.c
|
||||
mct.c
|
||||
mqc.c
|
||||
openjpeg.c
|
||||
pi.c
|
||||
raw.c
|
||||
t1.c
|
||||
t2.c
|
||||
tcd.c
|
||||
tgt.c
|
||||
)
|
||||
|
||||
# Pass proper definition to preprocessor to generate shared lib
|
||||
IF(WIN32)
|
||||
IF(BUILD_SHARED_LIBS)
|
||||
ADD_DEFINITIONS(-DOPJ_EXPORTS)
|
||||
ELSE(BUILD_SHARED_LIBS)
|
||||
ADD_DEFINITIONS(-DOPJ_STATIC)
|
||||
ENDIF(BUILD_SHARED_LIBS)
|
||||
ENDIF(WIN32)
|
||||
|
||||
# Create the library
|
||||
ADD_LIBRARY(openjpeg ${OPENJPEG_SRCS})
|
||||
SET_TARGET_PROPERTIES(openjpeg PROPERTIES
|
||||
set_target_properties(openjpeg PROPERTIES
|
||||
${OPENJPEG_LIBRARY_PROPERTIES})
|
||||
|
||||
|
||||
|
||||
@@ -527,7 +527,7 @@ static void dwt_decode_tile(opj_tcd_tilecomp_t* tilec, int numres, DWT1DFN dwt_1
|
||||
|
||||
int w = tilec->x1 - tilec->x0;
|
||||
|
||||
h.mem = opj_aligned_malloc(dwt_decode_max_resolution(tr, numres) * sizeof(int));
|
||||
h.mem = (int *)opj_aligned_malloc(dwt_decode_max_resolution(tr, numres) * sizeof(int));
|
||||
v.mem = h.mem;
|
||||
|
||||
while( --numres) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2005, Herv<EFBFBD> Drolon, FreeImage Team
|
||||
* Copyright (c) 2005, Hervé Drolon, FreeImage Team
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@@ -26,41 +26,6 @@
|
||||
|
||||
#include "opj_includes.h"
|
||||
|
||||
/* ==========================================================
|
||||
Utility functions
|
||||
==========================================================*/
|
||||
|
||||
#if !defined(_MSC_VER) && !defined(__MINGW32__)
|
||||
static char*
|
||||
i2a(unsigned i, char *a, unsigned r) {
|
||||
if (i/r > 0) a = i2a(i/r,a,r);
|
||||
*a = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"[i%r];
|
||||
return a+1;
|
||||
}
|
||||
|
||||
/**
|
||||
Transforms integer i into an ascii string and stores the result in a;
|
||||
string is encoded in the base indicated by r.
|
||||
@param i Number to be converted
|
||||
@param a String result
|
||||
@param r Base of value; must be in the range 2 - 36
|
||||
@return Returns a
|
||||
*/
|
||||
static char *
|
||||
_itoa(int i, char *a, int r) {
|
||||
r = ((r < 2) || (r > 36)) ? 10 : r;
|
||||
if(i < 0) {
|
||||
*a = '-';
|
||||
*i2a(-i, a+1, r) = 0;
|
||||
}
|
||||
else *i2a(i, a, r) = 0;
|
||||
return a;
|
||||
}
|
||||
|
||||
#endif /* !WIN32 */
|
||||
|
||||
/* ----------------------------------------------------------------------- */
|
||||
|
||||
opj_event_mgr_t* OPJ_CALLCONV opj_set_event_mgr(opj_common_ptr cinfo, opj_event_mgr_t *event_mgr, void *context) {
|
||||
if(cinfo) {
|
||||
opj_event_mgr_t *previous = cinfo->event_mgr;
|
||||
|
||||
@@ -236,7 +236,7 @@ static void j2k_read_unk(opj_j2k_t *j2k);
|
||||
/* ----------------------------------------------------------------------- */
|
||||
typedef struct j2k_prog_order{
|
||||
OPJ_PROG_ORDER enum_prog;
|
||||
char str_prog[4];
|
||||
char str_prog[5];
|
||||
}j2k_prog_order_t;
|
||||
|
||||
j2k_prog_order_t j2k_prog_order_list[] = {
|
||||
|
||||
@@ -1,163 +1,163 @@
|
||||
/*
|
||||
* Copyright (c) 2005, Herv<72> Drolon, FreeImage Team
|
||||
* Copyright (c) 2007, Callum Lerwick <seg@haxxed.com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS'
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#ifndef __OPJ_MALLOC_H
|
||||
#define __OPJ_MALLOC_H
|
||||
/**
|
||||
@file opj_malloc.h
|
||||
@brief Internal functions
|
||||
|
||||
The functions in opj_malloc.h are internal utilities used for memory management.
|
||||
*/
|
||||
|
||||
/** @defgroup MISC MISC - Miscellaneous internal functions */
|
||||
/*@{*/
|
||||
|
||||
/** @name Exported functions */
|
||||
/*@{*/
|
||||
/* ----------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
Allocate an uninitialized memory block
|
||||
@param size Bytes to allocate
|
||||
@return Returns a void pointer to the allocated space, or NULL if there is insufficient memory available
|
||||
*/
|
||||
#ifdef ALLOC_PERF_OPT
|
||||
void * OPJ_CALLCONV opj_malloc(size_t size);
|
||||
#else
|
||||
#define opj_malloc(size) malloc(size)
|
||||
#endif
|
||||
|
||||
/**
|
||||
Allocate a memory block with elements initialized to 0
|
||||
@param num Blocks to allocate
|
||||
@param size Bytes per block to allocate
|
||||
@return Returns a void pointer to the allocated space, or NULL if there is insufficient memory available
|
||||
*/
|
||||
#ifdef ALLOC_PERF_OPT
|
||||
void * OPJ_CALLCONV opj_calloc(size_t _NumOfElements, size_t _SizeOfElements);
|
||||
#else
|
||||
#define opj_calloc(num, size) calloc(num, size)
|
||||
#endif
|
||||
|
||||
/**
|
||||
Allocate memory aligned to a 16 byte boundry
|
||||
@param size Bytes to allocate
|
||||
@return Returns a void pointer to the allocated space, or NULL if there is insufficient memory available
|
||||
*/
|
||||
/* FIXME: These should be set with cmake tests, but we're currently not requiring use of cmake */
|
||||
#ifdef WIN32
|
||||
/* Someone should tell the mingw people that their malloc.h ought to provide _mm_malloc() */
|
||||
#ifdef __GNUC__
|
||||
#include <mm_malloc.h>
|
||||
#define HAVE_MM_MALLOC
|
||||
#else /* MSVC, Intel C++ */
|
||||
#include <malloc.h>
|
||||
#ifdef _mm_malloc
|
||||
#define HAVE_MM_MALLOC
|
||||
#endif
|
||||
#endif
|
||||
#else /* Not WIN32 */
|
||||
#if defined(__sun)
|
||||
#define HAVE_MEMALIGN
|
||||
/* Linux x86_64 and OSX always align allocations to 16 bytes */
|
||||
#elif !defined(__amd64__) && !defined(__APPLE__)
|
||||
#define HAVE_MEMALIGN
|
||||
#include <malloc.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#define opj_aligned_malloc(size) malloc(size)
|
||||
#define opj_aligned_free(m) free(m)
|
||||
|
||||
#ifdef HAVE_MM_MALLOC
|
||||
#undef opj_aligned_malloc
|
||||
#define opj_aligned_malloc(size) _mm_malloc(size, 16)
|
||||
#undef opj_aligned_free
|
||||
#define opj_aligned_free(m) _mm_free(m)
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_MEMALIGN
|
||||
extern void* memalign(size_t, size_t);
|
||||
#undef opj_aligned_malloc
|
||||
#define opj_aligned_malloc(size) memalign(16, (size))
|
||||
#undef opj_aligned_free
|
||||
#define opj_aligned_free(m) free(m)
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_POSIX_MEMALIGN
|
||||
#undef opj_aligned_malloc
|
||||
extern int posix_memalign(void**, size_t, size_t);
|
||||
|
||||
static INLINE void* __attribute__ ((malloc)) opj_aligned_malloc(size_t size){
|
||||
void* mem = NULL;
|
||||
posix_memalign(&mem, 16, size);
|
||||
return mem;
|
||||
}
|
||||
#undef opj_aligned_free
|
||||
#define opj_aligned_free(m) free(m)
|
||||
#endif
|
||||
|
||||
#ifdef ALLOC_PERF_OPT
|
||||
#undef opj_aligned_malloc
|
||||
#define opj_aligned_malloc(size) opj_malloc(size)
|
||||
#undef opj_aligned_free
|
||||
#define opj_aligned_free(m) opj_free(m)
|
||||
#endif
|
||||
|
||||
/**
|
||||
Reallocate memory blocks.
|
||||
@param memblock Pointer to previously allocated memory block
|
||||
@param size New size in bytes
|
||||
@return Returns a void pointer to the reallocated (and possibly moved) memory block
|
||||
*/
|
||||
#ifdef ALLOC_PERF_OPT
|
||||
void * OPJ_CALLCONV opj_realloc(void * _Memory, size_t NewSize);
|
||||
#else
|
||||
#define opj_realloc(m, s) realloc(m, s)
|
||||
#endif
|
||||
|
||||
/**
|
||||
Deallocates or frees a memory block.
|
||||
@param memblock Previously allocated memory block to be freed
|
||||
*/
|
||||
#ifdef ALLOC_PERF_OPT
|
||||
void OPJ_CALLCONV opj_free(void * _Memory);
|
||||
#else
|
||||
#define opj_free(m) free(m)
|
||||
#endif
|
||||
|
||||
#ifdef __GNUC__
|
||||
#pragma GCC poison malloc calloc realloc free
|
||||
#endif
|
||||
|
||||
/* ----------------------------------------------------------------------- */
|
||||
/*@}*/
|
||||
|
||||
/*@}*/
|
||||
|
||||
#endif /* __OPJ_MALLOC_H */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2005, Herv<72> Drolon, FreeImage Team
|
||||
* Copyright (c) 2007, Callum Lerwick <seg@haxxed.com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS'
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#ifndef __OPJ_MALLOC_H
|
||||
#define __OPJ_MALLOC_H
|
||||
/**
|
||||
@file opj_malloc.h
|
||||
@brief Internal functions
|
||||
|
||||
The functions in opj_malloc.h are internal utilities used for memory management.
|
||||
*/
|
||||
|
||||
/** @defgroup MISC MISC - Miscellaneous internal functions */
|
||||
/*@{*/
|
||||
|
||||
/** @name Exported functions */
|
||||
/*@{*/
|
||||
/* ----------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
Allocate an uninitialized memory block
|
||||
@param size Bytes to allocate
|
||||
@return Returns a void pointer to the allocated space, or NULL if there is insufficient memory available
|
||||
*/
|
||||
#ifdef ALLOC_PERF_OPT
|
||||
void * OPJ_CALLCONV opj_malloc(size_t size);
|
||||
#else
|
||||
#define opj_malloc(size) malloc(size)
|
||||
#endif
|
||||
|
||||
/**
|
||||
Allocate a memory block with elements initialized to 0
|
||||
@param num Blocks to allocate
|
||||
@param size Bytes per block to allocate
|
||||
@return Returns a void pointer to the allocated space, or NULL if there is insufficient memory available
|
||||
*/
|
||||
#ifdef ALLOC_PERF_OPT
|
||||
void * OPJ_CALLCONV opj_calloc(size_t _NumOfElements, size_t _SizeOfElements);
|
||||
#else
|
||||
#define opj_calloc(num, size) calloc(num, size)
|
||||
#endif
|
||||
|
||||
/**
|
||||
Allocate memory aligned to a 16 byte boundry
|
||||
@param size Bytes to allocate
|
||||
@return Returns a void pointer to the allocated space, or NULL if there is insufficient memory available
|
||||
*/
|
||||
/* FIXME: These should be set with cmake tests, but we're currently not requiring use of cmake */
|
||||
#ifdef WIN32
|
||||
/* Someone should tell the mingw people that their malloc.h ought to provide _mm_malloc() */
|
||||
#ifdef __GNUC__
|
||||
#include <mm_malloc.h>
|
||||
#define HAVE_MM_MALLOC
|
||||
#else /* MSVC, Intel C++ */
|
||||
#include <malloc.h>
|
||||
#ifdef _mm_malloc
|
||||
#define HAVE_MM_MALLOC
|
||||
#endif
|
||||
#endif
|
||||
#else /* Not WIN32 */
|
||||
#if defined(__sun)
|
||||
#define HAVE_MEMALIGN
|
||||
/* Linux x86_64 and OSX always align allocations to 16 bytes */
|
||||
#elif !defined(__amd64__) && !defined(__APPLE__)
|
||||
#define HAVE_MEMALIGN
|
||||
#include <malloc.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#define opj_aligned_malloc(size) malloc(size)
|
||||
#define opj_aligned_free(m) free(m)
|
||||
|
||||
#ifdef HAVE_MM_MALLOC
|
||||
#undef opj_aligned_malloc
|
||||
#define opj_aligned_malloc(size) _mm_malloc(size, 16)
|
||||
#undef opj_aligned_free
|
||||
#define opj_aligned_free(m) _mm_free(m)
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_MEMALIGN
|
||||
extern void* memalign(size_t, size_t);
|
||||
#undef opj_aligned_malloc
|
||||
#define opj_aligned_malloc(size) memalign(16, (size))
|
||||
#undef opj_aligned_free
|
||||
#define opj_aligned_free(m) free(m)
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_POSIX_MEMALIGN
|
||||
#undef opj_aligned_malloc
|
||||
extern int posix_memalign(void**, size_t, size_t);
|
||||
|
||||
static INLINE void* __attribute__ ((malloc)) opj_aligned_malloc(size_t size){
|
||||
void* mem = NULL;
|
||||
posix_memalign(&mem, 16, size);
|
||||
return mem;
|
||||
}
|
||||
#undef opj_aligned_free
|
||||
#define opj_aligned_free(m) free(m)
|
||||
#endif
|
||||
|
||||
#ifdef ALLOC_PERF_OPT
|
||||
#undef opj_aligned_malloc
|
||||
#define opj_aligned_malloc(size) opj_malloc(size)
|
||||
#undef opj_aligned_free
|
||||
#define opj_aligned_free(m) opj_free(m)
|
||||
#endif
|
||||
|
||||
/**
|
||||
Reallocate memory blocks.
|
||||
@param memblock Pointer to previously allocated memory block
|
||||
@param size New size in bytes
|
||||
@return Returns a void pointer to the reallocated (and possibly moved) memory block
|
||||
*/
|
||||
#ifdef ALLOC_PERF_OPT
|
||||
void * OPJ_CALLCONV opj_realloc(void * _Memory, size_t NewSize);
|
||||
#else
|
||||
#define opj_realloc(m, s) realloc(m, s)
|
||||
#endif
|
||||
|
||||
/**
|
||||
Deallocates or frees a memory block.
|
||||
@param memblock Previously allocated memory block to be freed
|
||||
*/
|
||||
#ifdef ALLOC_PERF_OPT
|
||||
void OPJ_CALLCONV opj_free(void * _Memory);
|
||||
#else
|
||||
#define opj_free(m) free(m)
|
||||
#endif
|
||||
|
||||
#ifdef __GNUC__
|
||||
#pragma GCC poison malloc calloc realloc free
|
||||
#endif
|
||||
|
||||
/* ----------------------------------------------------------------------- */
|
||||
/*@}*/
|
||||
|
||||
/*@}*/
|
||||
|
||||
#endif /* __OPJ_MALLOC_H */
|
||||
|
||||
|
||||
@@ -38,7 +38,7 @@ list(APPEND linux_crash_logger_SOURCE_FILES
|
||||
${linux_crash_logger_HEADER_FILES}
|
||||
)
|
||||
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -lrt -lapr-1 -Wl,--as-needed")
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--as-needed")
|
||||
|
||||
add_executable(linux-crash-logger ${linux_crash_logger_SOURCE_FILES})
|
||||
|
||||
@@ -47,11 +47,18 @@ target_link_libraries(linux-crash-logger
|
||||
${LLVFS_LIBRARIES}
|
||||
${LLXML_LIBRARIES}
|
||||
${LLMESSAGE_LIBRARIES}
|
||||
${LLUI_LIBRARIES}
|
||||
${LLVFS_LIBRARIES}
|
||||
${LLMATH_LIBRARIES}
|
||||
${LLCOMMON_LIBRARIES}
|
||||
${UI_LIBRARIES}
|
||||
${DB_LIBRARIES}
|
||||
${XMLRPCEPI_LIBRARIES}
|
||||
${CURL_LIBRARIES}
|
||||
${APR_LIBRARIES}
|
||||
${APRUTIL_LIBRARIES}
|
||||
${CRYPTO_LIBRARIES}
|
||||
rt
|
||||
)
|
||||
|
||||
add_custom_command(
|
||||
|
||||
@@ -5,16 +5,30 @@ project(llaudio)
|
||||
include(00-Common)
|
||||
include(Audio)
|
||||
include(LLAudio)
|
||||
include(FMOD)
|
||||
if(FMODEX)
|
||||
include(FMODEX)
|
||||
if(FMODEX)
|
||||
set(FMOD OFF)
|
||||
endif(FMODEX)
|
||||
endif(FMODEX)
|
||||
if(NOT FMODEX)
|
||||
include(FMOD)
|
||||
endif(NOT FMODEX)
|
||||
include(OPENAL)
|
||||
include(LLCommon)
|
||||
include(LLMath)
|
||||
include(LLMessage)
|
||||
include(LLVFS)
|
||||
|
||||
if(FMODEX)
|
||||
include_directories(${FMODEX_INCLUDE_DIR})
|
||||
endif(FMODEX)
|
||||
if(FMOD)
|
||||
include_directories(${FMOD_INCLUDE_DIR})
|
||||
endif(FMOD)
|
||||
|
||||
include_directories(
|
||||
${LLAUDIO_INCLUDE_DIRS}
|
||||
${FMOD_INCLUDE_DIR}
|
||||
${LLCOMMON_INCLUDE_DIRS}
|
||||
${LLMATH_INCLUDE_DIRS}
|
||||
${LLMESSAGE_INCLUDE_DIRS}
|
||||
@@ -46,6 +60,19 @@ set(llaudio_HEADER_FILES
|
||||
llwindgen.h
|
||||
)
|
||||
|
||||
if (FMODEX)
|
||||
list(APPEND llaudio_SOURCE_FILES
|
||||
llaudioengine_fmodex.cpp
|
||||
lllistener_fmodex.cpp
|
||||
llstreamingaudio_fmodex.cpp
|
||||
)
|
||||
|
||||
list(APPEND llaudio_HEADER_FILES
|
||||
llaudioengine_fmodex.h
|
||||
lllistener_fmodex.h
|
||||
llstreamingaudio_fmodex.h
|
||||
)
|
||||
endif (FMODEX)
|
||||
if (FMOD)
|
||||
list(APPEND llaudio_SOURCE_FILES
|
||||
llaudioengine_fmod.cpp
|
||||
|
||||
782
indra/llaudio/llaudioengine_fmodex.cpp
Normal file
782
indra/llaudio/llaudioengine_fmodex.cpp
Normal file
@@ -0,0 +1,782 @@
|
||||
/**
|
||||
* @file audioengine_FMODEX.cpp
|
||||
* @brief Implementation of LLAudioEngine class abstracting the audio support as a FMOD 3D implementation
|
||||
*
|
||||
* $LicenseInfo:firstyear=2002&license=viewergpl$
|
||||
*
|
||||
* Copyright (c) 2002-2009, Linden Research, Inc.
|
||||
*
|
||||
* Second Life Viewer Source Code
|
||||
* The source code in this file ("Source Code") is provided by Linden Lab
|
||||
* to you under the terms of the GNU General Public License, version 2.0
|
||||
* ("GPL"), unless you have obtained a separate licensing agreement
|
||||
* ("Other License"), formally executed by you and Linden Lab. Terms of
|
||||
* the GPL can be found in doc/GPL-license.txt in this distribution, or
|
||||
* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
|
||||
*
|
||||
* There are special exceptions to the terms and conditions of the GPL as
|
||||
* it is applied to this Source Code. View the full text of the exception
|
||||
* in the file doc/FLOSS-exception.txt in this software distribution, or
|
||||
* online at
|
||||
* http://secondlifegrid.net/programs/open_source/licensing/flossexception
|
||||
*
|
||||
* By copying, modifying or distributing this software, you acknowledge
|
||||
* that you have read and understood your obligations described above,
|
||||
* and agree to abide by those obligations.
|
||||
*
|
||||
* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
|
||||
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
|
||||
* COMPLETENESS OR PERFORMANCE.
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#include "linden_common.h"
|
||||
|
||||
#include "llstreamingaudio.h"
|
||||
#include "llstreamingaudio_fmodex.h"
|
||||
|
||||
#include "llaudioengine_fmodex.h"
|
||||
#include "lllistener_fmodex.h"
|
||||
|
||||
#include "llerror.h"
|
||||
#include "llmath.h"
|
||||
#include "llrand.h"
|
||||
|
||||
#include "fmod.hpp"
|
||||
#include "fmod_errors.h"
|
||||
#include "lldir.h"
|
||||
#include "llapr.h"
|
||||
|
||||
#include "sound_ids.h"
|
||||
|
||||
#if LL_WINDOWS //Some ugly code to make missing fmodex.dll not cause a fatal error.
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include "windows.h"
|
||||
#include <DelayImp.h>
|
||||
#pragma comment(lib, "delayimp.lib")
|
||||
|
||||
bool attemptDelayLoad()
|
||||
{
|
||||
__try
|
||||
{
|
||||
if( FAILED( __HrLoadAllImportsForDll( "fmodex.dll" ) ) )
|
||||
return false;
|
||||
}
|
||||
__except( EXCEPTION_EXECUTE_HANDLER )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
FMOD_RESULT F_CALLBACK windCallback(FMOD_DSP_STATE *dsp_state, float *inbuffer, float *outbuffer, unsigned int length, int inchannels, int outchannels);
|
||||
|
||||
LLAudioEngine_FMODEX::LLAudioEngine_FMODEX(bool enable_profiler)
|
||||
{
|
||||
mInited = false;
|
||||
mWindGen = NULL;
|
||||
mWindDSP = NULL;
|
||||
mSystem = NULL;
|
||||
mEnableProfiler = enable_profiler;
|
||||
}
|
||||
|
||||
|
||||
LLAudioEngine_FMODEX::~LLAudioEngine_FMODEX()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
inline bool Check_FMOD_Error(FMOD_RESULT result, const char *string)
|
||||
{
|
||||
if(result == FMOD_OK)
|
||||
return false;
|
||||
llwarns << string << " Error: " << FMOD_ErrorString(result) << llendl;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LLAudioEngine_FMODEX::init(const S32 num_channels, void* userdata)
|
||||
{
|
||||
|
||||
#if LL_WINDOWS
|
||||
if(!attemptDelayLoad())
|
||||
return false;
|
||||
#endif
|
||||
|
||||
U32 version;
|
||||
FMOD_RESULT result;
|
||||
int numdrivers;
|
||||
FMOD_SPEAKERMODE speakermode;
|
||||
FMOD_CAPS caps;
|
||||
char name[256];
|
||||
|
||||
LL_DEBUGS("AppInit") << "LLAudioEngine_FMODEX::init() initializing FMOD" << LL_ENDL;
|
||||
|
||||
result = FMOD::System_Create(&mSystem);
|
||||
if(Check_FMOD_Error(result, "FMOD::System_Create"))
|
||||
return false;
|
||||
|
||||
//will call LLAudioEngine_FMODEX::allocateListener, which needs a valid mSystem pointer.
|
||||
LLAudioEngine::init(num_channels, userdata);
|
||||
|
||||
result = mSystem->getVersion(&version);
|
||||
Check_FMOD_Error(result, "FMOD::System::getVersion");
|
||||
|
||||
if (version < FMOD_VERSION)
|
||||
{
|
||||
LL_WARNS("AppInit") << "Error : You are using the wrong FMOD version (" << version
|
||||
<< ")! You should be using FMOD " << FMOD_VERSION << LL_ENDL;
|
||||
}
|
||||
|
||||
#if LL_WINDOWS
|
||||
//Is this block applicable to linux?
|
||||
{
|
||||
result = mSystem->getNumDrivers(&numdrivers);
|
||||
Check_FMOD_Error(result, "FMOD::System::getNumDrivers");
|
||||
if (numdrivers == 0)
|
||||
{
|
||||
result = mSystem->setOutput(FMOD_OUTPUTTYPE_NOSOUND);
|
||||
Check_FMOD_Error(result, "FMOD::System::setOutput");
|
||||
}
|
||||
else
|
||||
{
|
||||
result = mSystem->getDriverCaps(0, &caps, 0, &speakermode);
|
||||
Check_FMOD_Error(result,"FMOD::System::getDriverCaps");
|
||||
/*
|
||||
Set the user selected speaker mode.
|
||||
*/
|
||||
result = mSystem->setSpeakerMode(speakermode);
|
||||
Check_FMOD_Error(result, "FMOD::System::setSpeakerMode");
|
||||
if (caps & FMOD_CAPS_HARDWARE_EMULATED)
|
||||
{
|
||||
/*
|
||||
The user has the 'Acceleration' slider set to off! This is really bad
|
||||
for latency! You might want to warn the user about this.
|
||||
*/
|
||||
result = mSystem->setDSPBufferSize(1024, 10);
|
||||
Check_FMOD_Error(result, "FMOD::System::setDSPBufferSize");
|
||||
}
|
||||
result = mSystem->getDriverInfo(0, name, 256, 0);
|
||||
Check_FMOD_Error(result, "FMOD::System::getDriverInfo");
|
||||
|
||||
if (strstr(name, "SigmaTel"))
|
||||
{
|
||||
/*
|
||||
Sigmatel sound devices crackle for some reason if the format is PCM 16bit.
|
||||
PCM floating point output seems to solve it.
|
||||
*/
|
||||
result = mSystem->setSoftwareFormat(48000, FMOD_SOUND_FORMAT_PCMFLOAT, 0,0, FMOD_DSP_RESAMPLER_LINEAR);
|
||||
Check_FMOD_Error(result,"FMOD::System::setSoftwareFormat");
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif //LL_WINDOWS
|
||||
|
||||
// In this case, all sounds, PLUS wind and stream will be software.
|
||||
result = mSystem->setSoftwareChannels(num_channels+2);
|
||||
Check_FMOD_Error(result,"FMOD::System::setSoftwareChannels");
|
||||
|
||||
U32 fmod_flags = FMOD_INIT_NORMAL;
|
||||
if(mEnableProfiler)
|
||||
fmod_flags |= FMOD_INIT_ENABLE_PROFILE;
|
||||
|
||||
#if LL_LINUX
|
||||
// If we don't set an output method, Linux FMOD always
|
||||
// decides on OSS and fails otherwise. So we'll manually
|
||||
// try ESD, then OSS, then ALSA.
|
||||
// Why this order? See SL-13250, but in short, OSS emulated
|
||||
// on top of ALSA is ironically more reliable than raw ALSA.
|
||||
// Ack, and ESD has more reliable failure modes - but has worse
|
||||
// latency - than all of them, so wins for now.
|
||||
bool audio_ok = false;
|
||||
|
||||
if (!audio_ok)
|
||||
{
|
||||
if (NULL == getenv("LL_BAD_FMODEX_ESD")) /*Flawfinder: ignore*/
|
||||
{
|
||||
LL_DEBUGS("AppInit") << "Trying ESD audio output..." << LL_ENDL;
|
||||
if(mSystem->SetOutput(FMOD_OUTPUTTYPE_ESD) == FMOD_OK &&
|
||||
(result = mSystem->init(num_channels, fmod_flags, 0)) == FMOD_OK)
|
||||
{
|
||||
LL_DEBUGS("AppInit") << "ESD audio output initialized OKAY" << LL_ENDL;
|
||||
audio_ok = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
Check_FMOD_Error(result, "ESD audio output FAILED to initialize");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LL_DEBUGS("AppInit") << "ESD audio output SKIPPED" << LL_ENDL;
|
||||
}
|
||||
}
|
||||
if (!audio_ok)
|
||||
{
|
||||
if (NULL == getenv("LL_BAD_FMODEX_OSS")) /*Flawfinder: ignore*/
|
||||
{
|
||||
LL_DEBUGS("AppInit") << "Trying OSS audio output..." << LL_ENDL;
|
||||
if(mSystem->SetOutput(FMOD_OUTPUTTYPE_OSS) == FMOD_OK &&
|
||||
(result = mSystem->init(num_channels, fmod_flags, 0)) == FMOD_OK)
|
||||
{
|
||||
LL_DEBUGS("AppInit") << "OSS audio output initialized OKAY" << LL_ENDL;
|
||||
audio_ok = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
Check_FMOD_Error(result, "OSS audio output FAILED to initialize" << LL_ENDL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LL_DEBUGS("AppInit") << "OSS audio output SKIPPED" << LL_ENDL;
|
||||
}
|
||||
}
|
||||
if (!audio_ok)
|
||||
{
|
||||
if (NULL == getenv("LL_BAD_FMODEX_ALSA")) /*Flawfinder: ignore*/
|
||||
{
|
||||
LL_DEBUGS("AppInit") << "Trying ALSA audio output..." << LL_ENDL;
|
||||
if(mSystem->SetOutput(FMOD_OUTPUTTYPE_ALSA) &&
|
||||
(result = mSystem->init(num_channels, fmod_flags, 0)) == FMOD_OK)
|
||||
{
|
||||
LL_DEBUGS("AppInit") << "ALSA audio output initialized OKAY" << LL_ENDL;
|
||||
audio_ok = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
Check_FMOD_Error(result, "ALSA audio output FAILED to initialize");
|
||||
}
|
||||
} else
|
||||
{
|
||||
LL_DEBUGS("AppInit") << "OSS audio output SKIPPED" << LL_ENDL;
|
||||
}
|
||||
}
|
||||
if (!audio_ok)
|
||||
{
|
||||
LL_WARNS("AppInit") << "Overall audio init failure." << LL_ENDL;
|
||||
return false;
|
||||
}
|
||||
|
||||
// On Linux, FMOD causes a SIGPIPE for some netstream error
|
||||
// conditions (an FMOD bug); ignore SIGPIPE so it doesn't crash us.
|
||||
// NOW FIXED in FMOD 3.x since 2006-10-01.
|
||||
//signal(SIGPIPE, SIG_IGN);
|
||||
|
||||
// We're interested in logging which output method we
|
||||
// ended up with, for QA purposes.
|
||||
FMOD_OUTPUTTYPE output_type;
|
||||
mSystem->getOutput(output_type);
|
||||
switch (output_type)
|
||||
{
|
||||
case FSOUND_OUTPUT_NOSOUND:
|
||||
LL_DEBUGS("AppInit") << "Audio output: NoSound" << LL_ENDL; break;
|
||||
case FSOUND_OUTPUT_OSS:
|
||||
LL_DEBUGS("AppInit") << "Audio output: OSS" << LL_ENDL; break;
|
||||
case FSOUND_OUTPUT_ESD:
|
||||
LL_DEBUGS("AppInit") << "Audio output: ESD" << LL_ENDL; break;
|
||||
case FSOUND_OUTPUT_ALSA:
|
||||
LL_DEBUGS("AppInit") << "Audio output: ALSA" << LL_ENDL; break;
|
||||
default:
|
||||
LL_INFOS("AppInit") << "Audio output: Unknown!" << LL_ENDL; break;
|
||||
};
|
||||
#else // LL_LINUX
|
||||
|
||||
// initialize the FMOD engine
|
||||
result = mSystem->init( num_channels + 2, fmod_flags, 0);
|
||||
if (result == FMOD_ERR_OUTPUT_CREATEBUFFER)
|
||||
{
|
||||
/*
|
||||
Ok, the speaker mode selected isn't supported by this soundcard. Switch it
|
||||
back to stereo...
|
||||
*/
|
||||
result = mSystem->setSpeakerMode(FMOD_SPEAKERMODE_STEREO);
|
||||
Check_FMOD_Error(result,"Error falling back to stereo mode");
|
||||
/*
|
||||
... and re-init.
|
||||
*/
|
||||
result = mSystem->init(100, FMOD_INIT_NORMAL, 0);
|
||||
}
|
||||
if(Check_FMOD_Error(result, "Error initializing FMOD"))
|
||||
return false;
|
||||
#endif
|
||||
|
||||
// set up our favourite FMOD-native streaming audio implementation if none has already been added
|
||||
if (!getStreamingAudioImpl()) // no existing implementation added
|
||||
setStreamingAudioImpl(new LLStreamingAudio_FMODEX(mSystem));
|
||||
|
||||
LL_DEBUGS("AppInit") << "LLAudioEngine_FMODEX::init() FMOD initialized correctly" << LL_ENDL;
|
||||
|
||||
mInited = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
std::string LLAudioEngine_FMODEX::getDriverName(bool verbose)
|
||||
{
|
||||
llassert_always(mSystem);
|
||||
if (verbose)
|
||||
{
|
||||
U32 version;
|
||||
if(!Check_FMOD_Error(mSystem->getVersion(&version), "FMOD::System::getVersion"))
|
||||
{
|
||||
return llformat("FMOD version %1x.%02x.%02x", version >> 16, version >> 8 & 0x000000FF, version & 0x000000FF);
|
||||
}
|
||||
}
|
||||
return "FMOD";
|
||||
}
|
||||
|
||||
|
||||
void LLAudioEngine_FMODEX::allocateListener(void)
|
||||
{
|
||||
mListenerp = (LLListener *) new LLListener_FMODEX(mSystem);
|
||||
if (!mListenerp)
|
||||
{
|
||||
llwarns << "Listener creation failed" << llendl;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void LLAudioEngine_FMODEX::shutdown()
|
||||
{
|
||||
stopInternetStream();
|
||||
|
||||
LLAudioEngine::shutdown();
|
||||
|
||||
llinfos << "LLAudioEngine_FMODEX::shutdown() closing FMOD" << llendl;
|
||||
mSystem->close();
|
||||
mSystem->release();
|
||||
llinfos << "LLAudioEngine_FMODEX::shutdown() done closing FMOD" << llendl;
|
||||
|
||||
delete mListenerp;
|
||||
mListenerp = NULL;
|
||||
}
|
||||
|
||||
|
||||
LLAudioBuffer * LLAudioEngine_FMODEX::createBuffer()
|
||||
{
|
||||
return new LLAudioBufferFMODEX(mSystem);
|
||||
}
|
||||
|
||||
|
||||
LLAudioChannel * LLAudioEngine_FMODEX::createChannel()
|
||||
{
|
||||
return new LLAudioChannelFMODEX(mSystem);
|
||||
}
|
||||
|
||||
bool LLAudioEngine_FMODEX::initWind()
|
||||
{
|
||||
mNextWindUpdate = 0.0;
|
||||
|
||||
if (!mWindDSP)
|
||||
{
|
||||
FMOD_DSP_DESCRIPTION dspdesc;
|
||||
memset(&dspdesc, 0, sizeof(FMOD_DSP_DESCRIPTION)); //Set everything to zero
|
||||
strncpy(dspdesc.name,"Wind Unit", sizeof(dspdesc.name)); //Set name to "Wind Unit"
|
||||
dspdesc.read = &windCallback; //Assign callback.
|
||||
if(Check_FMOD_Error(mSystem->createDSP(&dspdesc, &mWindDSP), "FMOD::createDSP"))
|
||||
return false;
|
||||
|
||||
if(mWindGen)
|
||||
delete mWindGen;
|
||||
|
||||
float frequency = 44100;
|
||||
mWindDSP->getDefaults(&frequency,0,0,0);
|
||||
mWindGen = new LLWindGen<MIXBUFFERFORMAT>((U32)frequency);
|
||||
mWindDSP->setUserData((void*)mWindGen);
|
||||
}
|
||||
|
||||
if (mWindDSP)
|
||||
{
|
||||
mSystem->playDSP(FMOD_CHANNEL_FREE, mWindDSP, false, 0);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void LLAudioEngine_FMODEX::cleanupWind()
|
||||
{
|
||||
if (mWindDSP)
|
||||
{
|
||||
mWindDSP->remove();
|
||||
mWindDSP->release();
|
||||
mWindDSP = NULL;
|
||||
}
|
||||
|
||||
delete mWindGen;
|
||||
mWindGen = NULL;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
void LLAudioEngine_FMODEX::updateWind(LLVector3 wind_vec, F32 camera_height_above_water)
|
||||
{
|
||||
LLVector3 wind_pos;
|
||||
F64 pitch;
|
||||
F64 center_freq;
|
||||
|
||||
if (!mEnableWind)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (mWindUpdateTimer.checkExpirationAndReset(LL_WIND_UPDATE_INTERVAL))
|
||||
{
|
||||
|
||||
// wind comes in as Linden coordinate (+X = forward, +Y = left, +Z = up)
|
||||
// need to convert this to the conventional orientation DS3D and OpenAL use
|
||||
// where +X = right, +Y = up, +Z = backwards
|
||||
|
||||
wind_vec.setVec(-wind_vec.mV[1], wind_vec.mV[2], -wind_vec.mV[0]);
|
||||
|
||||
// cerr << "Wind update" << endl;
|
||||
|
||||
pitch = 1.0 + mapWindVecToPitch(wind_vec);
|
||||
center_freq = 80.0 * pow(pitch,2.5*(mapWindVecToGain(wind_vec)+1.0));
|
||||
|
||||
mWindGen->mTargetFreq = (F32)center_freq;
|
||||
mWindGen->mTargetGain = (F32)mapWindVecToGain(wind_vec) * mMaxWindGain;
|
||||
mWindGen->mTargetPanGainR = (F32)mapWindVecToPan(wind_vec);
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
void LLAudioEngine_FMODEX::setInternalGain(F32 gain)
|
||||
{
|
||||
if (!mInited)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
gain = llclamp( gain, 0.0f, 1.0f );
|
||||
|
||||
FMOD::ChannelGroup *master_group;
|
||||
mSystem->getMasterChannelGroup(&master_group);
|
||||
|
||||
master_group->setVolume(gain);
|
||||
|
||||
LLStreamingAudioInterface *saimpl = getStreamingAudioImpl();
|
||||
if ( saimpl )
|
||||
{
|
||||
// fmod likes its streaming audio channel gain re-asserted after
|
||||
// master volume change.
|
||||
saimpl->setGain(saimpl->getGain());
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// LLAudioChannelFMODEX implementation
|
||||
//
|
||||
|
||||
LLAudioChannelFMODEX::LLAudioChannelFMODEX(FMOD::System *system) : LLAudioChannel(), mSystemp(system), mChannelp(NULL), mLastSamplePos(0)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
LLAudioChannelFMODEX::~LLAudioChannelFMODEX()
|
||||
{
|
||||
cleanup();
|
||||
}
|
||||
|
||||
bool LLAudioChannelFMODEX::updateBuffer()
|
||||
{
|
||||
if (LLAudioChannel::updateBuffer())
|
||||
{
|
||||
// Base class update returned true, which means that we need to actually
|
||||
// set up the channel for a different buffer.
|
||||
|
||||
LLAudioBufferFMODEX *bufferp = (LLAudioBufferFMODEX *)mCurrentSourcep->getCurrentBuffer();
|
||||
|
||||
// Grab the FMOD sample associated with the buffer
|
||||
FMOD::Sound *soundp = bufferp->getSound();
|
||||
if (!soundp)
|
||||
{
|
||||
// This is bad, there should ALWAYS be a sound associated with a legit
|
||||
// buffer.
|
||||
llerrs << "No FMOD sound!" << llendl;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// Actually play the sound. Start it off paused so we can do all the necessary
|
||||
// setup.
|
||||
if(!mChannelp)
|
||||
{
|
||||
FMOD_RESULT result = getSystem()->playSound(FMOD_CHANNEL_FREE, soundp, true, &mChannelp);
|
||||
Check_FMOD_Error(result, "FMOD::System::playSound");
|
||||
}
|
||||
|
||||
//llinfos << "Setting up channel " << std::hex << mChannelID << std::dec << llendl;
|
||||
}
|
||||
|
||||
// If we have a source for the channel, we need to update its gain.
|
||||
if (mCurrentSourcep)
|
||||
{
|
||||
// SJB: warnings can spam and hurt framerate, disabling
|
||||
FMOD_RESULT result;
|
||||
|
||||
result = mChannelp->setVolume(getSecondaryGain() * mCurrentSourcep->getGain());
|
||||
//Check_FMOD_Error(result, "FMOD::Channel::setVolume");
|
||||
|
||||
result = mChannelp->setMode(mCurrentSourcep->isLoop() ? FMOD_LOOP_NORMAL : FMOD_LOOP_OFF);
|
||||
/*if(Check_FMOD_Error(result, "FMOD::Channel::setMode"))
|
||||
{
|
||||
S32 index;
|
||||
mChannelp->getIndex(&index);
|
||||
llwarns << "Channel " << index << "Source ID: " << mCurrentSourcep->getID()
|
||||
<< " at " << mCurrentSourcep->getPositionGlobal() << llendl;
|
||||
}*/
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void LLAudioChannelFMODEX::update3DPosition()
|
||||
{
|
||||
if (!mChannelp)
|
||||
{
|
||||
// We're not actually a live channel (i.e., we're not playing back anything)
|
||||
return;
|
||||
}
|
||||
|
||||
LLAudioBufferFMODEX *bufferp = (LLAudioBufferFMODEX *)mCurrentBufferp;
|
||||
if (!bufferp)
|
||||
{
|
||||
// We don't have a buffer associated with us (should really have been picked up
|
||||
// by the above if.
|
||||
return;
|
||||
}
|
||||
|
||||
if (mCurrentSourcep->isAmbient())
|
||||
{
|
||||
// Ambient sound, don't need to do any positional updates.
|
||||
set3DMode(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Localized sound. Update the position and velocity of the sound.
|
||||
set3DMode(true);
|
||||
|
||||
LLVector3 float_pos;
|
||||
float_pos.setVec(mCurrentSourcep->getPositionGlobal());
|
||||
FMOD_RESULT result = mChannelp->set3DAttributes((FMOD_VECTOR*)float_pos.mV, (FMOD_VECTOR*)mCurrentSourcep->getVelocity().mV);
|
||||
Check_FMOD_Error(result, "FMOD::Channel::set3DAttributes");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void LLAudioChannelFMODEX::updateLoop()
|
||||
{
|
||||
if (!mChannelp)
|
||||
{
|
||||
// May want to clear up the loop/sample counters.
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
// Hack: We keep track of whether we looped or not by seeing when the
|
||||
// sample position looks like it's going backwards. Not reliable; may
|
||||
// yield false negatives.
|
||||
//
|
||||
U32 cur_pos;
|
||||
mChannelp->getPosition(&cur_pos,FMOD_TIMEUNIT_PCMBYTES);
|
||||
|
||||
if (cur_pos < (U32)mLastSamplePos)
|
||||
{
|
||||
mLoopedThisFrame = true;
|
||||
}
|
||||
mLastSamplePos = cur_pos;
|
||||
}
|
||||
|
||||
|
||||
void LLAudioChannelFMODEX::cleanup()
|
||||
{
|
||||
if (!mChannelp)
|
||||
{
|
||||
//llinfos << "Aborting cleanup with no channel handle." << llendl;
|
||||
return;
|
||||
}
|
||||
|
||||
//llinfos << "Cleaning up channel: " << mChannelID << llendl;
|
||||
Check_FMOD_Error(mChannelp->stop(),"FMOD::Channel::stop");
|
||||
|
||||
mCurrentBufferp = NULL;
|
||||
mChannelp = NULL;
|
||||
}
|
||||
|
||||
|
||||
void LLAudioChannelFMODEX::play()
|
||||
{
|
||||
if (!mChannelp)
|
||||
{
|
||||
llwarns << "Playing without a channel handle, aborting" << llendl;
|
||||
return;
|
||||
}
|
||||
|
||||
Check_FMOD_Error(mChannelp->setPaused(false), "FMOD::Channel::pause");
|
||||
|
||||
getSource()->setPlayedOnce(true);
|
||||
}
|
||||
|
||||
|
||||
void LLAudioChannelFMODEX::playSynced(LLAudioChannel *channelp)
|
||||
{
|
||||
LLAudioChannelFMODEX *fmod_channelp = (LLAudioChannelFMODEX*)channelp;
|
||||
if (!(fmod_channelp->mChannelp && mChannelp))
|
||||
{
|
||||
// Don't have channels allocated to both the master and the slave
|
||||
return;
|
||||
}
|
||||
|
||||
U32 cur_pos;
|
||||
if(Check_FMOD_Error(mChannelp->getPosition(&cur_pos,FMOD_TIMEUNIT_PCMBYTES), "Unable to retrieve current position"))
|
||||
return;
|
||||
|
||||
cur_pos %= mCurrentBufferp->getLength();
|
||||
|
||||
// Try to match the position of our sync master
|
||||
Check_FMOD_Error(mChannelp->setPosition(cur_pos,FMOD_TIMEUNIT_PCMBYTES),"Unable to set current position");
|
||||
|
||||
// Start us playing
|
||||
play();
|
||||
}
|
||||
|
||||
|
||||
bool LLAudioChannelFMODEX::isPlaying()
|
||||
{
|
||||
if (!mChannelp)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool paused, playing;
|
||||
mChannelp->getPaused(&paused);
|
||||
mChannelp->isPlaying(&playing);
|
||||
return !paused && playing;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// LLAudioChannelFMODEX implementation
|
||||
//
|
||||
|
||||
|
||||
LLAudioBufferFMODEX::LLAudioBufferFMODEX(FMOD::System *system) : mSystemp(system), mSoundp(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
LLAudioBufferFMODEX::~LLAudioBufferFMODEX()
|
||||
{
|
||||
if(mSoundp)
|
||||
{
|
||||
mSoundp->release();
|
||||
mSoundp = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool LLAudioBufferFMODEX::loadWAV(const std::string& filename)
|
||||
{
|
||||
// Try to open a wav file from disk. This will eventually go away, as we don't
|
||||
// really want to block doing this.
|
||||
if (filename.empty())
|
||||
{
|
||||
// invalid filename, abort.
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!LLAPRFile::isExist(filename, LL_APR_RPB))
|
||||
{
|
||||
// File not found, abort.
|
||||
return false;
|
||||
}
|
||||
|
||||
if (mSoundp)
|
||||
{
|
||||
// If there's already something loaded in this buffer, clean it up.
|
||||
mSoundp->release();
|
||||
mSoundp = NULL;
|
||||
}
|
||||
|
||||
FMOD_MODE base_mode = FMOD_LOOP_NORMAL | FMOD_SOFTWARE;
|
||||
FMOD_CREATESOUNDEXINFO exinfo;
|
||||
memset(&exinfo,0,sizeof(exinfo));
|
||||
exinfo.cbsize = sizeof(exinfo);
|
||||
exinfo.suggestedsoundtype = FMOD_SOUND_TYPE_WAV; //Hint to speed up loading.
|
||||
// Load up the wav file into an fmod sample
|
||||
#if LL_WINDOWS
|
||||
FMOD_RESULT result = getSystem()->createSound((const char*)utf8str_to_utf16str(filename).c_str(), base_mode | FMOD_UNICODE, &exinfo, &mSoundp);
|
||||
#else
|
||||
FMOD_RESULT result = getSystem()->createSound(filename.c_str(), base_mode, &exinfo, &mSoundp);
|
||||
#endif
|
||||
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
// We failed to load the file for some reason.
|
||||
llwarns << "Could not load data '" << filename << "': " << FMOD_ErrorString(result) << llendl;
|
||||
|
||||
//
|
||||
// If we EVER want to load wav files provided by end users, we need
|
||||
// to rethink this!
|
||||
//
|
||||
// file is probably corrupt - remove it.
|
||||
LLFile::remove(filename);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Everything went well, return true
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
U32 LLAudioBufferFMODEX::getLength()
|
||||
{
|
||||
if (!mSoundp)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
U32 length;
|
||||
mSoundp->getLength(&length, FMOD_TIMEUNIT_PCMBYTES);
|
||||
return length;
|
||||
}
|
||||
|
||||
|
||||
void LLAudioChannelFMODEX::set3DMode(bool use3d)
|
||||
{
|
||||
FMOD_MODE current_mode;
|
||||
if(mChannelp->getMode(¤t_mode) != FMOD_OK)
|
||||
return;
|
||||
FMOD_MODE new_mode = current_mode;
|
||||
new_mode &= ~(use3d ? FMOD_2D : FMOD_3D);
|
||||
new_mode |= use3d ? FMOD_3D : FMOD_2D;
|
||||
|
||||
if(current_mode != new_mode)
|
||||
{
|
||||
mChannelp->setMode(new_mode);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
FMOD_RESULT F_CALLBACK windCallback(FMOD_DSP_STATE *dsp_state, float *originalbuffer, float *newbuffer, unsigned int length, int inchannels, int outchannels)
|
||||
{
|
||||
// originalbuffer = fmod's original mixbuffer.
|
||||
// newbuffer = the buffer passed from the previous DSP unit.
|
||||
// length = length in samples at this mix time.
|
||||
// userdata = user parameter passed through in FSOUND_DSP_Create.
|
||||
|
||||
LLWindGen<LLAudioEngine_FMODEX::MIXBUFFERFORMAT> *windgen;
|
||||
FMOD::DSP *thisdsp = (FMOD::DSP *)dsp_state->instance;
|
||||
|
||||
thisdsp->getUserData((void **)&windgen);
|
||||
S32 channels, configwidth, configheight;
|
||||
thisdsp->getInfo(0, 0, &channels, &configwidth, &configheight);
|
||||
|
||||
windgen->windGenerate((LLAudioEngine_FMODEX::MIXBUFFERFORMAT *)newbuffer, length);
|
||||
|
||||
return FMOD_OK;
|
||||
}
|
||||
131
indra/llaudio/llaudioengine_fmodex.h
Normal file
131
indra/llaudio/llaudioengine_fmodex.h
Normal file
@@ -0,0 +1,131 @@
|
||||
/**
|
||||
* @file audioengine_FMODEX.h
|
||||
* @brief Definition of LLAudioEngine class abstracting the audio
|
||||
* support as a FMOD 3D implementation
|
||||
*
|
||||
* $LicenseInfo:firstyear=2002&license=viewergpl$
|
||||
*
|
||||
* Copyright (c) 2002-2009, Linden Research, Inc.
|
||||
*
|
||||
* Second Life Viewer Source Code
|
||||
* The source code in this file ("Source Code") is provided by Linden Lab
|
||||
* to you under the terms of the GNU General Public License, version 2.0
|
||||
* ("GPL"), unless you have obtained a separate licensing agreement
|
||||
* ("Other License"), formally executed by you and Linden Lab. Terms of
|
||||
* the GPL can be found in doc/GPL-license.txt in this distribution, or
|
||||
* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
|
||||
*
|
||||
* There are special exceptions to the terms and conditions of the GPL as
|
||||
* it is applied to this Source Code. View the full text of the exception
|
||||
* in the file doc/FLOSS-exception.txt in this software distribution, or
|
||||
* online at
|
||||
* http://secondlifegrid.net/programs/open_source/licensing/flossexception
|
||||
*
|
||||
* By copying, modifying or distributing this software, you acknowledge
|
||||
* that you have read and understood your obligations described above,
|
||||
* and agree to abide by those obligations.
|
||||
*
|
||||
* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
|
||||
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
|
||||
* COMPLETENESS OR PERFORMANCE.
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#ifndef LL_AUDIOENGINE_FMODEX_H
|
||||
#define LL_AUDIOENGINE_FMODEX_H
|
||||
|
||||
#include "llaudioengine.h"
|
||||
#include "lllistener_fmod.h"
|
||||
#include "llwindgen.h"
|
||||
|
||||
//Stubs
|
||||
class LLAudioStreamManagerFMODEX;
|
||||
namespace FMOD
|
||||
{
|
||||
class System;
|
||||
class Channel;
|
||||
class Sound;
|
||||
class DSP;
|
||||
}
|
||||
|
||||
//Interfaces
|
||||
class LLAudioEngine_FMODEX : public LLAudioEngine
|
||||
{
|
||||
public:
|
||||
LLAudioEngine_FMODEX(bool enable_profiler);
|
||||
virtual ~LLAudioEngine_FMODEX();
|
||||
|
||||
// initialization/startup/shutdown
|
||||
virtual bool init(const S32 num_channels, void *user_data);
|
||||
virtual std::string getDriverName(bool verbose);
|
||||
virtual void allocateListener();
|
||||
|
||||
virtual void shutdown();
|
||||
|
||||
/*virtual*/ bool initWind();
|
||||
/*virtual*/ void cleanupWind();
|
||||
|
||||
/*virtual*/void updateWind(LLVector3 direction, F32 camera_height_above_water);
|
||||
|
||||
typedef F32 MIXBUFFERFORMAT;
|
||||
|
||||
FMOD::System *getSystem() const {return mSystem;}
|
||||
protected:
|
||||
/*virtual*/ LLAudioBuffer *createBuffer(); // Get a free buffer, or flush an existing one if you have to.
|
||||
/*virtual*/ LLAudioChannel *createChannel(); // Create a new audio channel.
|
||||
|
||||
/*virtual*/ void setInternalGain(F32 gain);
|
||||
|
||||
bool mInited;
|
||||
|
||||
LLWindGen<MIXBUFFERFORMAT> *mWindGen;
|
||||
|
||||
FMOD::DSP *mWindDSP;
|
||||
FMOD::System *mSystem;
|
||||
bool mEnableProfiler;
|
||||
};
|
||||
|
||||
|
||||
class LLAudioChannelFMODEX : public LLAudioChannel
|
||||
{
|
||||
public:
|
||||
LLAudioChannelFMODEX(FMOD::System *audioengine);
|
||||
virtual ~LLAudioChannelFMODEX();
|
||||
|
||||
protected:
|
||||
/*virtual*/ void play();
|
||||
/*virtual*/ void playSynced(LLAudioChannel *channelp);
|
||||
/*virtual*/ void cleanup();
|
||||
/*virtual*/ bool isPlaying();
|
||||
|
||||
/*virtual*/ bool updateBuffer();
|
||||
/*virtual*/ void update3DPosition();
|
||||
/*virtual*/ void updateLoop();
|
||||
|
||||
void set3DMode(bool use3d);
|
||||
protected:
|
||||
FMOD::System *getSystem() const {return mSystemp;}
|
||||
FMOD::System *mSystemp;
|
||||
FMOD::Channel *mChannelp;
|
||||
S32 mLastSamplePos;
|
||||
};
|
||||
|
||||
|
||||
class LLAudioBufferFMODEX : public LLAudioBuffer
|
||||
{
|
||||
public:
|
||||
LLAudioBufferFMODEX(FMOD::System *audioengine);
|
||||
virtual ~LLAudioBufferFMODEX();
|
||||
|
||||
/*virtual*/ bool loadWAV(const std::string& filename);
|
||||
/*virtual*/ U32 getLength();
|
||||
friend class LLAudioChannelFMODEX;
|
||||
protected:
|
||||
FMOD::System *getSystem() const {return mSystemp;}
|
||||
FMOD::System *mSystemp;
|
||||
FMOD::Sound *getSound() const{ return mSoundp; }
|
||||
FMOD::Sound *mSoundp;
|
||||
};
|
||||
|
||||
|
||||
#endif // LL_AUDIOENGINE_FMODEX_H
|
||||
132
indra/llaudio/lllistener_fmodex.cpp
Normal file
132
indra/llaudio/lllistener_fmodex.cpp
Normal file
@@ -0,0 +1,132 @@
|
||||
/**
|
||||
* @file listener_fmod.cpp
|
||||
* @brief implementation of LISTENER class abstracting the audio
|
||||
* support as a FMOD 3D implementation (windows only)
|
||||
*
|
||||
* $LicenseInfo:firstyear=2002&license=viewergpl$
|
||||
*
|
||||
* Copyright (c) 2002-2009, Linden Research, Inc.
|
||||
*
|
||||
* Second Life Viewer Source Code
|
||||
* The source code in this file ("Source Code") is provided by Linden Lab
|
||||
* to you under the terms of the GNU General Public License, version 2.0
|
||||
* ("GPL"), unless you have obtained a separate licensing agreement
|
||||
* ("Other License"), formally executed by you and Linden Lab. Terms of
|
||||
* the GPL can be found in doc/GPL-license.txt in this distribution, or
|
||||
* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
|
||||
*
|
||||
* There are special exceptions to the terms and conditions of the GPL as
|
||||
* it is applied to this Source Code. View the full text of the exception
|
||||
* in the file doc/FLOSS-exception.txt in this software distribution, or
|
||||
* online at
|
||||
* http://secondlifegrid.net/programs/open_source/licensing/flossexception
|
||||
*
|
||||
* By copying, modifying or distributing this software, you acknowledge
|
||||
* that you have read and understood your obligations described above,
|
||||
* and agree to abide by those obligations.
|
||||
*
|
||||
* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
|
||||
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
|
||||
* COMPLETENESS OR PERFORMANCE.
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#include "linden_common.h"
|
||||
#include "llaudioengine.h"
|
||||
#include "lllistener_fmodex.h"
|
||||
#include "fmod.hpp"
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
// constructor
|
||||
//-----------------------------------------------------------------------
|
||||
LLListener_FMODEX::LLListener_FMODEX(FMOD::System *system)
|
||||
{
|
||||
mSystem = system;
|
||||
init();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
LLListener_FMODEX::~LLListener_FMODEX()
|
||||
{
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
void LLListener_FMODEX::init(void)
|
||||
{
|
||||
// do inherited
|
||||
LLListener::init();
|
||||
mDopplerFactor = 1.0f;
|
||||
mRolloffFactor = 1.0f;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
void LLListener_FMODEX::translate(LLVector3 offset)
|
||||
{
|
||||
LLListener::translate(offset);
|
||||
|
||||
mSystem->set3DListenerAttributes(0, (FMOD_VECTOR*)mPosition.mV, NULL, (FMOD_VECTOR*)mListenAt.mV, (FMOD_VECTOR*)mListenUp.mV);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
void LLListener_FMODEX::setPosition(LLVector3 pos)
|
||||
{
|
||||
LLListener::setPosition(pos);
|
||||
|
||||
mSystem->set3DListenerAttributes(0, (FMOD_VECTOR*)mPosition.mV, NULL, (FMOD_VECTOR*)mListenAt.mV, (FMOD_VECTOR*)mListenUp.mV);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
void LLListener_FMODEX::setVelocity(LLVector3 vel)
|
||||
{
|
||||
LLListener::setVelocity(vel);
|
||||
|
||||
mSystem->set3DListenerAttributes(0, NULL, (FMOD_VECTOR*)mVelocity.mV, (FMOD_VECTOR*)mListenAt.mV, (FMOD_VECTOR*)mListenUp.mV);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
void LLListener_FMODEX::orient(LLVector3 up, LLVector3 at)
|
||||
{
|
||||
LLListener::orient(up, at);
|
||||
|
||||
// Welcome to the transition between right and left
|
||||
// (coordinate systems, that is)
|
||||
// Leaving the at vector alone results in a L/R reversal
|
||||
// since DX is left-handed and we (LL, OpenGL, OpenAL) are right-handed
|
||||
at = -at;
|
||||
|
||||
mSystem->set3DListenerAttributes(0, NULL, NULL, (FMOD_VECTOR*)at.mV, (FMOD_VECTOR*)up.mV);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
void LLListener_FMODEX::commitDeferredChanges()
|
||||
{
|
||||
mSystem->update();
|
||||
}
|
||||
|
||||
|
||||
void LLListener_FMODEX::setRolloffFactor(F32 factor)
|
||||
{
|
||||
mRolloffFactor = factor;
|
||||
mSystem->set3DSettings(mDopplerFactor, 1.f, mRolloffFactor);
|
||||
}
|
||||
|
||||
|
||||
F32 LLListener_FMODEX::getRolloffFactor()
|
||||
{
|
||||
return mRolloffFactor;
|
||||
}
|
||||
|
||||
|
||||
void LLListener_FMODEX::setDopplerFactor(F32 factor)
|
||||
{
|
||||
mDopplerFactor = factor;
|
||||
mSystem->set3DSettings(mDopplerFactor, 1.f, mRolloffFactor);
|
||||
}
|
||||
|
||||
|
||||
F32 LLListener_FMODEX::getDopplerFactor()
|
||||
{
|
||||
return mDopplerFactor;
|
||||
}
|
||||
|
||||
|
||||
71
indra/llaudio/lllistener_fmodex.h
Normal file
71
indra/llaudio/lllistener_fmodex.h
Normal file
@@ -0,0 +1,71 @@
|
||||
/**
|
||||
* @file listener_fmod.h
|
||||
* @brief Description of LISTENER class abstracting the audio support
|
||||
* as an FMOD 3D implementation (windows and Linux)
|
||||
*
|
||||
* $LicenseInfo:firstyear=2002&license=viewergpl$
|
||||
*
|
||||
* Copyright (c) 2002-2009, Linden Research, Inc.
|
||||
*
|
||||
* Second Life Viewer Source Code
|
||||
* The source code in this file ("Source Code") is provided by Linden Lab
|
||||
* to you under the terms of the GNU General Public License, version 2.0
|
||||
* ("GPL"), unless you have obtained a separate licensing agreement
|
||||
* ("Other License"), formally executed by you and Linden Lab. Terms of
|
||||
* the GPL can be found in doc/GPL-license.txt in this distribution, or
|
||||
* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
|
||||
*
|
||||
* There are special exceptions to the terms and conditions of the GPL as
|
||||
* it is applied to this Source Code. View the full text of the exception
|
||||
* in the file doc/FLOSS-exception.txt in this software distribution, or
|
||||
* online at
|
||||
* http://secondlifegrid.net/programs/open_source/licensing/flossexception
|
||||
*
|
||||
* By copying, modifying or distributing this software, you acknowledge
|
||||
* that you have read and understood your obligations described above,
|
||||
* and agree to abide by those obligations.
|
||||
*
|
||||
* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
|
||||
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
|
||||
* COMPLETENESS OR PERFORMANCE.
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#ifndef LL_LISTENER_FMODEX_H
|
||||
#define LL_LISTENER_FMODEX_H
|
||||
|
||||
#include "lllistener.h"
|
||||
|
||||
//Stubs
|
||||
namespace FMOD
|
||||
{
|
||||
class System;
|
||||
}
|
||||
|
||||
//Interfaces
|
||||
class LLListener_FMODEX : public LLListener
|
||||
{
|
||||
public:
|
||||
LLListener_FMODEX(FMOD::System *system);
|
||||
virtual ~LLListener_FMODEX();
|
||||
virtual void init();
|
||||
|
||||
virtual void translate(LLVector3 offset);
|
||||
virtual void setPosition(LLVector3 pos);
|
||||
virtual void setVelocity(LLVector3 vel);
|
||||
virtual void orient(LLVector3 up, LLVector3 at);
|
||||
virtual void commitDeferredChanges();
|
||||
|
||||
virtual void setDopplerFactor(F32 factor);
|
||||
virtual F32 getDopplerFactor();
|
||||
virtual void setRolloffFactor(F32 factor);
|
||||
virtual F32 getRolloffFactor();
|
||||
protected:
|
||||
FMOD::System *mSystem;
|
||||
F32 mDopplerFactor;
|
||||
F32 mRolloffFactor;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -36,6 +36,8 @@
|
||||
|
||||
#include "stdtypes.h" // from llcommon
|
||||
|
||||
class LLSD;
|
||||
|
||||
// Entirely abstract. Based exactly on the historic API.
|
||||
class LLStreamingAudioInterface
|
||||
{
|
||||
@@ -51,6 +53,11 @@ class LLStreamingAudioInterface
|
||||
virtual void setGain(F32 vol) = 0;
|
||||
virtual F32 getGain() = 0;
|
||||
virtual std::string getURL() = 0;
|
||||
|
||||
virtual bool supportsMetaData() = 0;
|
||||
virtual const LLSD *getMetaData() = 0;
|
||||
virtual bool supportsWaveData() = 0;
|
||||
virtual bool getWaveData(float* arr, S32 count, S32 stride = 1) = 0;
|
||||
};
|
||||
|
||||
#endif // LL_STREAMINGAUDIO_H
|
||||
|
||||
@@ -51,6 +51,8 @@ public:
|
||||
const std::string& getURL() { return mInternetStreamURL; }
|
||||
|
||||
int getOpenState();
|
||||
|
||||
FSOUND_STREAM* getStream() { return mInternetStream; }
|
||||
protected:
|
||||
FSOUND_STREAM* mInternetStream;
|
||||
bool mReady;
|
||||
@@ -66,7 +68,8 @@ protected:
|
||||
LLStreamingAudio_FMOD::LLStreamingAudio_FMOD() :
|
||||
mCurrentInternetStreamp(NULL),
|
||||
mFMODInternetStreamChannel(-1),
|
||||
mGain(1.0f)
|
||||
mGain(1.0f),
|
||||
mMetaData(NULL)
|
||||
{
|
||||
// Number of milliseconds of audio to buffer for the audio card.
|
||||
// Must be larger than the usual Second Life frame stutter time.
|
||||
@@ -87,6 +90,17 @@ LLStreamingAudio_FMOD::~LLStreamingAudio_FMOD()
|
||||
// nothing interesting/safe to do.
|
||||
}
|
||||
|
||||
signed char F_CALLBACKAPI MetaDataCallback(char *name, char *value, void *userdata)
|
||||
{
|
||||
std::string szName(name);
|
||||
if(szName == "TITLE" || szName=="TIT2" || szName=="Title")
|
||||
(*(LLSD*)userdata)["TITLE"] = value;
|
||||
if(szName == "ARTIST" || szName=="TPE1" || szName =="WM/AlbumTitle")
|
||||
(*(LLSD*)userdata)["ARTIST"] = value;
|
||||
else
|
||||
(*(LLSD*)userdata)[std::string(name)] = value;
|
||||
return true;
|
||||
}
|
||||
|
||||
void LLStreamingAudio_FMOD::start(const std::string& url)
|
||||
{
|
||||
@@ -104,6 +118,10 @@ void LLStreamingAudio_FMOD::start(const std::string& url)
|
||||
llinfos << "Starting internet stream: " << url << llendl;
|
||||
mCurrentInternetStreamp = new LLAudioStreamManagerFMOD(url);
|
||||
mURL = url;
|
||||
if(mCurrentInternetStreamp->getStream())
|
||||
{
|
||||
mMetaData = new LLSD;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -154,6 +172,10 @@ void LLStreamingAudio_FMOD::update()
|
||||
// Reset volume to previously set volume
|
||||
setGain(getGain());
|
||||
FSOUND_SetPaused(mFMODInternetStreamChannel, false);
|
||||
if(mCurrentInternetStreamp->getStream() && mMetaData)
|
||||
{
|
||||
FSOUND_Stream_Net_SetMetadataCallback(mCurrentInternetStreamp->getStream(),&MetaDataCallback, mMetaData);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -184,11 +206,17 @@ void LLStreamingAudio_FMOD::update()
|
||||
// buffering
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void LLStreamingAudio_FMOD::stop()
|
||||
{
|
||||
if(mMetaData)
|
||||
{
|
||||
if(mCurrentInternetStreamp && mCurrentInternetStreamp->getStream())
|
||||
FSOUND_Stream_Net_SetMetadataCallback(mCurrentInternetStreamp->getStream(),NULL,NULL);
|
||||
delete mMetaData;
|
||||
mMetaData = NULL;
|
||||
}
|
||||
if (mFMODInternetStreamChannel != -1)
|
||||
{
|
||||
FSOUND_SetPaused(mFMODInternetStreamChannel, true);
|
||||
|
||||
@@ -55,6 +55,10 @@ class LLStreamingAudio_FMOD : public LLStreamingAudioInterface
|
||||
/*virtual*/ F32 getGain();
|
||||
/*virtual*/ std::string getURL();
|
||||
|
||||
/*virtual*/ bool supportsMetaData(){return true;}
|
||||
/*virtual*/ const LLSD *getMetaData(){return mMetaData;} //return NULL if not playing.
|
||||
/*virtual*/ bool supportsWaveData(){return false;}
|
||||
/*virtual*/ bool getWaveData(float* arr, S32 count, S32 stride = 1){return false;}
|
||||
private:
|
||||
LLAudioStreamManagerFMOD *mCurrentInternetStreamp;
|
||||
int mFMODInternetStreamChannel;
|
||||
@@ -62,6 +66,8 @@ private:
|
||||
|
||||
std::string mURL;
|
||||
F32 mGain;
|
||||
|
||||
LLSD *mMetaData;
|
||||
};
|
||||
|
||||
|
||||
|
||||
448
indra/llaudio/llstreamingaudio_fmodex.cpp
Normal file
448
indra/llaudio/llstreamingaudio_fmodex.cpp
Normal file
@@ -0,0 +1,448 @@
|
||||
/**
|
||||
* @file streamingaudio_fmod.cpp
|
||||
* @brief LLStreamingAudio_FMODEX implementation
|
||||
*
|
||||
* $LicenseInfo:firstyear=2009&license=viewergpl$
|
||||
*
|
||||
* Copyright (c) 2009, Linden Research, Inc.
|
||||
*
|
||||
* Second Life Viewer Source Code
|
||||
* The source code in this file ("Source Code") is provided by Linden Lab
|
||||
* to you under the terms of the GNU General Public License, version 2.0
|
||||
* ("GPL"), unless you have obtained a separate licensing agreement
|
||||
* ("Other License"), formally executed by you and Linden Lab. Terms of
|
||||
* the GPL can be found in doc/GPL-license.txt in this distribution, or
|
||||
* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
|
||||
*
|
||||
* There are special exceptions to the terms and conditions of the GPL as
|
||||
* it is applied to this Source Code. View the full text of the exception
|
||||
* in the file doc/FLOSS-exception.txt in this software distribution, or
|
||||
* online at
|
||||
* http://secondlifegrid.net/programs/open_source/licensing/flossexception
|
||||
*
|
||||
* By copying, modifying or distributing this software, you acknowledge
|
||||
* that you have read and understood your obligations described above,
|
||||
* and agree to abide by those obligations.
|
||||
*
|
||||
* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
|
||||
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
|
||||
* COMPLETENESS OR PERFORMANCE.
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#include "linden_common.h"
|
||||
|
||||
#include "llmath.h"
|
||||
|
||||
#include "fmod.hpp"
|
||||
#include "fmod_errors.h"
|
||||
|
||||
#include "llstreamingaudio_fmodex.h"
|
||||
|
||||
|
||||
class LLAudioStreamManagerFMODEX
|
||||
{
|
||||
public:
|
||||
LLAudioStreamManagerFMODEX(FMOD::System *system, const std::string& url);
|
||||
FMOD::Channel* startStream();
|
||||
bool stopStream(); // Returns true if the stream was successfully stopped.
|
||||
bool ready();
|
||||
|
||||
const std::string& getURL() { return mInternetStreamURL; }
|
||||
|
||||
FMOD_OPENSTATE getOpenState();
|
||||
protected:
|
||||
FMOD::System* mSystem;
|
||||
FMOD::Channel* mStreamChannel;
|
||||
FMOD::Sound* mInternetStream;
|
||||
bool mReady;
|
||||
|
||||
std::string mInternetStreamURL;
|
||||
};
|
||||
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// Internet Streaming
|
||||
//---------------------------------------------------------------------------
|
||||
LLStreamingAudio_FMODEX::LLStreamingAudio_FMODEX(FMOD::System *system) :
|
||||
mSystem(system),
|
||||
mCurrentInternetStreamp(NULL),
|
||||
mFMODInternetStreamChannelp(NULL),
|
||||
mGain(1.0f),
|
||||
mMetaData(NULL)
|
||||
{
|
||||
// Number of milliseconds of audio to buffer for the audio card.
|
||||
// Must be larger than the usual Second Life frame stutter time.
|
||||
mSystem->setStreamBufferSize(200, FMOD_TIMEUNIT_MS);
|
||||
|
||||
// Here's where we set the size of the network buffer and some buffering
|
||||
// parameters. In this case we want a network buffer of 16k, we want it
|
||||
// to prebuffer 40% of that when we first connect, and we want it
|
||||
// to rebuffer 80% of that whenever we encounter a buffer underrun.
|
||||
|
||||
// Leave the net buffer properties at the default.
|
||||
//FSOUND_Stream_Net_SetBufferProperties(20000, 40, 80);
|
||||
}
|
||||
|
||||
|
||||
LLStreamingAudio_FMODEX::~LLStreamingAudio_FMODEX()
|
||||
{
|
||||
// nothing interesting/safe to do.
|
||||
}
|
||||
|
||||
|
||||
void LLStreamingAudio_FMODEX::start(const std::string& url)
|
||||
{
|
||||
//if (!mInited)
|
||||
//{
|
||||
// llwarns << "startInternetStream before audio initialized" << llendl;
|
||||
// return;
|
||||
//}
|
||||
|
||||
// "stop" stream but don't clear url, etc. in case url == mInternetStreamURL
|
||||
stop();
|
||||
|
||||
if (!url.empty())
|
||||
{
|
||||
llinfos << "Starting internet stream: " << url << llendl;
|
||||
mCurrentInternetStreamp = new LLAudioStreamManagerFMODEX(mSystem,url);
|
||||
mURL = url;
|
||||
mMetaData = new LLSD;
|
||||
}
|
||||
else
|
||||
{
|
||||
llinfos << "Set internet stream to null" << llendl;
|
||||
mURL.clear();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void LLStreamingAudio_FMODEX::update()
|
||||
{
|
||||
// Kill dead internet streams, if possible
|
||||
std::list<LLAudioStreamManagerFMODEX *>::iterator iter;
|
||||
for (iter = mDeadStreams.begin(); iter != mDeadStreams.end();)
|
||||
{
|
||||
LLAudioStreamManagerFMODEX *streamp = *iter;
|
||||
if (streamp->stopStream())
|
||||
{
|
||||
llinfos << "Closed dead stream" << llendl;
|
||||
delete streamp;
|
||||
mDeadStreams.erase(iter++);
|
||||
}
|
||||
else
|
||||
{
|
||||
iter++;
|
||||
}
|
||||
}
|
||||
|
||||
// Don't do anything if there are no streams playing
|
||||
if (!mCurrentInternetStreamp)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
FMOD_OPENSTATE open_state = mCurrentInternetStreamp->getOpenState();
|
||||
|
||||
if (open_state == FMOD_OPENSTATE_READY)
|
||||
{
|
||||
// Stream is live
|
||||
|
||||
// start the stream if it's ready
|
||||
if (!mFMODInternetStreamChannelp &&
|
||||
(mFMODInternetStreamChannelp = mCurrentInternetStreamp->startStream()))
|
||||
{
|
||||
// Reset volume to previously set volume
|
||||
setGain(getGain());
|
||||
mFMODInternetStreamChannelp->setPaused(false);
|
||||
}
|
||||
}
|
||||
else if(open_state == FMOD_OPENSTATE_ERROR)
|
||||
{
|
||||
stop();
|
||||
return;
|
||||
}
|
||||
|
||||
if(mFMODInternetStreamChannelp)
|
||||
{
|
||||
if(!mMetaData)
|
||||
mMetaData = new LLSD;
|
||||
|
||||
FMOD::Sound *sound = NULL;
|
||||
|
||||
if(mFMODInternetStreamChannelp->getCurrentSound(&sound) == FMOD_OK && sound)
|
||||
{
|
||||
FMOD_TAG tag;
|
||||
S32 tagcount, dirtytagcount;
|
||||
if(sound->getNumTags(&tagcount, &dirtytagcount) == FMOD_OK && dirtytagcount)
|
||||
{
|
||||
mMetaData->clear();
|
||||
|
||||
for(S32 i = 0; i < tagcount; ++i)
|
||||
{
|
||||
if(sound->getTag(NULL, i, &tag)!=FMOD_OK)
|
||||
continue;
|
||||
std::string name = tag.name;
|
||||
switch(tag.type) //Crappy tag translate table.
|
||||
{
|
||||
case(FMOD_TAGTYPE_ID3V2):
|
||||
if(name == "TIT2") name = "TITLE";
|
||||
else if(name == "TPE1") name = "ARTIST";
|
||||
break;
|
||||
case(FMOD_TAGTYPE_ASF):
|
||||
if(name == "Title") name = "TITLE";
|
||||
else if(name == "WM/AlbumArtist") name = "ARTIST";
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
switch(tag.datatype)
|
||||
{
|
||||
case(FMOD_TAGDATATYPE_INT):
|
||||
(*mMetaData)[name]=*(LLSD::Integer*)(tag.data);
|
||||
llinfos << tag.name << ": " << *(int*)(tag.data) << llendl;
|
||||
break;
|
||||
case(FMOD_TAGDATATYPE_FLOAT):
|
||||
(*mMetaData)[name]=*(LLSD::Float*)(tag.data);
|
||||
llinfos << tag.name << ": " << *(float*)(tag.data) << llendl;
|
||||
break;
|
||||
case(FMOD_TAGDATATYPE_STRING):
|
||||
{
|
||||
std::string out = rawstr_to_utf8(std::string((char*)tag.data,tag.datalen));
|
||||
(*mMetaData)[name]=out;
|
||||
llinfos << tag.name << ": " << out << llendl;
|
||||
}
|
||||
break;
|
||||
case(FMOD_TAGDATATYPE_STRING_UTF16):
|
||||
{
|
||||
std::string out((char*)tag.data,tag.datalen);
|
||||
(*mMetaData)[std::string(tag.name)]=out;
|
||||
llinfos << tag.name << ": " << out << llendl;
|
||||
}
|
||||
break;
|
||||
case(FMOD_TAGDATATYPE_STRING_UTF16BE):
|
||||
{
|
||||
std::string out((char*)tag.data,tag.datalen);
|
||||
U16* buf = (U16*)out.c_str();
|
||||
for(U32 j = 0; j < out.size()/2; ++j)
|
||||
(((buf[j] & 0xff)<<8) | ((buf[j] & 0xff00)>>8));
|
||||
(*mMetaData)[std::string(tag.name)]=out;
|
||||
llinfos << tag.name << ": " << out << llendl;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LLStreamingAudio_FMODEX::stop()
|
||||
{
|
||||
if(mMetaData)
|
||||
{
|
||||
delete mMetaData;
|
||||
mMetaData = NULL;
|
||||
}
|
||||
if (mFMODInternetStreamChannelp)
|
||||
{
|
||||
mFMODInternetStreamChannelp->setPaused(true);
|
||||
mFMODInternetStreamChannelp->setPriority(0);
|
||||
mFMODInternetStreamChannelp = NULL;
|
||||
}
|
||||
|
||||
if (mCurrentInternetStreamp)
|
||||
{
|
||||
llinfos << "Stopping internet stream: " << mCurrentInternetStreamp->getURL() << llendl;
|
||||
if (mCurrentInternetStreamp->stopStream())
|
||||
{
|
||||
delete mCurrentInternetStreamp;
|
||||
}
|
||||
else
|
||||
{
|
||||
llwarns << "Pushing stream to dead list: " << mCurrentInternetStreamp->getURL() << llendl;
|
||||
mDeadStreams.push_back(mCurrentInternetStreamp);
|
||||
}
|
||||
mCurrentInternetStreamp = NULL;
|
||||
//mURL.clear();
|
||||
}
|
||||
}
|
||||
|
||||
void LLStreamingAudio_FMODEX::pause(int pauseopt)
|
||||
{
|
||||
if (pauseopt < 0)
|
||||
{
|
||||
pauseopt = mCurrentInternetStreamp ? 1 : 0;
|
||||
}
|
||||
|
||||
if (pauseopt)
|
||||
{
|
||||
if (mCurrentInternetStreamp)
|
||||
{
|
||||
stop();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
start(getURL());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// A stream is "playing" if it has been requested to start. That
|
||||
// doesn't necessarily mean audio is coming out of the speakers.
|
||||
int LLStreamingAudio_FMODEX::isPlaying()
|
||||
{
|
||||
if (mCurrentInternetStreamp)
|
||||
{
|
||||
return 1; // Active and playing
|
||||
}
|
||||
else if (!mURL.empty())
|
||||
{
|
||||
return 2; // "Paused"
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
F32 LLStreamingAudio_FMODEX::getGain()
|
||||
{
|
||||
return mGain;
|
||||
}
|
||||
|
||||
|
||||
std::string LLStreamingAudio_FMODEX::getURL()
|
||||
{
|
||||
return mURL;
|
||||
}
|
||||
|
||||
|
||||
void LLStreamingAudio_FMODEX::setGain(F32 vol)
|
||||
{
|
||||
mGain = vol;
|
||||
|
||||
if (mFMODInternetStreamChannelp)
|
||||
{
|
||||
vol = llclamp(vol * vol, 0.f, 1.f); //should vol be squared here?
|
||||
|
||||
mFMODInternetStreamChannelp->setVolume(vol);
|
||||
}
|
||||
}
|
||||
|
||||
/*virtual*/ bool LLStreamingAudio_FMODEX::getWaveData(float* arr, S32 count, S32 stride/*=1*/)
|
||||
{
|
||||
if(!mFMODInternetStreamChannelp || !mCurrentInternetStreamp)
|
||||
return false;
|
||||
|
||||
static std::vector<float> local_array(count); //Have to have an extra buffer to mix channels. Bleh.
|
||||
if(count > (S32)local_array.size()) //Expand the array if needed. Try to minimize allocation calls, so don't ever shrink.
|
||||
local_array.resize(count);
|
||||
|
||||
if( mFMODInternetStreamChannelp->getWaveData(&local_array[0],count,0) == FMOD_OK &&
|
||||
mFMODInternetStreamChannelp->getWaveData(&arr[0],count,1) == FMOD_OK )
|
||||
{
|
||||
for(S32 i = count-1;i>=0;i-=stride)
|
||||
{
|
||||
arr[i] += local_array[i];
|
||||
arr[i] *= .5f;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////
|
||||
// manager of possibly-multiple internet audio streams
|
||||
|
||||
LLAudioStreamManagerFMODEX::LLAudioStreamManagerFMODEX(FMOD::System *system, const std::string& url) :
|
||||
mSystem(system),
|
||||
mStreamChannel(NULL),
|
||||
mInternetStream(NULL),
|
||||
mReady(false)
|
||||
{
|
||||
mInternetStreamURL = url;
|
||||
|
||||
FMOD_CREATESOUNDEXINFO exinfo;
|
||||
memset(&exinfo,0,sizeof(exinfo));
|
||||
exinfo.cbsize = sizeof(exinfo);
|
||||
exinfo.suggestedsoundtype = FMOD_SOUND_TYPE_MPEG; //Hint to speed up loading.
|
||||
|
||||
FMOD_RESULT result = mSystem->createStream(url.c_str(), FMOD_2D | FMOD_NONBLOCKING, &exinfo, &mInternetStream);
|
||||
|
||||
if (result!= FMOD_OK)
|
||||
{
|
||||
llwarns << "Couldn't open fmod stream, error "
|
||||
<< FMOD_ErrorString(result)
|
||||
<< llendl;
|
||||
mReady = false;
|
||||
return;
|
||||
}
|
||||
|
||||
mReady = true;
|
||||
}
|
||||
|
||||
FMOD::Channel *LLAudioStreamManagerFMODEX::startStream()
|
||||
{
|
||||
// We need a live and opened stream before we try and play it.
|
||||
if (!mInternetStream || getOpenState() != FMOD_OPENSTATE_READY)
|
||||
{
|
||||
llwarns << "No internet stream to start playing!" << llendl;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if(mStreamChannel)
|
||||
return mStreamChannel; //Already have a channel for this stream.
|
||||
|
||||
mSystem->playSound(FMOD_CHANNEL_FREE, mInternetStream, true, &mStreamChannel);
|
||||
return mStreamChannel;
|
||||
}
|
||||
|
||||
bool LLAudioStreamManagerFMODEX::stopStream()
|
||||
{
|
||||
if (mInternetStream)
|
||||
{
|
||||
|
||||
|
||||
bool close = true;
|
||||
switch (getOpenState())
|
||||
{
|
||||
case FMOD_OPENSTATE_CONNECTING:
|
||||
close = false;
|
||||
break;
|
||||
/*case FSOUND_STREAM_NET_NOTCONNECTED:
|
||||
case FSOUND_STREAM_NET_BUFFERING:
|
||||
case FSOUND_STREAM_NET_READY:
|
||||
case FSOUND_STREAM_NET_ERROR:*/
|
||||
default:
|
||||
close = true;
|
||||
}
|
||||
|
||||
if (close)
|
||||
{
|
||||
mInternetStream->release();
|
||||
mStreamChannel = NULL;
|
||||
mInternetStream = NULL;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
FMOD_OPENSTATE LLAudioStreamManagerFMODEX::getOpenState()
|
||||
{
|
||||
FMOD_OPENSTATE state;
|
||||
mInternetStream->getOpenState(&state,NULL,NULL,NULL);
|
||||
return state;
|
||||
}
|
||||
83
indra/llaudio/llstreamingaudio_fmodex.h
Normal file
83
indra/llaudio/llstreamingaudio_fmodex.h
Normal file
@@ -0,0 +1,83 @@
|
||||
/**
|
||||
* @file streamingaudio_fmod.h
|
||||
* @author Tofu Linden
|
||||
* @brief Definition of LLStreamingAudio_FMOD implementation
|
||||
*
|
||||
* $LicenseInfo:firstyear=2009&license=viewergpl$
|
||||
*
|
||||
* Copyright (c) 2009, Linden Research, Inc.
|
||||
*
|
||||
* Second Life Viewer Source Code
|
||||
* The source code in this file ("Source Code") is provided by Linden Lab
|
||||
* to you under the terms of the GNU General Public License, version 2.0
|
||||
* ("GPL"), unless you have obtained a separate licensing agreement
|
||||
* ("Other License"), formally executed by you and Linden Lab. Terms of
|
||||
* the GPL can be found in doc/GPL-license.txt in this distribution, or
|
||||
* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
|
||||
*
|
||||
* There are special exceptions to the terms and conditions of the GPL as
|
||||
* it is applied to this Source Code. View the full text of the exception
|
||||
* in the file doc/FLOSS-exception.txt in this software distribution, or
|
||||
* online at
|
||||
* http://secondlifegrid.net/programs/open_source/licensing/flossexception
|
||||
*
|
||||
* By copying, modifying or distributing this software, you acknowledge
|
||||
* that you have read and understood your obligations described above,
|
||||
* and agree to abide by those obligations.
|
||||
*
|
||||
* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
|
||||
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
|
||||
* COMPLETENESS OR PERFORMANCE.
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#ifndef LL_STREAMINGAUDIO_FMOD_H
|
||||
#define LL_STREAMINGAUDIO_FMOD_H
|
||||
|
||||
#include "stdtypes.h" // from llcommon
|
||||
|
||||
#include "llstreamingaudio.h"
|
||||
|
||||
//Stubs
|
||||
class LLAudioStreamManagerFMODEX;
|
||||
namespace FMOD
|
||||
{
|
||||
class System;
|
||||
class Channel;
|
||||
}
|
||||
|
||||
//Interfaces
|
||||
class LLStreamingAudio_FMODEX : public LLStreamingAudioInterface
|
||||
{
|
||||
public:
|
||||
LLStreamingAudio_FMODEX(FMOD::System *system);
|
||||
/*virtual*/ ~LLStreamingAudio_FMODEX();
|
||||
|
||||
/*virtual*/ void start(const std::string& url);
|
||||
/*virtual*/ void stop();
|
||||
/*virtual*/ void pause(int pause);
|
||||
/*virtual*/ void update();
|
||||
/*virtual*/ int isPlaying();
|
||||
/*virtual*/ void setGain(F32 vol);
|
||||
/*virtual*/ F32 getGain();
|
||||
/*virtual*/ std::string getURL();
|
||||
|
||||
/*virtual*/ bool supportsMetaData(){return true;}
|
||||
/*virtual*/ const LLSD *getMetaData(){return mMetaData;} //return NULL if not playing.
|
||||
/*virtual*/ bool supportsWaveData(){return true;}
|
||||
/*virtual*/ bool getWaveData(float* arr, S32 count, S32 stride = 1);
|
||||
private:
|
||||
FMOD::System *mSystem;
|
||||
|
||||
LLAudioStreamManagerFMODEX *mCurrentInternetStreamp;
|
||||
FMOD::Channel *mFMODInternetStreamChannelp;
|
||||
std::list<LLAudioStreamManagerFMODEX *> mDeadStreams;
|
||||
|
||||
std::string mURL;
|
||||
F32 mGain;
|
||||
|
||||
LLSD *mMetaData;
|
||||
};
|
||||
|
||||
|
||||
#endif // LL_STREAMINGAUDIO_FMOD_H
|
||||
@@ -133,10 +133,10 @@ BOOL decode_vorbis_file(LLVFS *vfs, const LLUUID &in_uuid, char *out_fname)
|
||||
return(FALSE);
|
||||
}
|
||||
|
||||
//**********************************
|
||||
// **********************************
|
||||
LLAPRFile outfile ;
|
||||
outfile.open(out_fname,LL_APR_WPB);
|
||||
//**********************************
|
||||
// **********************************
|
||||
if (!outfile.getFileHandle())
|
||||
{
|
||||
llwarning("unable to open vorbis destination file for writing",0);
|
||||
@@ -308,9 +308,9 @@ BOOL decode_vorbis_file(LLVFS *vfs, const LLUUID &in_uuid, char *out_fname)
|
||||
|
||||
outfile.seek(SEEK_END,-fade_length*2);
|
||||
outfile.write(pcmout,2*fade_length); //write back xfaded last 16 samples
|
||||
//*******************
|
||||
// *******************
|
||||
outfile.close();
|
||||
//*******************
|
||||
// *******************
|
||||
|
||||
if ((36 == data_length) || (!(eof)))
|
||||
{
|
||||
|
||||
@@ -87,10 +87,10 @@ S32 check_for_invalid_wav_formats(const std::string& in_fname, std::string& erro
|
||||
|
||||
error_msg.clear();
|
||||
|
||||
//********************************
|
||||
// ********************************
|
||||
LLAPRFile infile ;
|
||||
infile.open(in_fname,LL_APR_RB, LLAPRFile::global);
|
||||
//********************************
|
||||
infile.open(in_fname,LL_APR_RB);
|
||||
// ********************************
|
||||
if (!infile.getFileHandle())
|
||||
{
|
||||
error_msg = "CannotUploadSoundFile";
|
||||
@@ -159,9 +159,9 @@ S32 check_for_invalid_wav_formats(const std::string& in_fname, std::string& erro
|
||||
file_pos += (chunk_length + 8);
|
||||
chunk_length = 0;
|
||||
}
|
||||
//****************
|
||||
// ****************
|
||||
infile.close();
|
||||
//****************
|
||||
// ****************
|
||||
|
||||
if (!uncompressed_pcm)
|
||||
{
|
||||
@@ -240,7 +240,7 @@ S32 encode_vorbis_file(const std::string& in_fname, const std::string& out_fname
|
||||
S32 data_left = 0;
|
||||
|
||||
LLAPRFile infile ;
|
||||
infile.open(in_fname,LL_APR_RB, LLAPRFile::global);
|
||||
infile.open(in_fname,LL_APR_RB);
|
||||
if (!infile.getFileHandle())
|
||||
{
|
||||
llwarns << "Couldn't open temporary ogg file for writing: " << in_fname
|
||||
@@ -249,7 +249,7 @@ S32 encode_vorbis_file(const std::string& in_fname, const std::string& out_fname
|
||||
}
|
||||
|
||||
LLAPRFile outfile ;
|
||||
outfile.open(out_fname,LL_APR_WPB, LLAPRFile::global);
|
||||
outfile.open(out_fname,LL_APR_WPB);
|
||||
if (!outfile.getFileHandle())
|
||||
{
|
||||
llwarns << "Couldn't open upload sound file for reading: " << in_fname
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
#define WINDGEN_H
|
||||
|
||||
#include "llcommon.h"
|
||||
#include "llrand.h"
|
||||
|
||||
template <class MIXBUFFERFORMAT_T>
|
||||
class LLWindGen
|
||||
@@ -60,7 +61,9 @@ public:
|
||||
}
|
||||
|
||||
const U32 getInputSamplingRate() { return mInputSamplingRate; }
|
||||
|
||||
const F32 getNextSample();
|
||||
const F32 getClampedSample(bool clamp, F32 sample);
|
||||
|
||||
// newbuffer = the buffer passed from the previous DSP unit.
|
||||
// numsamples = length in samples-per-channel at this mix time.
|
||||
// NOTE: generates L/R interleaved stereo
|
||||
@@ -95,7 +98,7 @@ public:
|
||||
|
||||
// Start with white noise
|
||||
// This expression is fragile, rearrange it and it will break!
|
||||
next_sample = (F32)rand() * (1.0f / (F32)(RAND_MAX / (U16_MAX / 8))) + (F32)(S16_MIN / 8);
|
||||
next_sample = getNextSample();
|
||||
|
||||
// Apply a pinking filter
|
||||
// Magic numbers taken from PKE method at http://www.firstpr.com.au/dsp/pink-noise/
|
||||
@@ -132,23 +135,13 @@ public:
|
||||
for (U8 i=mSubSamples; i && numsamples; --i, --numsamples)
|
||||
{
|
||||
mLastSample = mLastSample + delta;
|
||||
S32 sample_right = (S32)(mLastSample * mCurrentPanGainR);
|
||||
S32 sample_left = (S32)mLastSample - sample_right;
|
||||
MIXBUFFERFORMAT_T sample_right = (MIXBUFFERFORMAT_T)getClampedSample(clip, mLastSample * mCurrentPanGainR);
|
||||
MIXBUFFERFORMAT_T sample_left = (MIXBUFFERFORMAT_T)getClampedSample(clip, mLastSample - (F32)sample_right);
|
||||
|
||||
if (!clip)
|
||||
{
|
||||
*cursamplep = (MIXBUFFERFORMAT_T)sample_left;
|
||||
++cursamplep;
|
||||
*cursamplep = (MIXBUFFERFORMAT_T)sample_right;
|
||||
++cursamplep;
|
||||
}
|
||||
else
|
||||
{
|
||||
*cursamplep = (MIXBUFFERFORMAT_T)llclamp(sample_left, (S32)S16_MIN, (S32)S16_MAX);
|
||||
++cursamplep;
|
||||
*cursamplep = (MIXBUFFERFORMAT_T)llclamp(sample_right, (S32)S16_MIN, (S32)S16_MAX);
|
||||
++cursamplep;
|
||||
}
|
||||
*cursamplep = sample_left;
|
||||
++cursamplep;
|
||||
*cursamplep = sample_right;
|
||||
++cursamplep;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -179,4 +172,9 @@ private:
|
||||
F32 mLastSample;
|
||||
};
|
||||
|
||||
template<class T> inline const F32 LLWindGen<T>::getNextSample() { return (F32)rand() * (1.0f / (F32)(RAND_MAX / (U16_MAX / 8))) + (F32)(S16_MIN / 8); }
|
||||
template<> inline const F32 LLWindGen<F32>::getNextSample() { return ll_frand()-.5f; }
|
||||
template<class T> inline const F32 LLWindGen<T>::getClampedSample(bool clamp, F32 sample) { return clamp ? (F32)llclamp((S32)sample,(S32)S16_MIN,(S32)S16_MAX) : sample; }
|
||||
template<> inline const F32 LLWindGen<F32>::getClampedSample(bool clamp, F32 sample) { return sample; }
|
||||
|
||||
#endif
|
||||
|
||||
@@ -225,8 +225,7 @@ ELoadStatus LLBVHLoader::loadTranslationTable(const char *fileName)
|
||||
//--------------------------------------------------------------------
|
||||
std::string path = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS,fileName);
|
||||
|
||||
LLAPRFile infile ;
|
||||
infile.open(path, LL_APR_R, LLAPRFile::global);
|
||||
LLAPRFile infile(path, LL_APR_R);
|
||||
apr_file_t *fp = infile.getFileHandle();
|
||||
if (!fp)
|
||||
return E_ST_NO_XLT_FILE;
|
||||
|
||||
@@ -45,7 +45,7 @@
|
||||
LLStringTable LLCharacter::sVisualParamNames(1024);
|
||||
|
||||
std::vector< LLCharacter* > LLCharacter::sInstances;
|
||||
|
||||
BOOL LLCharacter::sAllowInstancesChange = TRUE ;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// LLCharacter()
|
||||
@@ -59,8 +59,10 @@ LLCharacter::LLCharacter()
|
||||
mSkeletonSerialNum( 0 ),
|
||||
mInAppearance( false )
|
||||
{
|
||||
mMotionController.setCharacter( this );
|
||||
llassert_always(sAllowInstancesChange) ;
|
||||
sInstances.push_back(this);
|
||||
|
||||
mMotionController.setCharacter( this );
|
||||
mPauseRequest = new LLPauseRequestHandle();
|
||||
}
|
||||
|
||||
@@ -77,11 +79,22 @@ LLCharacter::~LLCharacter()
|
||||
{
|
||||
delete param;
|
||||
}
|
||||
std::vector<LLCharacter*>::iterator iter = std::find(sInstances.begin(), sInstances.end(), this);
|
||||
if (iter != sInstances.end())
|
||||
|
||||
U32 i ;
|
||||
U32 size = sInstances.size() ;
|
||||
for(i = 0 ; i < size ; i++)
|
||||
{
|
||||
sInstances.erase(iter);
|
||||
if(sInstances[i] == this)
|
||||
{
|
||||
break ;
|
||||
}
|
||||
}
|
||||
|
||||
llassert_always(i < size) ;
|
||||
|
||||
llassert_always(sAllowInstancesChange) ;
|
||||
sInstances[i] = sInstances[size - 1] ;
|
||||
sInstances.pop_back() ;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -42,7 +42,7 @@
|
||||
#include "llmotioncontroller.h"
|
||||
#include "llvisualparam.h"
|
||||
#include "string_table.h"
|
||||
#include "llmemory.h"
|
||||
#include "llpointer.h"
|
||||
#include "llthread.h"
|
||||
|
||||
class LLPolyMesh;
|
||||
@@ -279,6 +279,7 @@ public:
|
||||
void setSkeletonSerialNum( U32 num ) { mSkeletonSerialNum = num; }
|
||||
|
||||
static std::vector< LLCharacter* > sInstances;
|
||||
static BOOL sAllowInstancesChange ; //debug use
|
||||
|
||||
protected:
|
||||
LLMotionController mMotionController;
|
||||
|
||||
@@ -56,6 +56,7 @@ LLJoint::LLJoint()
|
||||
mUpdateXform = TRUE;
|
||||
mJointNum = -1;
|
||||
touch();
|
||||
mResetAfterRestoreOldXform = false;
|
||||
}
|
||||
|
||||
|
||||
@@ -239,6 +240,41 @@ void LLJoint::setPosition( const LLVector3& pos )
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// setPosition()
|
||||
//--------------------------------------------------------------------
|
||||
void LLJoint::setDefaultFromCurrentXform( void )
|
||||
{
|
||||
mDefaultXform = mXform;
|
||||
touch(MATRIX_DIRTY | POSITION_DIRTY);
|
||||
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// storeCurrentXform()
|
||||
//--------------------------------------------------------------------
|
||||
void LLJoint::storeCurrentXform( const LLVector3& pos )
|
||||
{
|
||||
mOldXform = mXform;
|
||||
mResetAfterRestoreOldXform = true;
|
||||
setPosition( pos );
|
||||
}
|
||||
//--------------------------------------------------------------------
|
||||
// restoreOldXform()
|
||||
//--------------------------------------------------------------------
|
||||
void LLJoint::restoreOldXform( void )
|
||||
{
|
||||
mResetAfterRestoreOldXform = false;
|
||||
mXform = mOldXform;
|
||||
}
|
||||
//--------------------------------------------------------------------
|
||||
// restoreOldXform()
|
||||
//--------------------------------------------------------------------
|
||||
void LLJoint::restoreToDefaultXform( void )
|
||||
{
|
||||
mXform = mDefaultXform;
|
||||
setPosition( mXform.getPosition() );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// getWorldPosition()
|
||||
|
||||
@@ -86,10 +86,14 @@ protected:
|
||||
|
||||
// explicit transformation members
|
||||
LLXformMatrix mXform;
|
||||
LLXformMatrix mOldXform;
|
||||
LLXformMatrix mDefaultXform;
|
||||
|
||||
LLUUID mId;
|
||||
public:
|
||||
U32 mDirtyFlags;
|
||||
BOOL mUpdateXform;
|
||||
BOOL mResetAfterRestoreOldXform;
|
||||
|
||||
// describes the skin binding pose
|
||||
LLVector3 mSkinOffset;
|
||||
@@ -179,6 +183,21 @@ public:
|
||||
S32 getJointNum() const { return mJointNum; }
|
||||
void setJointNum(S32 joint_num) { mJointNum = joint_num; }
|
||||
|
||||
void restoreOldXform( void );
|
||||
void restoreToDefaultXform( void );
|
||||
void setDefaultFromCurrentXform( void );
|
||||
void storeCurrentXform( const LLVector3& pos );
|
||||
|
||||
//Accessor for the joint id
|
||||
LLUUID getId( void ) { return mId; }
|
||||
//Setter for the joints id
|
||||
void setId( const LLUUID& id ) { mId = id;}
|
||||
|
||||
//If the old transform flag has been set, then the reset logic in avatar needs to be aware(test) of it
|
||||
const BOOL doesJointNeedToBeReset( void ) const { return mResetAfterRestoreOldXform; }
|
||||
//Setter for joint reset flag
|
||||
void setJointToBeReset( BOOL val ) { mResetAfterRestoreOldXform = val; }
|
||||
|
||||
// <edit>
|
||||
std::string exportString(U32 tabs = 0);
|
||||
// </edit>
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
// Header Files
|
||||
//-----------------------------------------------------------------------------
|
||||
#include "lljoint.h"
|
||||
#include "llmemory.h"
|
||||
#include "llrefcount.h"
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// class LLJointState
|
||||
|
||||
@@ -838,7 +838,11 @@ void LLKeyframeMotion::initializeConstraint(JointConstraint* constraint)
|
||||
S32 joint_num;
|
||||
LLVector3 source_pos = mCharacter->getVolumePos(shared_data->mSourceConstraintVolume, shared_data->mSourceConstraintOffset);
|
||||
LLJoint* cur_joint = getJoint(shared_data->mJointStateIndices[0]);
|
||||
|
||||
if ( !cur_joint )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
F32 source_pos_offset = dist_vec(source_pos, cur_joint->getWorldPosition());
|
||||
|
||||
constraint->mTotalLength = constraint->mJointLengths[0] = dist_vec(cur_joint->getParent()->getWorldPosition(), source_pos);
|
||||
@@ -889,6 +893,10 @@ void LLKeyframeMotion::activateConstraint(JointConstraint* constraint)
|
||||
for (joint_num = 1; joint_num < shared_data->mChainLength; joint_num++)
|
||||
{
|
||||
LLJoint* cur_joint = getJoint(shared_data->mJointStateIndices[joint_num]);
|
||||
if ( !cur_joint )
|
||||
{
|
||||
return;
|
||||
}
|
||||
constraint->mPositions[joint_num] = (cur_joint->getWorldPosition() - mPelvisp->getWorldPosition()) * ~mPelvisp->getWorldRotation();
|
||||
}
|
||||
|
||||
@@ -949,6 +957,10 @@ void LLKeyframeMotion::applyConstraint(JointConstraint* constraint, F32 time, U8
|
||||
}
|
||||
|
||||
LLJoint* root_joint = getJoint(shared_data->mJointStateIndices[shared_data->mChainLength]);
|
||||
if (! root_joint)
|
||||
{
|
||||
return;
|
||||
}
|
||||
LLVector3 root_pos = root_joint->getWorldPosition();
|
||||
// LLQuaternion root_rot =
|
||||
root_joint->getParent()->getWorldRotation();
|
||||
@@ -960,6 +972,11 @@ void LLKeyframeMotion::applyConstraint(JointConstraint* constraint, F32 time, U8
|
||||
for (joint_num = 0; joint_num <= shared_data->mChainLength; joint_num++)
|
||||
{
|
||||
LLJoint* cur_joint = getJoint(shared_data->mJointStateIndices[joint_num]);
|
||||
if (!cur_joint)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (joint_mask[cur_joint->getJointNum()] >= (0xff >> (7 - getPriority())))
|
||||
{
|
||||
// skip constraint
|
||||
@@ -1050,7 +1067,14 @@ void LLKeyframeMotion::applyConstraint(JointConstraint* constraint, F32 time, U8
|
||||
|
||||
if (shared_data->mChainLength)
|
||||
{
|
||||
LLQuaternion end_rot = getJoint(shared_data->mJointStateIndices[0])->getWorldRotation();
|
||||
LLJoint* end_joint = getJoint(shared_data->mJointStateIndices[0]);
|
||||
|
||||
if (!end_joint)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
LLQuaternion end_rot = end_joint->getWorldRotation();
|
||||
|
||||
// slam start and end of chain to the proper positions (rest of chain stays put)
|
||||
positions[0] = lerp(keyframe_source_pos, target_pos, weight);
|
||||
@@ -1059,7 +1083,14 @@ void LLKeyframeMotion::applyConstraint(JointConstraint* constraint, F32 time, U8
|
||||
// grab keyframe-specified positions of joints
|
||||
for (joint_num = 1; joint_num < shared_data->mChainLength; joint_num++)
|
||||
{
|
||||
LLVector3 kinematic_position = getJoint(shared_data->mJointStateIndices[joint_num])->getWorldPosition() +
|
||||
LLJoint* cur_joint = getJoint(shared_data->mJointStateIndices[joint_num]);
|
||||
|
||||
if (!cur_joint)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
LLVector3 kinematic_position = cur_joint->getWorldPosition() +
|
||||
(source_to_target * constraint->mJointLengthFractions[joint_num]);
|
||||
|
||||
// convert intermediate joint positions to world coordinates
|
||||
@@ -1105,7 +1136,17 @@ void LLKeyframeMotion::applyConstraint(JointConstraint* constraint, F32 time, U8
|
||||
for (joint_num = shared_data->mChainLength; joint_num > 0; joint_num--)
|
||||
{
|
||||
LLJoint* cur_joint = getJoint(shared_data->mJointStateIndices[joint_num]);
|
||||
|
||||
if (!cur_joint)
|
||||
{
|
||||
return;
|
||||
}
|
||||
LLJoint* child_joint = getJoint(shared_data->mJointStateIndices[joint_num - 1]);
|
||||
if (!child_joint)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
LLQuaternion parent_rot = cur_joint->getParent()->getWorldRotation();
|
||||
|
||||
LLQuaternion cur_rot = cur_joint->getWorldRotation();
|
||||
@@ -1139,7 +1180,6 @@ void LLKeyframeMotion::applyConstraint(JointConstraint* constraint, F32 time, U8
|
||||
cur_joint->setRotation(target_rot);
|
||||
}
|
||||
|
||||
LLJoint* end_joint = getJoint(shared_data->mJointStateIndices[0]);
|
||||
LLQuaternion end_local_rot = end_rot * ~end_joint->getParent()->getWorldRotation();
|
||||
|
||||
if (weight == 1.f)
|
||||
@@ -1162,12 +1202,18 @@ void LLKeyframeMotion::applyConstraint(JointConstraint* constraint, F32 time, U8
|
||||
constraint->mPositions[joint_num] = new_pos;
|
||||
}
|
||||
constraint->mFixupDistanceRMS *= 1.f / (constraint->mTotalLength * (F32)(shared_data->mChainLength - 1));
|
||||
constraint->mFixupDistanceRMS = fsqrtf(constraint->mFixupDistanceRMS);
|
||||
constraint->mFixupDistanceRMS = (F32) sqrt(constraint->mFixupDistanceRMS);
|
||||
|
||||
//reset old joint rots
|
||||
for (joint_num = 0; joint_num <= shared_data->mChainLength; joint_num++)
|
||||
{
|
||||
getJoint(shared_data->mJointStateIndices[joint_num])->setRotation(old_rots[joint_num]);
|
||||
LLJoint* cur_joint = getJoint(shared_data->mJointStateIndices[joint_num]);
|
||||
if (!cur_joint)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
cur_joint->setRotation(old_rots[joint_num]);
|
||||
}
|
||||
}
|
||||
// simple positional constraint (pelvis only)
|
||||
@@ -1816,7 +1862,15 @@ BOOL LLKeyframeMotion::deserialize(LLDataPacker& dp)
|
||||
constraintp->mJointStateIndices[i] = -1;
|
||||
for (U32 j = 0; j < mJointMotionList->getNumJointMotions(); j++)
|
||||
{
|
||||
if(getJoint(j) == joint)
|
||||
LLJoint* constraint_joint = getJoint(j);
|
||||
|
||||
if ( !constraint_joint )
|
||||
{
|
||||
llwarns << "Invalid joint " << j << llendl;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if(constraint_joint == joint)
|
||||
{
|
||||
constraintp->mJointStateIndices[i] = (S32)j;
|
||||
break;
|
||||
|
||||
@@ -357,8 +357,7 @@ BOOL LLKeyframeMotionParam::loadMotions()
|
||||
// open the file
|
||||
//-------------------------------------------------------------------------
|
||||
S32 fileSize = 0;
|
||||
LLAPRFile infile ;
|
||||
infile.open(path, LL_APR_R, LLAPRFile::global, &fileSize);
|
||||
LLAPRFile infile(path, LL_APR_R, &fileSize);
|
||||
apr_file_t* fp = infile.getFileHandle() ;
|
||||
if (!fp || fileSize == 0)
|
||||
{
|
||||
|
||||
@@ -637,9 +637,9 @@ void LLMotionController::updateMotionsByType(LLMotion::LLMotionBlendType anim_ty
|
||||
motionp->fadeIn();
|
||||
}
|
||||
|
||||
//**********************
|
||||
// **********************
|
||||
// MOTION INACTIVE
|
||||
//**********************
|
||||
// **********************
|
||||
if (motionp->isStopped() && mAnimTime > motionp->getStopTime() + motionp->getEaseOutDuration())
|
||||
{
|
||||
// this motion has gone on too long, deactivate it
|
||||
@@ -659,9 +659,9 @@ void LLMotionController::updateMotionsByType(LLMotion::LLMotionBlendType anim_ty
|
||||
}
|
||||
}
|
||||
|
||||
//**********************
|
||||
// **********************
|
||||
// MOTION EASE OUT
|
||||
//**********************
|
||||
// **********************
|
||||
else if (motionp->isStopped() && mAnimTime > motionp->getStopTime())
|
||||
{
|
||||
// is this the first iteration in the ease out phase?
|
||||
@@ -684,9 +684,9 @@ void LLMotionController::updateMotionsByType(LLMotion::LLMotionBlendType anim_ty
|
||||
update_result = motionp->onUpdate(mAnimTime - motionp->mActivationTimestamp, last_joint_signature);
|
||||
}
|
||||
|
||||
//**********************
|
||||
// **********************
|
||||
// MOTION ACTIVE
|
||||
//**********************
|
||||
// **********************
|
||||
else if (mAnimTime > motionp->mActivationTimestamp + motionp->getEaseInDuration())
|
||||
{
|
||||
posep->setWeight(motionp->getFadeWeight());
|
||||
@@ -707,9 +707,9 @@ void LLMotionController::updateMotionsByType(LLMotion::LLMotionBlendType anim_ty
|
||||
update_result = motionp->onUpdate(mAnimTime - motionp->mActivationTimestamp, last_joint_signature);
|
||||
}
|
||||
|
||||
//**********************
|
||||
// **********************
|
||||
// MOTION EASE IN
|
||||
//**********************
|
||||
// **********************
|
||||
else if (mAnimTime >= motionp->mActivationTimestamp)
|
||||
{
|
||||
if (mLastTime < motionp->mActivationTimestamp)
|
||||
|
||||
@@ -89,6 +89,7 @@ LLJointState *LLPose::getNextJointState()
|
||||
//-----------------------------------------------------------------------------
|
||||
BOOL LLPose::addJointState(const LLPointer<LLJointState>& jointState)
|
||||
{
|
||||
llassert_always(jointState.notNull());
|
||||
if (mJointMap.find(jointState->getJoint()->getName()) == mJointMap.end())
|
||||
{
|
||||
mJointMap[jointState->getJoint()->getName()] = jointState;
|
||||
@@ -161,6 +162,7 @@ void LLPose::setWeight(F32 weight)
|
||||
// <edit>
|
||||
// there was a crash here
|
||||
// </edit>
|
||||
llassert_always(iter->second.notNull());
|
||||
iter->second->setWeight(weight);
|
||||
}
|
||||
mWeight = weight;
|
||||
|
||||
@@ -40,6 +40,8 @@
|
||||
#include "lljointstate.h"
|
||||
#include "lljoint.h"
|
||||
#include "llmap.h"
|
||||
#include "llpointer.h"
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
|
||||
@@ -210,8 +210,7 @@ LLFSMState* LLStateDiagram::getState(U32 state_id)
|
||||
|
||||
BOOL LLStateDiagram::saveDotFile(const std::string& filename)
|
||||
{
|
||||
LLAPRFile outfile ;
|
||||
outfile.open(filename, LL_APR_W, LLAPRFile::global);
|
||||
LLAPRFile outfile(filename, LL_APR_W);
|
||||
apr_file_t* dot_file = outfile.getFileHandle() ;
|
||||
|
||||
if (!dot_file)
|
||||
|
||||
@@ -16,11 +16,11 @@ include_directories(
|
||||
|
||||
set(llcommon_SOURCE_FILES
|
||||
aiframetimer.cpp
|
||||
aiaprpool.cpp
|
||||
imageids.cpp
|
||||
indra_constants.cpp
|
||||
llapp.cpp
|
||||
llapr.cpp
|
||||
llaprpool.cpp
|
||||
llassettype.cpp
|
||||
llavatarname.cpp
|
||||
llbase32.cpp
|
||||
@@ -40,6 +40,7 @@ set(llcommon_SOURCE_FILES
|
||||
llfile.cpp
|
||||
llfindlocale.cpp
|
||||
llfixedbuffer.cpp
|
||||
llfoldertype.cpp
|
||||
llformat.cpp
|
||||
llframetimer.cpp
|
||||
llheartbeat.cpp
|
||||
@@ -58,12 +59,15 @@ set(llcommon_SOURCE_FILES
|
||||
llprocessor.cpp
|
||||
llqueuedthread.cpp
|
||||
llrand.cpp
|
||||
llrefcount.cpp
|
||||
llrun.cpp
|
||||
llscopedvolatileaprpool.h
|
||||
llsd.cpp
|
||||
llsdserialize.cpp
|
||||
llsdserialize_xml.cpp
|
||||
llsdutil.cpp
|
||||
llsecondlifeurls.cpp
|
||||
llsingleton.cpp
|
||||
llstat.cpp
|
||||
llstacktrace.cpp
|
||||
llstreamtools.cpp
|
||||
@@ -71,6 +75,7 @@ set(llcommon_SOURCE_FILES
|
||||
llstringtable.cpp
|
||||
llsys.cpp
|
||||
llthread.cpp
|
||||
llthreadsafequeue.cpp
|
||||
lltimer.cpp
|
||||
lluri.cpp
|
||||
lluuid.cpp
|
||||
@@ -86,7 +91,6 @@ set(llcommon_HEADER_FILES
|
||||
CMakeLists.txt
|
||||
|
||||
aiframetimer.h
|
||||
aiaprpool.h
|
||||
aithreadsafe.h
|
||||
bitpack.h
|
||||
ctype_workaround.h
|
||||
@@ -95,10 +99,12 @@ set(llcommon_HEADER_FILES
|
||||
indra_constants.h
|
||||
linden_common.h
|
||||
linked_lists.h
|
||||
llaccountingcost.h
|
||||
llagentconstants.h
|
||||
llavatarname.h
|
||||
llapp.h
|
||||
llapr.h
|
||||
llaprpool.h
|
||||
llassettype.h
|
||||
llassoclist.h
|
||||
llavatarconstants.h
|
||||
@@ -135,6 +141,7 @@ set(llcommon_HEADER_FILES
|
||||
llfile.h
|
||||
llfindlocale.h
|
||||
llfixedbuffer.h
|
||||
llfoldertype.h
|
||||
llformat.h
|
||||
llframetimer.h
|
||||
llhash.h
|
||||
@@ -159,6 +166,7 @@ set(llcommon_HEADER_FILES
|
||||
llmortician.h
|
||||
llnametable.h
|
||||
lloptioninterface.h
|
||||
llpointer.h
|
||||
llpreprocessor.h
|
||||
llpriqueuemap.h
|
||||
llprocesslauncher.h
|
||||
@@ -167,14 +175,17 @@ set(llcommon_HEADER_FILES
|
||||
llptrskipmap.h
|
||||
llqueuedthread.h
|
||||
llrand.h
|
||||
llrefcount.h
|
||||
llrun.h
|
||||
llscopedvolatileaprpool.h
|
||||
llrefcount.h
|
||||
llsafehandle.h
|
||||
llsd.h
|
||||
llsdserialize.h
|
||||
llsdserialize_xml.h
|
||||
llsdutil.h
|
||||
llsecondlifeurls.h
|
||||
llsimplehash.h
|
||||
llsingleton.h
|
||||
llskiplist.h
|
||||
llskipmap.h
|
||||
llstack.h
|
||||
@@ -188,7 +199,9 @@ set(llcommon_HEADER_FILES
|
||||
llstringtable.h
|
||||
llsys.h
|
||||
llthread.h
|
||||
llthreadsafequeue.h
|
||||
lltimer.h
|
||||
lltreeiterators.h
|
||||
lluri.h
|
||||
lluuid.h
|
||||
lluuidhashmap.h
|
||||
@@ -205,6 +218,7 @@ set(llcommon_HEADER_FILES
|
||||
stdenums.h
|
||||
stdtypes.h
|
||||
string_table.h
|
||||
stringize.h
|
||||
timer.h
|
||||
timing.h
|
||||
u64.h
|
||||
@@ -224,6 +238,7 @@ target_link_libraries(
|
||||
${EXPAT_LIBRARIES}
|
||||
${ZLIB_LIBRARIES}
|
||||
${WINDOWS_LIBRARIES}
|
||||
${BOOST_REGEX_LIBRARY}
|
||||
${CWDEBUG_LIBRARIES}
|
||||
${CORESERVICES_LIBRARY}
|
||||
)
|
||||
|
||||
@@ -175,7 +175,7 @@ protected:
|
||||
|
||||
// For use by AIThreadSafeDC
|
||||
AIThreadSafe(void) { }
|
||||
AIThreadSafe(AIAPRPool& parent) : mRWLock(parent) { }
|
||||
AIThreadSafe(LLAPRPool& parent) : mRWLock(parent) { }
|
||||
|
||||
public:
|
||||
// Only for use by AITHREADSAFE, see below.
|
||||
@@ -406,7 +406,7 @@ protected:
|
||||
friend struct AIRegisteredStateMachinesList;
|
||||
// For use by AIThreadSafeSimpleDC and AIRegisteredStateMachinesList.
|
||||
AIThreadSafeSimple(void) { }
|
||||
AIThreadSafeSimple(AIAPRPool& parent) : mMutex(parent) { }
|
||||
AIThreadSafeSimple(LLAPRPool& parent) : mMutex(parent) { }
|
||||
|
||||
public:
|
||||
// Only for use by AITHREADSAFESIMPLE, see below.
|
||||
@@ -471,7 +471,7 @@ public:
|
||||
|
||||
protected:
|
||||
// For use by AIThreadSafeSimpleDCRootPool
|
||||
AIThreadSafeSimpleDC(AIAPRPool& parent) : AIThreadSafeSimple<T>(parent) { new (AIThreadSafeSimple<T>::ptr()) T; }
|
||||
AIThreadSafeSimpleDC(LLAPRPool& parent) : AIThreadSafeSimple<T>(parent) { new (AIThreadSafeSimple<T>::ptr()) T; }
|
||||
};
|
||||
|
||||
// Helper class for AIThreadSafeSimpleDCRootPool to assure initialization of
|
||||
@@ -479,7 +479,7 @@ protected:
|
||||
class AIThreadSafeSimpleDCRootPool_pbase
|
||||
{
|
||||
protected:
|
||||
AIAPRRootPool mRootPool;
|
||||
LLAPRRootPool mRootPool;
|
||||
|
||||
private:
|
||||
template<typename T> friend class AIThreadSafeSimpleDCRootPool;
|
||||
@@ -489,7 +489,7 @@ private:
|
||||
/**
|
||||
* @brief A wrapper class for objects that need to be accessed by more than one thread.
|
||||
*
|
||||
* The same as AIThreadSafeSimpleDC except that this class creates its own AIAPRRootPool
|
||||
* The same as AIThreadSafeSimpleDC except that this class creates its own LLAPRRootPool
|
||||
* for the internally used mutexes and condition, instead of using the current threads
|
||||
* root pool. The advantage of this is that it can be used for objects that need to
|
||||
* be accessed from the destructors of global objects (after main). The disadvantage
|
||||
|
||||
@@ -124,7 +124,7 @@ public:
|
||||
|
||||
// NOTE: This next two funtions are only included here
|
||||
// for those too familiar with the LLLinkedList template class.
|
||||
// They are depreciated. resetList() is unecessary while
|
||||
// They are deprecated. resetList() is unecessary while
|
||||
// getCurrentData() is identical to getNextData() and has
|
||||
// a misleading name.
|
||||
//
|
||||
@@ -604,7 +604,7 @@ BOOL LLDoubleLinkedList<DATA_TYPE>::checkData(const DATA_TYPE *data)
|
||||
|
||||
// NOTE: This next two funtions are only included here
|
||||
// for those too familiar with the LLLinkedList template class.
|
||||
// They are depreciated. resetList() is unecessary while
|
||||
// They are deprecated. resetList() is unecessary while
|
||||
// getCurrentData() is identical to getNextData() and has
|
||||
// a misleading name.
|
||||
//
|
||||
|
||||
@@ -153,11 +153,6 @@ const char LAND_LAYER_CODE = 'L';
|
||||
const char WATER_LAYER_CODE = 'W';
|
||||
const char WIND_LAYER_CODE = '7';
|
||||
const char CLOUD_LAYER_CODE = '8';
|
||||
// Extended land layer for Aurora Sim
|
||||
const char AURORA_LAND_LAYER_CODE = 'M';
|
||||
const char AURORA_WATER_LAYER_CODE = 'X';
|
||||
const char AURORA_WIND_LAYER_CODE = '9';
|
||||
const char AURORA_CLOUD_LAYER_CODE = ':';
|
||||
|
||||
// keys
|
||||
// Bit masks for various keyboard modifier keys.
|
||||
@@ -324,6 +319,14 @@ const F32 CHAT_SHOUT_RADIUS = 100.f;
|
||||
const F32 CHAT_MAX_RADIUS = CHAT_SHOUT_RADIUS;
|
||||
const F32 CHAT_MAX_RADIUS_BY_TWO = CHAT_MAX_RADIUS / 2.f;
|
||||
|
||||
// squared editions of the above for distance checks
|
||||
const F32 CHAT_WHISPER_RADIUS_SQUARED = CHAT_WHISPER_RADIUS * CHAT_WHISPER_RADIUS;
|
||||
const F32 CHAT_NORMAL_RADIUS_SQUARED = CHAT_NORMAL_RADIUS * CHAT_NORMAL_RADIUS;
|
||||
const F32 CHAT_SHOUT_RADIUS_SQUARED = CHAT_SHOUT_RADIUS * CHAT_SHOUT_RADIUS;
|
||||
const F32 CHAT_MAX_RADIUS_SQUARED = CHAT_SHOUT_RADIUS_SQUARED;
|
||||
const F32 CHAT_MAX_RADIUS_BY_TWO_SQUARED = CHAT_MAX_RADIUS_BY_TWO * CHAT_MAX_RADIUS_BY_TWO;
|
||||
|
||||
|
||||
// this times above gives barely audible radius
|
||||
const F32 CHAT_BARELY_AUDIBLE_FACTOR = 2.0f;
|
||||
|
||||
|
||||
86
indra/llcommon/llaccountingcost.h
Normal file
86
indra/llcommon/llaccountingcost.h
Normal file
@@ -0,0 +1,86 @@
|
||||
/**
|
||||
* @file llaccountingcost.h
|
||||
* @
|
||||
*
|
||||
* $LicenseInfo:firstyear=2001&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2011, Linden Research, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#ifndef LL_ACCOUNTINGQUOTA_H
|
||||
#define LL_ACCOUNTINGQUOTA_H
|
||||
|
||||
struct ParcelQuota
|
||||
{
|
||||
ParcelQuota( F32 ownerRenderCost, F32 ownerPhysicsCost, F32 ownerNetworkCost, F32 ownerSimulationCost,
|
||||
F32 groupRenderCost, F32 groupPhysicsCost, F32 groupNetworkCost, F32 groupSimulationCost,
|
||||
F32 otherRenderCost, F32 otherPhysicsCost, F32 otherNetworkCost, F32 otherSimulationCost,
|
||||
F32 tempRenderCost, F32 tempPhysicsCost, F32 tempNetworkCost, F32 tempSimulationCost,
|
||||
F32 selectedRenderCost, F32 selectedPhysicsCost, F32 selectedNetworkCost, F32 selectedSimulationCost,
|
||||
F32 parcelCapacity )
|
||||
: mOwnerRenderCost( ownerRenderCost ), mOwnerPhysicsCost( ownerPhysicsCost )
|
||||
, mOwnerNetworkCost( ownerNetworkCost ), mOwnerSimulationCost( ownerSimulationCost )
|
||||
, mGroupRenderCost( groupRenderCost ), mGroupPhysicsCost( groupPhysicsCost )
|
||||
, mGroupNetworkCost( groupNetworkCost ), mGroupSimulationCost( groupSimulationCost )
|
||||
, mOtherRenderCost( otherRenderCost ), mOtherPhysicsCost( otherPhysicsCost )
|
||||
, mOtherNetworkCost( otherNetworkCost ), mOtherSimulationCost( otherSimulationCost )
|
||||
, mTempRenderCost( tempRenderCost ), mTempPhysicsCost( tempPhysicsCost )
|
||||
, mTempNetworkCost( tempNetworkCost ), mTempSimulationCost( tempSimulationCost )
|
||||
, mSelectedRenderCost( tempRenderCost ), mSelectedPhysicsCost( tempPhysicsCost )
|
||||
, mSelectedNetworkCost( tempNetworkCost ), mSelectedSimulationCost( selectedSimulationCost )
|
||||
, mParcelCapacity( parcelCapacity )
|
||||
{
|
||||
}
|
||||
|
||||
ParcelQuota(){}
|
||||
F32 mOwnerRenderCost, mOwnerPhysicsCost, mOwnerNetworkCost, mOwnerSimulationCost;
|
||||
F32 mGroupRenderCost, mGroupPhysicsCost, mGroupNetworkCost, mGroupSimulationCost;
|
||||
F32 mOtherRenderCost, mOtherPhysicsCost, mOtherNetworkCost, mOtherSimulationCost;
|
||||
F32 mTempRenderCost, mTempPhysicsCost, mTempNetworkCost, mTempSimulationCost;
|
||||
F32 mSelectedRenderCost, mSelectedPhysicsCost, mSelectedNetworkCost, mSelectedSimulationCost;
|
||||
F32 mParcelCapacity;
|
||||
};
|
||||
|
||||
//SelectionQuota atm does not require a id
|
||||
struct SelectionCost
|
||||
{
|
||||
SelectionCost( /*LLTransactionID transactionId, */ F32 physicsCost, F32 networkCost, F32 simulationCost )
|
||||
//: mTransactionId( transactionId)
|
||||
: mPhysicsCost( physicsCost )
|
||||
, mNetworkCost( networkCost )
|
||||
, mSimulationCost( simulationCost )
|
||||
{
|
||||
}
|
||||
SelectionCost()
|
||||
: mPhysicsCost( 0.0f )
|
||||
, mNetworkCost( 0.0f )
|
||||
, mSimulationCost( 0.0f )
|
||||
{}
|
||||
|
||||
F32 mPhysicsCost, mNetworkCost, mSimulationCost;
|
||||
//LLTransactionID mTransactionId;
|
||||
};
|
||||
|
||||
typedef enum { Roots = 0 , Prims } eSelectionType;
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
@@ -288,10 +288,13 @@ void LLApp::startErrorThread()
|
||||
// Start the error handling thread, which is responsible for taking action
|
||||
// when the app goes into the APP_STATUS_ERROR state
|
||||
//
|
||||
llinfos << "Starting error thread" << llendl;
|
||||
mThreadErrorp = new LLErrorThread();
|
||||
mThreadErrorp->setUserData((void *) this);
|
||||
mThreadErrorp->start();
|
||||
if(!mThreadErrorp)
|
||||
{
|
||||
llinfos << "Starting error thread" << llendl;
|
||||
mThreadErrorp = new LLErrorThread();
|
||||
mThreadErrorp->setUserData((void *) this);
|
||||
mThreadErrorp->start();
|
||||
}
|
||||
}
|
||||
|
||||
void LLApp::setErrorHandler(LLAppErrorHandler handler)
|
||||
|
||||
@@ -102,12 +102,12 @@ LLAPRFile::LLAPRFile()
|
||||
{
|
||||
}
|
||||
|
||||
LLAPRFile::LLAPRFile(const std::string& filename, apr_int32_t flags, access_t access_type)
|
||||
LLAPRFile::LLAPRFile(const std::string& filename, apr_int32_t flags, S32* sizep, access_t access_type)
|
||||
: mFile(NULL),
|
||||
mVolatileFilePoolp(NULL),
|
||||
mRegularFilePoolp(NULL)
|
||||
{
|
||||
open(filename, flags, access_type);
|
||||
open(filename, flags, access_type, sizep);
|
||||
}
|
||||
|
||||
LLAPRFile::~LLAPRFile()
|
||||
@@ -147,18 +147,19 @@ apr_status_t LLAPRFile::open(std::string const& filename, apr_int32_t flags, acc
|
||||
apr_status_t status;
|
||||
{
|
||||
apr_pool_t* apr_file_open_pool;
|
||||
if (access_type == local)
|
||||
// This is a temporary variable for a pool that is passed directly to apr_file_open below.
|
||||
if (access_type == short_lived)
|
||||
{
|
||||
// Use a "volatile" thread-local pool.
|
||||
mVolatileFilePoolp = &AIThreadLocalData::tldata().mVolatileAPRPool;
|
||||
mVolatileFilePoolp = &LLThreadLocalData::tldata().mVolatileAPRPool;
|
||||
// Access the pool and increment it's reference count.
|
||||
// The reference count of AIVolatileAPRPool objects will be decremented
|
||||
// The reference count of LLVolatileAPRPool objects will be decremented
|
||||
// again in LLAPRFile::close by calling mVolatileFilePoolp->clearVolatileAPRPool().
|
||||
apr_file_open_pool = mVolatileFilePoolp->getVolatileAPRPool();
|
||||
}
|
||||
else
|
||||
{
|
||||
mRegularFilePoolp = new AIAPRPool(AIThreadLocalData::tldata().mRootPool);
|
||||
mRegularFilePoolp = new LLAPRPool(LLThreadLocalData::tldata().mRootPool);
|
||||
apr_file_open_pool = (*mRegularFilePoolp)();
|
||||
}
|
||||
status = apr_file_open(&mFile, filename.c_str(), flags, APR_OS_DEFAULT, apr_file_open_pool);
|
||||
@@ -191,6 +192,10 @@ apr_status_t LLAPRFile::open(std::string const& filename, apr_int32_t flags, acc
|
||||
return status;
|
||||
}
|
||||
|
||||
apr_status_t LLAPRFile::open(const std::string& filename, apr_int32_t flags, BOOL use_global_pool)
|
||||
{
|
||||
return open(filename, flags, use_global_pool ? LLAPRFile::long_lived : LLAPRFile::short_lived);
|
||||
}
|
||||
// File I/O
|
||||
S32 LLAPRFile::read(void *buf, S32 nbytes)
|
||||
{
|
||||
@@ -244,7 +249,7 @@ S32 LLAPRFile::seek(apr_seek_where_t where, S32 offset)
|
||||
}
|
||||
|
||||
//
|
||||
//*******************************************************************************************************************************
|
||||
// *******************************************************************************************************************************
|
||||
//static components of LLAPRFile
|
||||
//
|
||||
|
||||
@@ -499,5 +504,5 @@ bool LLAPRFile::removeDir(const std::string& dirname)
|
||||
}
|
||||
//
|
||||
//end of static components of LLAPRFile
|
||||
//*******************************************************************************************************************************
|
||||
// *******************************************************************************************************************************
|
||||
//
|
||||
|
||||
@@ -48,8 +48,8 @@
|
||||
#include "apr_atomic.h"
|
||||
#include "llstring.h"
|
||||
|
||||
class AIAPRPool;
|
||||
class AIVolatileAPRPool;
|
||||
class LLAPRPool;
|
||||
class LLVolatileAPRPool;
|
||||
|
||||
/**
|
||||
* @class LLScopedLock
|
||||
@@ -140,20 +140,21 @@ class LL_COMMON_API LLAPRFile : boost::noncopyable
|
||||
// make this non copyable since a copy closes the file
|
||||
private:
|
||||
apr_file_t* mFile ;
|
||||
AIVolatileAPRPool* mVolatileFilePoolp; // (Thread local) APR pool currently in use.
|
||||
AIAPRPool* mRegularFilePoolp; // ...or a regular pool.
|
||||
LLVolatileAPRPool* mVolatileFilePoolp; // (Thread local) APR pool currently in use.
|
||||
LLAPRPool* mRegularFilePoolp; // ...or a regular pool.
|
||||
|
||||
public:
|
||||
enum access_t {
|
||||
global, // Use a global pool for long-lived file accesses. This should really only happen from the main thread.
|
||||
local // Use a thread-local volatile pool for short file accesses.
|
||||
long_lived, // Use a global pool for long-lived file accesses.
|
||||
short_lived // Use a volatile pool for short-lived file accesses.
|
||||
};
|
||||
|
||||
LLAPRFile() ;
|
||||
LLAPRFile(const std::string& filename, apr_int32_t flags, access_t access_type);
|
||||
LLAPRFile(const std::string& filename, apr_int32_t flags, S32* sizep = NULL, access_t access_type = short_lived);
|
||||
~LLAPRFile() ;
|
||||
|
||||
apr_status_t open(const std::string& filename, apr_int32_t flags, access_t access_type, S32* sizep = NULL);
|
||||
apr_status_t open(const std::string& filename, apr_int32_t flags, access_t access_type = short_lived, S32* sizep = NULL);
|
||||
apr_status_t open(const std::string& filename, apr_int32_t flags, BOOL use_global_pool); //use global pool.
|
||||
apr_status_t close() ;
|
||||
|
||||
// Returns actual offset, -1 if seek fails
|
||||
@@ -167,7 +168,7 @@ public:
|
||||
apr_file_t* getFileHandle() {return mFile;}
|
||||
|
||||
//
|
||||
//*******************************************************************************************************************************
|
||||
// *******************************************************************************************************************************
|
||||
//static components
|
||||
//
|
||||
private:
|
||||
@@ -184,7 +185,7 @@ public:
|
||||
// Returns bytes read/written, 0 if read/write fails:
|
||||
static S32 readEx(const std::string& filename, void *buf, S32 offset, S32 nbytes);
|
||||
static S32 writeEx(const std::string& filename, void *buf, S32 offset, S32 nbytes);
|
||||
//*******************************************************************************************************************************
|
||||
// *******************************************************************************************************************************
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* @file aiaprpool.cpp
|
||||
* @file LLAPRPool.cpp
|
||||
*
|
||||
* Copyright (c) 2010, Aleric Inglewood.
|
||||
*
|
||||
@@ -36,18 +36,18 @@
|
||||
#include "linden_common.h"
|
||||
|
||||
#include "llerror.h"
|
||||
#include "aiaprpool.h"
|
||||
#include "llaprpool.h"
|
||||
#include "llthread.h"
|
||||
|
||||
// Create a subpool from parent.
|
||||
void AIAPRPool::create(AIAPRPool& parent)
|
||||
void LLAPRPool::create(LLAPRPool& parent)
|
||||
{
|
||||
llassert(!mPool); // Must be non-initialized.
|
||||
mParent = &parent;
|
||||
if (!mParent) // Using the default parameter?
|
||||
{
|
||||
// By default use the root pool of the current thread.
|
||||
mParent = &AIThreadLocalData::tldata().mRootPool;
|
||||
mParent = &LLThreadLocalData::tldata().mRootPool;
|
||||
}
|
||||
llassert(mParent->mPool); // Parent must be initialized.
|
||||
#if APR_HAS_THREADS
|
||||
@@ -72,7 +72,7 @@ void AIAPRPool::create(AIAPRPool& parent)
|
||||
}
|
||||
|
||||
// Destroy the (sub)pool, if any.
|
||||
void AIAPRPool::destroy(void)
|
||||
void LLAPRPool::destroy(void)
|
||||
{
|
||||
// Only do anything if we are not already (being) destroyed.
|
||||
if (mPool)
|
||||
@@ -92,12 +92,12 @@ void AIAPRPool::destroy(void)
|
||||
}
|
||||
}
|
||||
|
||||
bool AIAPRPool::parent_is_being_destructed(void)
|
||||
bool LLAPRPool::parent_is_being_destructed(void)
|
||||
{
|
||||
return mParent && (!mParent->mPool || mParent->parent_is_being_destructed());
|
||||
}
|
||||
|
||||
AIAPRInitialization::AIAPRInitialization(void)
|
||||
LLAPRInitialization::LLAPRInitialization(void)
|
||||
{
|
||||
static bool apr_initialized = false;
|
||||
|
||||
@@ -109,13 +109,13 @@ AIAPRInitialization::AIAPRInitialization(void)
|
||||
apr_initialized = true;
|
||||
}
|
||||
|
||||
bool AIAPRRootPool::sCountInitialized = false;
|
||||
apr_uint32_t volatile AIAPRRootPool::sCount;
|
||||
bool LLAPRRootPool::sCountInitialized = false;
|
||||
apr_uint32_t volatile LLAPRRootPool::sCount;
|
||||
|
||||
extern apr_thread_mutex_t* gLogMutexp;
|
||||
extern apr_thread_mutex_t* gCallStacksLogMutexp;
|
||||
apr_thread_mutex_t* gLogMutexp;
|
||||
apr_thread_mutex_t* gCallStacksLogMutexp;
|
||||
|
||||
AIAPRRootPool::AIAPRRootPool(void) : AIAPRInitialization(), AIAPRPool(0)
|
||||
LLAPRRootPool::LLAPRRootPool(void) : LLAPRInitialization(), LLAPRPool(0)
|
||||
{
|
||||
// sCountInitialized don't need locking because when we get here there is still only a single thread.
|
||||
if (!sCountInitialized)
|
||||
@@ -130,14 +130,14 @@ AIAPRRootPool::AIAPRRootPool(void) : AIAPRInitialization(), AIAPRPool(0)
|
||||
sCountInitialized = true;
|
||||
|
||||
// Initialize thread-local APR pool support.
|
||||
// Because this recursively calls AIAPRRootPool::AIAPRRootPool(void)
|
||||
// Because this recursively calls LLAPRRootPool::LLAPRRootPool(void)
|
||||
// it must be done last, so that sCount is already initialized.
|
||||
AIThreadLocalData::init();
|
||||
LLThreadLocalData::init();
|
||||
}
|
||||
apr_atomic_inc32(&sCount);
|
||||
}
|
||||
|
||||
AIAPRRootPool::~AIAPRRootPool()
|
||||
LLAPRRootPool::~LLAPRRootPool()
|
||||
{
|
||||
if (!apr_atomic_dec32(&sCount))
|
||||
{
|
||||
@@ -161,21 +161,21 @@ AIAPRRootPool::~AIAPRRootPool()
|
||||
gCallStacksLogMutexp = NULL;
|
||||
}
|
||||
|
||||
// Must destroy ALL, and therefore this last AIAPRRootPool, before terminating APR.
|
||||
static_cast<AIAPRRootPool*>(this)->destroy();
|
||||
// Must destroy ALL, and therefore this last LLAPRRootPool, before terminating APR.
|
||||
static_cast<LLAPRRootPool*>(this)->destroy();
|
||||
|
||||
apr_terminate();
|
||||
}
|
||||
}
|
||||
|
||||
//static
|
||||
AIAPRRootPool& AIAPRRootPool::get(void)
|
||||
LLAPRRootPool& LLAPRRootPool::get(void)
|
||||
{
|
||||
static AIAPRRootPool global_APRpool(0); // This is what used to be gAPRPoolp.
|
||||
static LLAPRRootPool global_APRpool(0); // This is what used to be gAPRPoolp.
|
||||
return global_APRpool;
|
||||
}
|
||||
|
||||
void AIVolatileAPRPool::clearVolatileAPRPool()
|
||||
void LLVolatileAPRPool::clearVolatileAPRPool()
|
||||
{
|
||||
llassert_always(mNumActiveRef > 0);
|
||||
if (--mNumActiveRef == 0)
|
||||
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* @file aiaprpool.h
|
||||
* @brief Implementation of AIAPRPool.
|
||||
* @file LLAPRPool.h
|
||||
* @brief Implementation of LLAPRPool.
|
||||
*
|
||||
* Copyright (c) 2010, Aleric Inglewood.
|
||||
*
|
||||
@@ -34,11 +34,15 @@
|
||||
* of subpools by threads other than the parent pool owner.
|
||||
*/
|
||||
|
||||
#ifndef AIAPRPOOL_H
|
||||
#define AIAPRPOOL_H
|
||||
#ifndef LL_LLAPRPOOL_H
|
||||
#define LL_LLAPRPOOL_H
|
||||
|
||||
#ifdef LL_WINDOWS
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable:4996)
|
||||
#include <winsock2.h>
|
||||
#include <ws2tcpip.h> // Needed before including apr_portable.h
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
#include "apr_portable.h"
|
||||
@@ -53,27 +57,27 @@ extern void ll_init_apr();
|
||||
* Usage of this class should be restricted to passing it to libapr-1 function calls that need it.
|
||||
*
|
||||
*/
|
||||
class LL_COMMON_API AIAPRPool
|
||||
class LL_COMMON_API LLAPRPool
|
||||
{
|
||||
protected:
|
||||
apr_pool_t* mPool; //!< Pointer to the underlaying pool. NULL if not initialized.
|
||||
AIAPRPool* mParent; //!< Pointer to the parent pool, if any. Only valid when mPool is non-zero.
|
||||
LLAPRPool* mParent; //!< Pointer to the parent pool, if any. Only valid when mPool is non-zero.
|
||||
apr_os_thread_t mOwner; //!< The thread that owns this memory pool. Only valid when mPool is non-zero.
|
||||
|
||||
public:
|
||||
//! Construct an uninitialized (destructed) pool.
|
||||
AIAPRPool(void) : mPool(NULL) { }
|
||||
LLAPRPool(void) : mPool(NULL) { }
|
||||
|
||||
//! Construct a subpool from an existing pool.
|
||||
// This is not a copy-constructor, this class doesn't have one!
|
||||
AIAPRPool(AIAPRPool& parent) : mPool(NULL) { create(parent); }
|
||||
LLAPRPool(LLAPRPool& parent) : mPool(NULL) { create(parent); }
|
||||
|
||||
//! Destruct the memory pool (free all of it's subpools and allocated memory).
|
||||
~AIAPRPool() { destroy(); }
|
||||
~LLAPRPool() { destroy(); }
|
||||
|
||||
protected:
|
||||
// Create a pool that is allocated from the Operating System. Only used by AIAPRRootPool.
|
||||
AIAPRPool(int) : mPool(NULL), mParent(NULL), mOwner(apr_os_thread_current())
|
||||
// Create a pool that is allocated from the Operating System. Only used by LLAPRRootPool.
|
||||
LLAPRPool(int) : mPool(NULL), mParent(NULL), mOwner(apr_os_thread_current())
|
||||
{
|
||||
apr_status_t const apr_pool_create_status = apr_pool_create(&mPool, NULL);
|
||||
llassert_always(apr_pool_create_status == APR_SUCCESS);
|
||||
@@ -84,15 +88,15 @@ protected:
|
||||
public:
|
||||
//! Create a subpool from parent. May only be called for an uninitialized/destroyed pool.
|
||||
// The default parameter causes the root pool of the current thread to be used.
|
||||
void create(AIAPRPool& parent = *static_cast<AIAPRPool*>(NULL));
|
||||
void create(LLAPRPool& parent = *static_cast<LLAPRPool*>(NULL));
|
||||
|
||||
//! Destroy the (sub)pool, if any.
|
||||
void destroy(void);
|
||||
|
||||
// Use some safebool idiom (http://www.artima.com/cppsource/safebool.html) rather than operator bool.
|
||||
typedef apr_pool_t* const AIAPRPool::* const bool_type;
|
||||
//! Return true if the pool is initialized.
|
||||
operator bool_type() const { return mPool ? &AIAPRPool::mPool : 0; }
|
||||
typedef LLAPRPool* const LLAPRPool::* const bool_type;
|
||||
/// Return true if the pool is initialized.
|
||||
operator bool_type() const { return mPool ? &LLAPRPool::mParent : 0; }
|
||||
|
||||
// Painful, but we have to either provide access to this, or wrap
|
||||
// every APR function call that needs a apr_pool_t* to be passed.
|
||||
@@ -133,7 +137,7 @@ public:
|
||||
|
||||
private:
|
||||
bool parent_is_being_destructed(void);
|
||||
static apr_status_t s_plain_cleanup(void* userdata) { return static_cast<AIAPRPool*>(userdata)->plain_cleanup(); }
|
||||
static apr_status_t s_plain_cleanup(void* userdata) { return static_cast<LLAPRPool*>(userdata)->plain_cleanup(); }
|
||||
|
||||
apr_status_t plain_cleanup(void)
|
||||
{
|
||||
@@ -148,30 +152,30 @@ private:
|
||||
}
|
||||
};
|
||||
|
||||
class AIAPRInitialization
|
||||
class LLAPRInitialization
|
||||
{
|
||||
public:
|
||||
AIAPRInitialization(void);
|
||||
LLAPRInitialization(void);
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Root memory pool (allocates memory from the operating system).
|
||||
*
|
||||
* This class should only be used by AIThreadLocalData and AIThreadSafeSimpleDCRootPool_pbase
|
||||
* This class should only be used by LLThreadLocalData and AIThreadSafeSimpleDCRootPool_pbase
|
||||
* (and LLMutexRootPool when APR_HAS_THREADS isn't defined).
|
||||
*/
|
||||
class LL_COMMON_API AIAPRRootPool : public AIAPRInitialization, public AIAPRPool
|
||||
class LL_COMMON_API LLAPRRootPool : public LLAPRInitialization, public LLAPRPool
|
||||
{
|
||||
private:
|
||||
friend class AIThreadLocalData;
|
||||
friend class LLThreadLocalData;
|
||||
friend class AIThreadSafeSimpleDCRootPool_pbase;
|
||||
#if !APR_HAS_THREADS
|
||||
friend class LLMutexRootPool;
|
||||
#endif
|
||||
//! Construct a root memory pool.
|
||||
// Should only be used by AIThreadLocalData and AIThreadSafeSimpleDCRootPool_pbase.
|
||||
AIAPRRootPool(void);
|
||||
~AIAPRRootPool();
|
||||
// Should only be used by LLThreadLocalData and AIThreadSafeSimpleDCRootPool_pbase.
|
||||
LLAPRRootPool(void);
|
||||
~LLAPRRootPool();
|
||||
|
||||
private:
|
||||
// Keep track of how many root pools exist and when the last one is destructed.
|
||||
@@ -179,10 +183,10 @@ private:
|
||||
static apr_uint32_t volatile sCount;
|
||||
|
||||
public:
|
||||
// Return a global root pool that is independent of AIThreadLocalData.
|
||||
// Return a global root pool that is independent of LLThreadLocalData.
|
||||
// Normally you should not use this. Only use for early initialization
|
||||
// (before main) and deinitialization (after main).
|
||||
static AIAPRRootPool& get(void);
|
||||
static LLAPRRootPool& get(void);
|
||||
|
||||
#if APR_POOL_DEBUG
|
||||
void grab_ownership(void)
|
||||
@@ -194,11 +198,11 @@ public:
|
||||
#endif
|
||||
|
||||
private:
|
||||
// Used for constructing the Special Global Root Pool (returned by AIAPRRootPool::get).
|
||||
// Used for constructing the Special Global Root Pool (returned by LLAPRRootPool::get).
|
||||
// It is the same as the default constructor but omits to increment sCount. As a result,
|
||||
// we must be sure that at least one other AIAPRRootPool is created before termination
|
||||
// of the application (which is the case: we create one AIAPRRootPool per thread).
|
||||
AIAPRRootPool(int) : AIAPRInitialization(), AIAPRPool(0) { }
|
||||
// we must be sure that at least one other LLAPRRootPool is created before termination
|
||||
// of the application (which is the case: we create one LLAPRRootPool per thread).
|
||||
LLAPRRootPool(int) : LLAPRInitialization(), LLAPRPool(0) { }
|
||||
};
|
||||
|
||||
//! Volatile memory pool
|
||||
@@ -210,29 +214,33 @@ private:
|
||||
// the system memory to be allocated more efficiently and not
|
||||
// get scattered through RAM.
|
||||
//
|
||||
class LL_COMMON_API AIVolatileAPRPool : protected AIAPRPool
|
||||
class LL_COMMON_API LLVolatileAPRPool : protected LLAPRPool
|
||||
{
|
||||
public:
|
||||
AIVolatileAPRPool(void) : mNumActiveRef(0), mNumTotalRef(0) { }
|
||||
LLVolatileAPRPool(void) : mNumActiveRef(0), mNumTotalRef(0) { }
|
||||
|
||||
apr_pool_t* getVolatileAPRPool(void)
|
||||
{
|
||||
if (!mPool) create();
|
||||
++mNumActiveRef;
|
||||
++mNumTotalRef;
|
||||
return AIAPRPool::operator()();
|
||||
}
|
||||
void clearVolatileAPRPool(void);
|
||||
|
||||
bool isOld(void) const { return mNumTotalRef > FULL_VOLATILE_APR_POOL; }
|
||||
bool isUnused() const { return mNumActiveRef == 0; }
|
||||
|
||||
private:
|
||||
friend class LLScopedVolatileAPRPool;
|
||||
friend class LLAPRFile;
|
||||
apr_pool_t* getVolatileAPRPool(void) // The use of apr_pool_t is OK here.
|
||||
{
|
||||
if (!mPool) create();
|
||||
++mNumActiveRef;
|
||||
++mNumTotalRef;
|
||||
return LLAPRPool::operator()();
|
||||
}
|
||||
|
||||
private:
|
||||
S32 mNumActiveRef; // Number of active uses of the pool.
|
||||
S32 mNumTotalRef; // Number of total uses of the pool since last creation.
|
||||
|
||||
// Maximum number of references to AIVolatileAPRPool until the pool is recreated.
|
||||
// Maximum number of references to LLVolatileAPRPool until the pool is recreated.
|
||||
static S32 const FULL_VOLATILE_APR_POOL = 1024;
|
||||
};
|
||||
|
||||
#endif // AIAPRPOOL_H
|
||||
#endif // LLAPRPool_H
|
||||
@@ -35,6 +35,7 @@
|
||||
#include "llassettype.h"
|
||||
#include "lldictionary.h"
|
||||
#include "llmemory.h"
|
||||
#include "llsingleton.h"
|
||||
|
||||
///----------------------------------------------------------------------------
|
||||
/// Class LLAssetType
|
||||
@@ -85,26 +86,27 @@ LLAssetDictionary::LLAssetDictionary()
|
||||
addEntry(LLAssetType::AT_OBJECT, new AssetEntry("OBJECT", "object", "object", true, false, false));
|
||||
addEntry(LLAssetType::AT_NOTECARD, new AssetEntry("NOTECARD", "notecard", "note card", true, false, true));
|
||||
addEntry(LLAssetType::AT_CATEGORY, new AssetEntry("CATEGORY", "category", "folder", true, false, false));
|
||||
addEntry(LLAssetType::AT_ROOT_CATEGORY, new AssetEntry("ROOT_CATEGORY", "root", "root", false, false, false));
|
||||
//addEntry(LLAssetType::AT_ROOT_CATEGORY, new AssetEntry("ROOT_CATEGORY", "root", "root", false, false, false));
|
||||
addEntry(LLAssetType::AT_LSL_TEXT, new AssetEntry("LSL_TEXT", "lsltext", "lsl2 script", true, false, false));
|
||||
addEntry(LLAssetType::AT_LSL_BYTECODE, new AssetEntry("LSL_BYTECODE", "lslbyte", "lsl bytecode", true, false, false));
|
||||
addEntry(LLAssetType::AT_TEXTURE_TGA, new AssetEntry("TEXTURE_TGA", "txtr_tga", "tga texture", true, false, false));
|
||||
addEntry(LLAssetType::AT_BODYPART, new AssetEntry("BODYPART", "bodypart", "body part", true, true, true));
|
||||
addEntry(LLAssetType::AT_TRASH, new AssetEntry("TRASH", "trash", "trash", false, false, false));
|
||||
addEntry(LLAssetType::AT_SNAPSHOT_CATEGORY, new AssetEntry("SNAPSHOT_CATEGORY", "snapshot", "snapshot", false, false, false));
|
||||
addEntry(LLAssetType::AT_LOST_AND_FOUND, new AssetEntry("LOST_AND_FOUND", "lstndfnd", "lost and found", false, false, false));
|
||||
//addEntry(LLAssetType::AT_TRASH, new AssetEntry("TRASH", "trash", "trash", false, false, false));
|
||||
//addEntry(LLAssetType::AT_SNAPSHOT_CATEGORY, new AssetEntry("SNAPSHOT_CATEGORY", "snapshot", "snapshot", false, false, false));
|
||||
//addEntry(LLAssetType::AT_LOST_AND_FOUND, new AssetEntry("LOST_AND_FOUND", "lstndfnd", "lost and found", false, false, false));
|
||||
addEntry(LLAssetType::AT_SOUND_WAV, new AssetEntry("SOUND_WAV", "snd_wav", "sound", true, false, false));
|
||||
addEntry(LLAssetType::AT_IMAGE_TGA, new AssetEntry("IMAGE_TGA", "img_tga", "targa image", true, false, false));
|
||||
addEntry(LLAssetType::AT_IMAGE_JPEG, new AssetEntry("IMAGE_JPEG", "jpeg", "jpeg image", true, false, false));
|
||||
addEntry(LLAssetType::AT_ANIMATION, new AssetEntry("ANIMATION", "animatn", "animation", true, true, true));
|
||||
addEntry(LLAssetType::AT_GESTURE, new AssetEntry("GESTURE", "gesture", "gesture", true, true, true));
|
||||
addEntry(LLAssetType::AT_SIMSTATE, new AssetEntry("SIMSTATE", "simstate", "simstate", false, false, false));
|
||||
addEntry(LLAssetType::AT_FAVORITE, new AssetEntry("FAVORITE", "favorite", "", false, false, false));
|
||||
//addEntry(LLAssetType::AT_FAVORITE, new AssetEntry("FAVORITE", "favorite", "", false, false, false));
|
||||
addEntry(LLAssetType::AT_LINK, new AssetEntry("LINK", "link", "sym link", false, false, true));
|
||||
addEntry(LLAssetType::AT_LINK_FOLDER, new AssetEntry("FOLDER_LINK", "link_f", "sym folder link", false, false, true));
|
||||
addEntry(LLAssetType::AT_CURRENT_OUTFIT, new AssetEntry("FOLDER_LINK", "current", "current outfit", false, false, false));
|
||||
addEntry(LLAssetType::AT_OUTFIT, new AssetEntry("OUTFIT", "outfit", "outfit", false, false, false));
|
||||
addEntry(LLAssetType::AT_MY_OUTFITS, new AssetEntry("MY_OUTFITS", "my_otfts", "my outfits", false, false, false));
|
||||
addEntry(LLAssetType::AT_MESH, new AssetEntry("MESH", "mesh", "mesh", false, true, true));
|
||||
addEntry(LLAssetType::AT_NONE, new AssetEntry("NONE", "-1", NULL, false, false, false));
|
||||
};
|
||||
|
||||
@@ -206,63 +208,22 @@ LLAssetType::EType LLAssetType::lookupHumanReadable(const std::string& readable_
|
||||
return AT_NONE;
|
||||
}
|
||||
|
||||
EDragAndDropType LLAssetType::lookupDragAndDropType( EType asset )
|
||||
{
|
||||
switch( asset )
|
||||
{
|
||||
case AT_TEXTURE: return DAD_TEXTURE;
|
||||
case AT_SOUND: return DAD_SOUND;
|
||||
case AT_CALLINGCARD: return DAD_CALLINGCARD;
|
||||
case AT_LANDMARK: return DAD_LANDMARK;
|
||||
case AT_SCRIPT: return DAD_NONE;
|
||||
case AT_CLOTHING: return DAD_CLOTHING;
|
||||
case AT_OBJECT: return DAD_OBJECT;
|
||||
case AT_NOTECARD: return DAD_NOTECARD;
|
||||
case AT_CATEGORY: return DAD_CATEGORY;
|
||||
case AT_ROOT_CATEGORY: return DAD_ROOT_CATEGORY;
|
||||
case AT_LSL_TEXT: return DAD_SCRIPT;
|
||||
case AT_BODYPART: return DAD_BODYPART;
|
||||
case AT_ANIMATION: return DAD_ANIMATION;
|
||||
case AT_GESTURE: return DAD_GESTURE;
|
||||
case AT_FAVORITE: return DAD_CATEGORY;
|
||||
case AT_LINK: return DAD_LINK;
|
||||
case AT_LINK_FOLDER: return DAD_LINK;
|
||||
case AT_CURRENT_OUTFIT: return DAD_LINK;
|
||||
case AT_OUTFIT: return DAD_LINK;
|
||||
case AT_MY_OUTFITS: return DAD_CATEGORY;
|
||||
default: return DAD_NONE;
|
||||
};
|
||||
}
|
||||
|
||||
// static. Generate a good default description
|
||||
void LLAssetType::generateDescriptionFor(LLAssetType::EType type,
|
||||
std::string& desc)
|
||||
{
|
||||
const S32 BUF_SIZE = 30;
|
||||
char time_str[BUF_SIZE]; /* Flawfinder: ignore */
|
||||
time_t now;
|
||||
time(&now);
|
||||
memset(time_str, '\0', BUF_SIZE);
|
||||
strftime(time_str, BUF_SIZE - 1, "%Y-%m-%d %H:%M:%S ", localtime(&now));
|
||||
desc.assign(time_str);
|
||||
desc.append(LLAssetType::lookupHumanReadable(type));
|
||||
}
|
||||
//NOTE: LLAssetType::lookupDragAndDropType & LLAssetType::generateDescriptionFor moved to newview/llviewerassettype.h
|
||||
|
||||
// static
|
||||
bool LLAssetType::lookupCanLink(EType asset_type)
|
||||
{
|
||||
//Check that enabling all these other types as linkable doesn't break things.
|
||||
/*const LLAssetDictionary *dict = LLAssetDictionary::getInstance();
|
||||
const LLAssetDictionary *dict = LLAssetDictionary::getInstance();
|
||||
const AssetEntry *entry = dict->lookup(asset_type);
|
||||
if (entry)
|
||||
{
|
||||
return entry->mCanLink;
|
||||
}
|
||||
return false;
|
||||
*/
|
||||
|
||||
return (asset_type == AT_CLOTHING || asset_type == AT_OBJECT || asset_type == AT_CATEGORY ||
|
||||
asset_type == AT_BODYPART || asset_type == AT_GESTURE);
|
||||
/*return (asset_type == AT_CLOTHING || asset_type == AT_OBJECT || asset_type == AT_CATEGORY ||
|
||||
asset_type == AT_BODYPART || asset_type == AT_GESTURE);*/
|
||||
}
|
||||
|
||||
// static
|
||||
|
||||
@@ -84,7 +84,7 @@ public:
|
||||
// A root category is a user's root inventory category. We
|
||||
// decided to expose it visually, so it seems logical to fold
|
||||
// it into the asset types.
|
||||
AT_ROOT_CATEGORY = 9,
|
||||
//AT_ROOT_CATEGORY = 9,
|
||||
|
||||
// The LSL is the brand spanking new scripting language. We've
|
||||
// split it into a text and bytecode representation.
|
||||
@@ -101,15 +101,15 @@ public:
|
||||
// This asset type is meant to only be used as a marker for a
|
||||
// category preferred type. Using this, we can throw things in
|
||||
// the trash before completely deleting.
|
||||
AT_TRASH = 14,
|
||||
//AT_TRASH = 14,
|
||||
|
||||
// This is a marker for a folder meant for snapshots. No
|
||||
// actual assets will be snapshots, though if there were, you
|
||||
// could interpret them as textures.
|
||||
AT_SNAPSHOT_CATEGORY = 15,
|
||||
//AT_SNAPSHOT_CATEGORY = 15,
|
||||
|
||||
// This is used to stuff lost&found items into
|
||||
AT_LOST_AND_FOUND = 16,
|
||||
//AT_LOST_AND_FOUND = 16,
|
||||
|
||||
// uncompressed sound
|
||||
AT_SOUND_WAV = 17,
|
||||
@@ -131,20 +131,24 @@ public:
|
||||
// simstate file
|
||||
AT_SIMSTATE = 22,
|
||||
|
||||
AT_FAVORITE = 23,
|
||||
//AT_FAVORITE = 23,
|
||||
|
||||
// Inventory symbolic link
|
||||
AT_LINK = 24,
|
||||
|
||||
// Inventory folder link
|
||||
AT_LINK_FOLDER = 25,
|
||||
|
||||
|
||||
AT_CURRENT_OUTFIT = 46,
|
||||
|
||||
AT_OUTFIT = 47,
|
||||
|
||||
AT_MY_OUTFITS = 48,
|
||||
|
||||
AT_MESH = 49,
|
||||
// Mesh data in our proprietary SLM format
|
||||
|
||||
AT_COUNT = 50,
|
||||
// +*********************************************+
|
||||
// | TO ADD AN ELEMENT TO THIS ENUM: |
|
||||
// +*********************************************+
|
||||
@@ -154,8 +158,6 @@ public:
|
||||
// | 4. ADD TO LLAssetType::mAssetTypeHumanNames |
|
||||
// +*********************************************+
|
||||
|
||||
AT_COUNT = 49,
|
||||
|
||||
AT_NONE = -1
|
||||
};
|
||||
|
||||
@@ -169,12 +171,7 @@ public:
|
||||
static EType lookupHumanReadable(const std::string& readable_name);
|
||||
static const char* lookupHumanReadable(EType asset_type);
|
||||
|
||||
static EDragAndDropType lookupDragAndDropType( EType );
|
||||
|
||||
// Generate a good default description. You may want to add a verb
|
||||
// or agent name after this depending on your application.
|
||||
static void generateDescriptionFor(LLAssetType::EType type,
|
||||
std::string& desc);
|
||||
//NOTE: LLAssetType::lookupDragAndDropType & LLAssetType::generateDescriptionFor moved to newview/llviewerassettype.h
|
||||
|
||||
static EType getType(const std::string& desc_name);
|
||||
static const std::string& getDesc(EType asset_type);
|
||||
|
||||
@@ -25,10 +25,6 @@
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
/*
|
||||
Ported to Phoenix by Wolfspirit Magic.
|
||||
*/
|
||||
#include "linden_common.h"
|
||||
|
||||
#include "llavatarname.h"
|
||||
@@ -52,7 +48,7 @@ LLAvatarName::LLAvatarName()
|
||||
mLegacyFirstName(),
|
||||
mLegacyLastName(),
|
||||
mIsDisplayNameDefault(false),
|
||||
mIsDummy(false),
|
||||
mIsTemporaryName(false),
|
||||
mExpires(F64_MAX),
|
||||
mNextUpdate(0.0)
|
||||
{ }
|
||||
@@ -94,21 +90,16 @@ void LLAvatarName::fromLLSD(const LLSD& sd)
|
||||
std::string LLAvatarName::getCompleteName(bool linefeed) const
|
||||
{
|
||||
std::string name;
|
||||
if (!mUsername.empty())
|
||||
if (mUsername.empty() || mIsDisplayNameDefault)
|
||||
// If the display name feature is off
|
||||
// OR this particular display name is defaulted (i.e. based on user name),
|
||||
// then display only the easier to read instance of the person's name.
|
||||
{
|
||||
if (linefeed)
|
||||
{
|
||||
name = mDisplayName + "\n(" + mUsername + ")";
|
||||
}
|
||||
else
|
||||
{
|
||||
name = mDisplayName + " (" + mUsername + ")";
|
||||
}
|
||||
name = mDisplayName;
|
||||
}
|
||||
else
|
||||
{
|
||||
// ...display names are off, legacy name is in mDisplayName
|
||||
name = mDisplayName;
|
||||
name = mDisplayName + (linefeed ? "\n(" : "(") + mUsername + ")";
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
@@ -79,7 +79,7 @@ public:
|
||||
// Under error conditions, we may insert "dummy" records with
|
||||
// names like "???" into caches as placeholders. These can be
|
||||
// shown in UI, but are not serialized.
|
||||
bool mIsDummy;
|
||||
bool mIsTemporaryName;
|
||||
|
||||
// Names can change, so need to keep track of when name was
|
||||
// last checked.
|
||||
|
||||
@@ -56,7 +56,8 @@ typedef enum e_chat_type
|
||||
CHAT_TYPE_STOP = 5,
|
||||
CHAT_TYPE_DEBUG_MSG = 6,
|
||||
CHAT_TYPE_REGION = 7,
|
||||
CHAT_TYPE_OWNER = 8
|
||||
CHAT_TYPE_OWNER = 8,
|
||||
CHAT_TYPE_DIRECT = 9 // From llRegionSayTo()
|
||||
} EChatType;
|
||||
|
||||
typedef enum e_chat_audible_level
|
||||
|
||||
@@ -42,5 +42,6 @@ const U8 CLICK_ACTION_PAY = 3;
|
||||
const U8 CLICK_ACTION_OPEN = 4;
|
||||
const U8 CLICK_ACTION_PLAY = 5;
|
||||
const U8 CLICK_ACTION_OPEN_MEDIA = 6;
|
||||
|
||||
const U8 CLICK_ACTION_ZOOM = 7;
|
||||
// DO NOT CHANGE THE SEQUENCE OF THIS LIST!!
|
||||
#endif
|
||||
|
||||
@@ -38,6 +38,8 @@
|
||||
#include <iosfwd>
|
||||
#include <string>
|
||||
|
||||
#include "llpreprocessor.h"
|
||||
|
||||
#include "stdtypes.h"
|
||||
|
||||
/**
|
||||
|
||||
@@ -56,9 +56,8 @@
|
||||
#include "llsdserialize.h"
|
||||
#include "llstl.h"
|
||||
#include "lltimer.h"
|
||||
#include "aithreadsafe.h"
|
||||
|
||||
extern apr_thread_mutex_t* gCallStacksLogMutexp;
|
||||
#include "aithreadsafe.h"
|
||||
|
||||
namespace {
|
||||
#if !LL_WINDOWS
|
||||
@@ -881,8 +880,8 @@ You get:
|
||||
|
||||
*/
|
||||
|
||||
apr_thread_mutex_t* gLogMutexp;
|
||||
apr_thread_mutex_t* gCallStacksLogMutexp;
|
||||
extern apr_thread_mutex_t* gLogMutexp;
|
||||
extern apr_thread_mutex_t* gCallStacksLogMutexp;
|
||||
|
||||
namespace {
|
||||
bool checkLevelMap(const LevelMap& map, const std::string& key,
|
||||
|
||||
@@ -107,7 +107,14 @@ const int LL_ERR_PRICE_MISMATCH = -23018;
|
||||
|
||||
#define llwarning(msg, num) llwarns << "Warning # " << num << ": " << msg << llendl;
|
||||
|
||||
#define llassert_always(func) if (LL_UNLIKELY(!(func))) llerrs << "ASSERT (" << #func << ")" << llendl;
|
||||
#define liru_slashpos std::string(__FILE__).find_last_of("/\\")
|
||||
#define liru_slashpos2 std::string(__FILE__).substr(0,liru_slashpos).find_last_of("/\\")
|
||||
#define liru_assert_strip /*strip path down to lastlevel directory and filename for assert.*/\
|
||||
(liru_slashpos == std::string::npos ? std::string(__FILE__)/*just filename, print as is*/\
|
||||
: liru_slashpos2 == std::string::npos ? std::string(__FILE__)/*Apparently, we're in / or perhaps the top of the drive, print as is*/\
|
||||
: std::string(__FILE__).substr(1+liru_slashpos2))/*print foo/bar.cpp or perhaps foo\bar.cpp*/
|
||||
|
||||
#define llassert_always(func) if (LL_UNLIKELY(!(func))) llerrs <<"\nASSERT(" #func ")\nfile:"<<liru_assert_strip<<" line:"<<__LINE__ << llendl;
|
||||
|
||||
#ifdef SHOW_ASSERT
|
||||
#define llassert(func) llassert_always(func)
|
||||
|
||||
@@ -44,63 +44,40 @@
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//std::list<LLEventTimer*> LLEventTimer::sActiveList;
|
||||
|
||||
LLEventTimer::LLEventTimer(F32 period)
|
||||
: mEventTimer()
|
||||
{
|
||||
mPeriod = period;
|
||||
//sActiveList.push_back(this);
|
||||
}
|
||||
|
||||
LLEventTimer::LLEventTimer(const LLDate& time)
|
||||
: mEventTimer()
|
||||
{
|
||||
mPeriod = (F32)(time.secondsSinceEpoch() - LLDate::now().secondsSinceEpoch());
|
||||
//sActiveList.push_back(this);
|
||||
}
|
||||
|
||||
|
||||
LLEventTimer::~LLEventTimer()
|
||||
LLEventTimer::~LLEventTimer()
|
||||
{
|
||||
//sActiveList.remove(this);
|
||||
}
|
||||
|
||||
//static
|
||||
void LLEventTimer::updateClass()
|
||||
{
|
||||
std::list<LLEventTimer*> completed_timers;
|
||||
|
||||
/*{
|
||||
for (std::list<LLEventTimer*>::iterator iter = sActiveList.begin(); iter != sActiveList.end(); )
|
||||
{
|
||||
LLEventTimer* timer = *iter++;
|
||||
F32 et = timer->mEventTimer.getElapsedTimeF32();
|
||||
if (timer->mEventTimer.getStarted() && et > timer->mPeriod) {
|
||||
timer->mEventTimer.reset();
|
||||
if ( timer->tick() )
|
||||
{
|
||||
completed_timers.push_back( timer );
|
||||
}
|
||||
}
|
||||
}
|
||||
}*/
|
||||
for (instance_iter iter = beginInstances(); iter != endInstances(); )
|
||||
{
|
||||
LLInstanceTrackerScopedGuard guard;
|
||||
for (instance_iter iter = guard.beginInstances(); iter != guard.endInstances(); )
|
||||
{
|
||||
LLEventTimer& timer = *iter++;
|
||||
F32 et = timer.mEventTimer.getElapsedTimeF32();
|
||||
if (timer.mEventTimer.getStarted() && et > timer.mPeriod) {
|
||||
timer.mEventTimer.reset();
|
||||
if ( timer.tick() )
|
||||
{
|
||||
completed_timers.push_back( &timer );
|
||||
}
|
||||
LLEventTimer& timer = *iter++;
|
||||
F32 et = timer.mEventTimer.getElapsedTimeF32();
|
||||
if (timer.mEventTimer.getStarted() && et > timer.mPeriod) {
|
||||
timer.mEventTimer.reset();
|
||||
if ( timer.tick() )
|
||||
{
|
||||
completed_timers.push_back( &timer );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if ( completed_timers.size() > 0 )
|
||||
{
|
||||
for (std::list<LLEventTimer*>::iterator completed_iter = completed_timers.begin();
|
||||
|
||||
@@ -56,11 +56,6 @@ public:
|
||||
protected:
|
||||
LLTimer mEventTimer;
|
||||
F32 mPeriod;
|
||||
|
||||
//private:
|
||||
//list of active timers
|
||||
// static std::list<LLEventTimer*> sActiveList; // TODO should this be a vector
|
||||
};
|
||||
|
||||
|
||||
#endif //LL_EVENTTIMER_H
|
||||
|
||||
@@ -72,7 +72,10 @@ public:
|
||||
FTM_UPDATE_GRASS,
|
||||
FTM_UPDATE_TREE,
|
||||
FTM_UPDATE_AVATAR,
|
||||
|
||||
FTM_UPDATE_RIGGED_VOLUME,
|
||||
FTM_SKIN_RIGGED,
|
||||
FTM_RIGGED_OCTREE,
|
||||
|
||||
// common render components
|
||||
FTM_SHADOW_GEOMETRY,
|
||||
FTM_SHADOW_RENDER,
|
||||
@@ -131,8 +134,21 @@ public:
|
||||
FTM_STATESORT,
|
||||
FTM_STATESORT_DRAWABLE,
|
||||
FTM_STATESORT_POSTSORT,
|
||||
FTM_MESH_UPDATE,
|
||||
FTM_MESH_LOCK1,
|
||||
FTM_MESH_LOCK2,
|
||||
FTM_LOAD_MESH_LOD,
|
||||
FTM_REBUILD_VBO,
|
||||
FTM_REBUILD_VOLUME_VB,
|
||||
FTM_FACE_GET_GEOM,
|
||||
FTM_FACE_GEOM_POSITION,
|
||||
FTM_FACE_GEOM_NORMAL,
|
||||
FTM_FACE_GEOM_TEXTURE,
|
||||
FTM_FACE_GEOM_COLOR,
|
||||
FTM_FACE_GEOM_EMISSIVE,
|
||||
FTM_FACE_GEOM_WEIGHTS,
|
||||
FTM_FACE_GEOM_BINORMAL,
|
||||
FTM_FACE_GEOM_INDEX,
|
||||
FTM_REBUILD_BRIDGE_VB,
|
||||
FTM_REBUILD_HUD_VB,
|
||||
FTM_REBUILD_TERRAIN_VB,
|
||||
@@ -206,6 +222,13 @@ public:
|
||||
FTM_TEMP6,
|
||||
FTM_TEMP7,
|
||||
FTM_TEMP8,
|
||||
FTM_TEMP9,
|
||||
FTM_TEMP10,
|
||||
FTM_TEMP11,
|
||||
FTM_TEMP12,
|
||||
FTM_TEMP13,
|
||||
FTM_TEMP14,
|
||||
FTM_TEMP15,
|
||||
|
||||
FTM_OTHER, // Special, used by display code
|
||||
|
||||
|
||||
175
indra/llcommon/llfoldertype.cpp
Normal file
175
indra/llcommon/llfoldertype.cpp
Normal file
@@ -0,0 +1,175 @@
|
||||
/**
|
||||
* @file llfoldertype.cpp
|
||||
* @brief Implementatino of LLFolderType functionality.
|
||||
*
|
||||
* $LicenseInfo:firstyear=2001&license=viewergpl$
|
||||
*
|
||||
* Copyright (c) 2001-2010, Linden Research, Inc.
|
||||
*
|
||||
* Second Life Viewer Source Code
|
||||
* The source code in this file ("Source Code") is provided by Linden Lab
|
||||
* to you under the terms of the GNU General Public License, version 2.0
|
||||
* ("GPL"), unless you have obtained a separate licensing agreement
|
||||
* ("Other License"), formally executed by you and Linden Lab. Terms of
|
||||
* the GPL can be found in doc/GPL-license.txt in this distribution, or
|
||||
* online at http://secondlife.com/developers/opensource/gplv2
|
||||
*
|
||||
* There are special exceptions to the terms and conditions of the GPL as
|
||||
* it is applied to this Source Code. View the full text of the exception
|
||||
* in the file doc/FLOSS-exception.txt in this software distribution, or
|
||||
* online at
|
||||
* http://secondlife.com/developers/opensource/flossexception
|
||||
*
|
||||
* By copying, modifying or distributing this software, you acknowledge
|
||||
* that you have read and understood your obligations described above,
|
||||
* and agree to abide by those obligations.
|
||||
*
|
||||
* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
|
||||
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
|
||||
* COMPLETENESS OR PERFORMANCE.
|
||||
* $/LicenseInfo$
|
||||
*
|
||||
*/
|
||||
|
||||
#include "linden_common.h"
|
||||
|
||||
#include "llfoldertype.h"
|
||||
#include "lldictionary.h"
|
||||
#include "llmemory.h"
|
||||
#include "llsingleton.h"
|
||||
|
||||
///----------------------------------------------------------------------------
|
||||
/// Class LLFolderType
|
||||
///----------------------------------------------------------------------------
|
||||
struct FolderEntry : public LLDictionaryEntry
|
||||
{
|
||||
FolderEntry(const std::string &type_name, // 8 character limit!
|
||||
bool is_protected) // can the viewer change categories of this type?
|
||||
:
|
||||
LLDictionaryEntry(type_name),
|
||||
mIsProtected(is_protected)
|
||||
{
|
||||
llassert(type_name.length() <= 8);
|
||||
}
|
||||
|
||||
const bool mIsProtected;
|
||||
};
|
||||
|
||||
class LLFolderDictionary : public LLSingleton<LLFolderDictionary>,
|
||||
public LLDictionary<LLFolderType::EType, FolderEntry>
|
||||
{
|
||||
public:
|
||||
LLFolderDictionary();
|
||||
protected:
|
||||
virtual LLFolderType::EType notFound() const
|
||||
{
|
||||
return LLFolderType::FT_NONE;
|
||||
}
|
||||
};
|
||||
|
||||
LLFolderDictionary::LLFolderDictionary()
|
||||
{
|
||||
// TYPE NAME PROTECTED
|
||||
// |-----------|---------|
|
||||
addEntry(LLFolderType::FT_TEXTURE, new FolderEntry("texture", TRUE));
|
||||
addEntry(LLFolderType::FT_SOUND, new FolderEntry("sound", TRUE));
|
||||
addEntry(LLFolderType::FT_CALLINGCARD, new FolderEntry("callcard", TRUE));
|
||||
addEntry(LLFolderType::FT_LANDMARK, new FolderEntry("landmark", TRUE));
|
||||
addEntry(LLFolderType::FT_CLOTHING, new FolderEntry("clothing", TRUE));
|
||||
addEntry(LLFolderType::FT_OBJECT, new FolderEntry("object", TRUE));
|
||||
addEntry(LLFolderType::FT_NOTECARD, new FolderEntry("notecard", TRUE));
|
||||
addEntry(LLFolderType::FT_ROOT_INVENTORY, new FolderEntry("root_inv", TRUE));
|
||||
addEntry(LLFolderType::FT_LSL_TEXT, new FolderEntry("lsltext", TRUE));
|
||||
addEntry(LLFolderType::FT_BODYPART, new FolderEntry("bodypart", TRUE));
|
||||
addEntry(LLFolderType::FT_TRASH, new FolderEntry("trash", TRUE));
|
||||
addEntry(LLFolderType::FT_SNAPSHOT_CATEGORY, new FolderEntry("snapshot", TRUE));
|
||||
addEntry(LLFolderType::FT_LOST_AND_FOUND, new FolderEntry("lstndfnd", TRUE));
|
||||
addEntry(LLFolderType::FT_ANIMATION, new FolderEntry("animatn", TRUE));
|
||||
addEntry(LLFolderType::FT_GESTURE, new FolderEntry("gesture", TRUE));
|
||||
addEntry(LLFolderType::FT_FAVORITE, new FolderEntry("favorite", TRUE));
|
||||
|
||||
for (S32 ensemble_num = S32(LLFolderType::FT_ENSEMBLE_START); ensemble_num <= S32(LLFolderType::FT_ENSEMBLE_END); ensemble_num++)
|
||||
{
|
||||
addEntry(LLFolderType::EType(ensemble_num), new FolderEntry("ensemble", FALSE));
|
||||
}
|
||||
|
||||
addEntry(LLFolderType::FT_CURRENT_OUTFIT, new FolderEntry("current", TRUE));
|
||||
addEntry(LLFolderType::FT_OUTFIT, new FolderEntry("outfit", FALSE));
|
||||
addEntry(LLFolderType::FT_MY_OUTFITS, new FolderEntry("my_otfts", TRUE));
|
||||
|
||||
addEntry(LLFolderType::FT_MESH, new FolderEntry("mesh", TRUE));
|
||||
|
||||
addEntry(LLFolderType::FT_INBOX, new FolderEntry("inbox", TRUE));
|
||||
addEntry(LLFolderType::FT_OUTBOX, new FolderEntry("outbox", TRUE));
|
||||
addEntry(LLFolderType::FT_BASIC_ROOT, new FolderEntry("basic_rt", TRUE));
|
||||
|
||||
addEntry(LLFolderType::FT_NONE, new FolderEntry("-1", FALSE));
|
||||
};
|
||||
|
||||
// static
|
||||
LLFolderType::EType LLFolderType::lookup(const std::string& name)
|
||||
{
|
||||
return LLFolderDictionary::getInstance()->lookup(name);
|
||||
}
|
||||
|
||||
// static
|
||||
const std::string &LLFolderType::lookup(LLFolderType::EType folder_type)
|
||||
{
|
||||
const FolderEntry *entry = LLFolderDictionary::getInstance()->lookup(folder_type);
|
||||
if (entry)
|
||||
{
|
||||
return entry->mName;
|
||||
}
|
||||
else
|
||||
{
|
||||
return badLookup();
|
||||
}
|
||||
}
|
||||
|
||||
// static
|
||||
// Only ensembles and plain folders aren't protected. "Protected" means
|
||||
// you can't change certain properties such as their type.
|
||||
bool LLFolderType::lookupIsProtectedType(EType folder_type)
|
||||
{
|
||||
const LLFolderDictionary *dict = LLFolderDictionary::getInstance();
|
||||
const FolderEntry *entry = dict->lookup(folder_type);
|
||||
if (entry)
|
||||
{
|
||||
return entry->mIsProtected;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// static
|
||||
bool LLFolderType::lookupIsEnsembleType(EType folder_type)
|
||||
{
|
||||
return (folder_type >= FT_ENSEMBLE_START &&
|
||||
folder_type <= FT_ENSEMBLE_END);
|
||||
}
|
||||
|
||||
// static
|
||||
LLAssetType::EType LLFolderType::folderTypeToAssetType(LLFolderType::EType folder_type)
|
||||
{
|
||||
if (LLAssetType::lookup(LLAssetType::EType(folder_type)) == LLAssetType::badLookup())
|
||||
{
|
||||
llwarns << "Converting to unknown asset type " << folder_type << llendl;
|
||||
}
|
||||
return (LLAssetType::EType)folder_type;
|
||||
}
|
||||
|
||||
// static
|
||||
LLFolderType::EType LLFolderType::assetTypeToFolderType(LLAssetType::EType asset_type)
|
||||
{
|
||||
if (LLFolderType::lookup(LLFolderType::EType(asset_type)) == LLFolderType::badLookup())
|
||||
{
|
||||
llwarns << "Converting to unknown folder type " << asset_type << llendl;
|
||||
}
|
||||
return (LLFolderType::EType)asset_type;
|
||||
}
|
||||
|
||||
// static
|
||||
const std::string &LLFolderType::badLookup()
|
||||
{
|
||||
static const std::string sBadLookup = "llfoldertype_bad_lookup";
|
||||
return sBadLookup;
|
||||
}
|
||||
118
indra/llcommon/llfoldertype.h
Normal file
118
indra/llcommon/llfoldertype.h
Normal file
@@ -0,0 +1,118 @@
|
||||
/**
|
||||
* @file llfoldertype.h
|
||||
* @brief Declaration of LLFolderType.
|
||||
*
|
||||
* $LicenseInfo:firstyear=2001&license=viewergpl$
|
||||
*
|
||||
* Copyright (c) 2001-2010, Linden Research, Inc.
|
||||
*
|
||||
* Second Life Viewer Source Code
|
||||
* The source code in this file ("Source Code") is provided by Linden Lab
|
||||
* to you under the terms of the GNU General Public License, version 2.0
|
||||
* ("GPL"), unless you have obtained a separate licensing agreement
|
||||
* ("Other License"), formally executed by you and Linden Lab. Terms of
|
||||
* the GPL can be found in doc/GPL-license.txt in this distribution, or
|
||||
* online at http://secondlife.com/developers/opensource/gplv2
|
||||
*
|
||||
* There are special exceptions to the terms and conditions of the GPL as
|
||||
* it is applied to this Source Code. View the full text of the exception
|
||||
* in the file doc/FLOSS-exception.txt in this software distribution, or
|
||||
* online at
|
||||
* http://secondlife.com/developers/opensource/flossexception
|
||||
*
|
||||
* By copying, modifying or distributing this software, you acknowledge
|
||||
* that you have read and understood your obligations described above,
|
||||
* and agree to abide by those obligations.
|
||||
*
|
||||
* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
|
||||
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
|
||||
* COMPLETENESS OR PERFORMANCE.
|
||||
* $/LicenseInfo$
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LL_LLFOLDERTYPE_H
|
||||
#define LL_LLFOLDERTYPE_H
|
||||
|
||||
#include <string>
|
||||
#include "llassettype.h"
|
||||
|
||||
// This class handles folder types (similar to assettype, except for folders)
|
||||
// and operations on those.
|
||||
class LL_COMMON_API LLFolderType
|
||||
{
|
||||
public:
|
||||
// ! BACKWARDS COMPATIBILITY ! Folder type enums must match asset type enums.
|
||||
enum EType
|
||||
{
|
||||
FT_TEXTURE = 0,
|
||||
|
||||
FT_SOUND = 1,
|
||||
|
||||
FT_CALLINGCARD = 2,
|
||||
|
||||
FT_LANDMARK = 3,
|
||||
|
||||
FT_CLOTHING = 5,
|
||||
|
||||
FT_OBJECT = 6,
|
||||
|
||||
FT_NOTECARD = 7,
|
||||
|
||||
FT_ROOT_INVENTORY = 8,
|
||||
// We'd really like to change this to 9 since AT_CATEGORY is 8,
|
||||
// but "My Inventory" has been type 8 for a long time.
|
||||
|
||||
FT_LSL_TEXT = 10,
|
||||
|
||||
FT_BODYPART = 13,
|
||||
|
||||
FT_TRASH = 14,
|
||||
|
||||
FT_SNAPSHOT_CATEGORY = 15,
|
||||
|
||||
FT_LOST_AND_FOUND = 16,
|
||||
|
||||
FT_ANIMATION = 20,
|
||||
|
||||
FT_GESTURE = 21,
|
||||
|
||||
FT_FAVORITE = 23,
|
||||
|
||||
FT_ENSEMBLE_START = 26,
|
||||
FT_ENSEMBLE_END = 45,
|
||||
// This range is reserved for special clothing folder types.
|
||||
|
||||
FT_CURRENT_OUTFIT = 46,
|
||||
FT_OUTFIT = 47,
|
||||
FT_MY_OUTFITS = 48,
|
||||
|
||||
FT_MESH = 49,
|
||||
|
||||
FT_INBOX = 50,
|
||||
FT_OUTBOX = 51,
|
||||
|
||||
FT_BASIC_ROOT = 52,
|
||||
|
||||
FT_COUNT,
|
||||
|
||||
FT_NONE = -1
|
||||
};
|
||||
|
||||
static EType lookup(const std::string& type_name);
|
||||
static const std::string& lookup(EType folder_type);
|
||||
|
||||
static bool lookupIsProtectedType(EType folder_type);
|
||||
static bool lookupIsEnsembleType(EType folder_type);
|
||||
|
||||
static LLAssetType::EType folderTypeToAssetType(LLFolderType::EType folder_type);
|
||||
static LLFolderType::EType assetTypeToFolderType(LLAssetType::EType asset_type);
|
||||
|
||||
static const std::string& badLookup(); // error string when a lookup fails
|
||||
|
||||
protected:
|
||||
LLFolderType() {}
|
||||
~LLFolderType() {}
|
||||
};
|
||||
|
||||
#endif // LL_LLFOLDERTYPE_H
|
||||
@@ -35,13 +35,15 @@
|
||||
//static
|
||||
void * & LLInstanceTrackerBase::getInstances(std::type_info const & info)
|
||||
{
|
||||
static std::map<std::string, void *> instances;
|
||||
typedef std::map<std::string, void *> InstancesMap;
|
||||
static InstancesMap instances;
|
||||
|
||||
std::string k = info.name();
|
||||
if(instances.find(k) == instances.end())
|
||||
{
|
||||
instances[k] = NULL;
|
||||
}
|
||||
|
||||
return instances[k];
|
||||
// std::map::insert() is just what we want here. You attempt to insert a
|
||||
// (key, value) pair. If the specified key doesn't yet exist, it inserts
|
||||
// the pair and returns a std::pair of (iterator, true). If the specified
|
||||
// key DOES exist, insert() simply returns (iterator, false). One lookup
|
||||
// handles both cases.
|
||||
return instances.insert(InstancesMap::value_type(info.name(),
|
||||
InstancesMap::mapped_type()))
|
||||
.first->second;
|
||||
}
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
#define LL_LLINSTANCETRACKER_H
|
||||
|
||||
#include <map>
|
||||
#include <typeinfo>
|
||||
|
||||
#include "string_table.h"
|
||||
#include <boost/utility.hpp>
|
||||
@@ -48,7 +49,32 @@ class LL_COMMON_API LLInstanceTrackerBase : public boost::noncopyable
|
||||
{
|
||||
protected:
|
||||
static void * & getInstances(std::type_info const & info);
|
||||
|
||||
/// Find or create a STATICDATA instance for the specified TRACKED class.
|
||||
/// STATICDATA must be default-constructible.
|
||||
template<typename STATICDATA, class TRACKED>
|
||||
static STATICDATA& getStatic()
|
||||
{
|
||||
void *& instances = getInstances(typeid(TRACKED));
|
||||
if (! instances)
|
||||
{
|
||||
instances = new STATICDATA;
|
||||
}
|
||||
return *static_cast<STATICDATA*>(instances);
|
||||
}
|
||||
|
||||
/// It's not essential to derive your STATICDATA (for use with
|
||||
/// getStatic()) from StaticBase; it's just that both known
|
||||
/// implementations do.
|
||||
struct StaticBase
|
||||
{
|
||||
StaticBase():
|
||||
sIterationNestDepth(0)
|
||||
{}
|
||||
S32 sIterationNestDepth;
|
||||
};
|
||||
};
|
||||
|
||||
/// This mix-in class adds support for tracking all instances of the specified class parameter T
|
||||
/// The (optional) key associates a value of type KEY with a given instance of T, for quick lookup
|
||||
/// If KEY is not provided, then instances are stored in a simple set
|
||||
@@ -56,15 +82,89 @@ class LL_COMMON_API LLInstanceTrackerBase : public boost::noncopyable
|
||||
template<typename T, typename KEY = T*>
|
||||
class LLInstanceTracker : public LLInstanceTrackerBase
|
||||
{
|
||||
typedef typename std::map<KEY, T*> InstanceMap;
|
||||
typedef LLInstanceTracker<T, KEY> MyT;
|
||||
typedef boost::function<const KEY&(typename InstanceMap::value_type&)> KeyGetter;
|
||||
typedef boost::function<T*(typename InstanceMap::value_type&)> InstancePtrGetter;
|
||||
typedef typename std::map<KEY, T*> InstanceMap;
|
||||
struct StaticData: public StaticBase
|
||||
{
|
||||
InstanceMap sMap;
|
||||
};
|
||||
static StaticData& getStatic() { return LLInstanceTrackerBase::getStatic<StaticData, MyT>(); }
|
||||
static InstanceMap& getMap_() { return getStatic().sMap; }
|
||||
|
||||
public:
|
||||
/// Dereferencing key_iter gives you a const KEY&
|
||||
typedef boost::transform_iterator<KeyGetter, typename InstanceMap::iterator> key_iter;
|
||||
/// Dereferencing instance_iter gives you a T&
|
||||
typedef boost::indirect_iterator< boost::transform_iterator<InstancePtrGetter, typename InstanceMap::iterator> > instance_iter;
|
||||
class instance_iter : public boost::iterator_facade<instance_iter, T, boost::forward_traversal_tag>
|
||||
{
|
||||
public:
|
||||
typedef boost::iterator_facade<instance_iter, T, boost::forward_traversal_tag> super_t;
|
||||
|
||||
instance_iter(const typename InstanceMap::iterator& it)
|
||||
: mIterator(it)
|
||||
{
|
||||
++getStatic().sIterationNestDepth;
|
||||
}
|
||||
|
||||
~instance_iter()
|
||||
{
|
||||
--getStatic().sIterationNestDepth;
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
friend class boost::iterator_core_access;
|
||||
|
||||
void increment() { mIterator++; }
|
||||
bool equal(instance_iter const& other) const
|
||||
{
|
||||
return mIterator == other.mIterator;
|
||||
}
|
||||
|
||||
T& dereference() const
|
||||
{
|
||||
return *(mIterator->second);
|
||||
}
|
||||
|
||||
typename InstanceMap::iterator mIterator;
|
||||
};
|
||||
|
||||
class key_iter : public boost::iterator_facade<key_iter, KEY, boost::forward_traversal_tag>
|
||||
{
|
||||
public:
|
||||
typedef boost::iterator_facade<key_iter, KEY, boost::forward_traversal_tag> super_t;
|
||||
|
||||
key_iter(typename InstanceMap::iterator it)
|
||||
: mIterator(it)
|
||||
{
|
||||
++getStatic().sIterationNestDepth;
|
||||
}
|
||||
|
||||
key_iter(const key_iter& other)
|
||||
: mIterator(other.mIterator)
|
||||
{
|
||||
++getStatic().sIterationNestDepth;
|
||||
}
|
||||
|
||||
~key_iter()
|
||||
{
|
||||
--getStatic().sIterationNestDepth;
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
friend class boost::iterator_core_access;
|
||||
|
||||
void increment() { mIterator++; }
|
||||
bool equal(key_iter const& other) const
|
||||
{
|
||||
return mIterator == other.mIterator;
|
||||
}
|
||||
|
||||
KEY& dereference() const
|
||||
{
|
||||
return const_cast<KEY&>(mIterator->first);
|
||||
}
|
||||
|
||||
typename InstanceMap::iterator mIterator;
|
||||
};
|
||||
|
||||
static T* getInstance(const KEY& k)
|
||||
{
|
||||
@@ -72,57 +172,56 @@ public:
|
||||
return (found == getMap_().end()) ? NULL : found->second;
|
||||
}
|
||||
|
||||
static instance_iter beginInstances()
|
||||
{
|
||||
return instance_iter(getMap_().begin());
|
||||
}
|
||||
|
||||
static instance_iter endInstances()
|
||||
{
|
||||
return instance_iter(getMap_().end());
|
||||
}
|
||||
|
||||
static S32 instanceCount() { return getMap_().size(); }
|
||||
|
||||
static key_iter beginKeys()
|
||||
{
|
||||
return boost::make_transform_iterator(getMap_().begin(),
|
||||
boost::bind(&InstanceMap::value_type::first, _1));
|
||||
return key_iter(getMap_().begin());
|
||||
}
|
||||
static key_iter endKeys()
|
||||
{
|
||||
return boost::make_transform_iterator(getMap_().end(),
|
||||
boost::bind(&InstanceMap::value_type::first, _1));
|
||||
return key_iter(getMap_().end());
|
||||
}
|
||||
static instance_iter beginInstances()
|
||||
{
|
||||
return instance_iter(boost::make_transform_iterator(getMap_().begin(),
|
||||
boost::bind(&InstanceMap::value_type::second, _1)));
|
||||
}
|
||||
static instance_iter endInstances()
|
||||
{
|
||||
return instance_iter(boost::make_transform_iterator(getMap_().end(),
|
||||
boost::bind(&InstanceMap::value_type::second, _1)));
|
||||
}
|
||||
static S32 instanceCount() { return getMap_().size(); }
|
||||
|
||||
protected:
|
||||
LLInstanceTracker(KEY key) { add_(key); }
|
||||
virtual ~LLInstanceTracker() { remove_(); }
|
||||
LLInstanceTracker(KEY key)
|
||||
{
|
||||
// make sure static data outlives all instances
|
||||
getStatic();
|
||||
add_(key);
|
||||
}
|
||||
virtual ~LLInstanceTracker()
|
||||
{
|
||||
// it's unsafe to delete instances of this type while all instances are being iterated over.
|
||||
llassert_always(getStatic().sIterationNestDepth == 0);
|
||||
remove_();
|
||||
}
|
||||
virtual void setKey(KEY key) { remove_(); add_(key); }
|
||||
virtual const KEY& getKey() const { return mKey; }
|
||||
virtual const KEY& getKey() const { return mInstanceKey; }
|
||||
|
||||
private:
|
||||
void add_(KEY key)
|
||||
{
|
||||
mKey = key;
|
||||
mInstanceKey = key;
|
||||
getMap_()[key] = static_cast<T*>(this);
|
||||
}
|
||||
void remove_()
|
||||
{
|
||||
getMap_().erase(mKey);
|
||||
getMap_().erase(mInstanceKey);
|
||||
}
|
||||
|
||||
static InstanceMap& getMap_()
|
||||
{
|
||||
void * & instances = getInstances(typeid(MyT));
|
||||
if (! instances)
|
||||
{
|
||||
instances = new InstanceMap;
|
||||
}
|
||||
return * static_cast<InstanceMap*>(instances);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
KEY mKey;
|
||||
KEY mInstanceKey;
|
||||
};
|
||||
|
||||
/// explicit specialization for default case where KEY is T*
|
||||
@@ -130,73 +229,79 @@ private:
|
||||
template<typename T>
|
||||
class LLInstanceTracker<T, T*> : public LLInstanceTrackerBase
|
||||
{
|
||||
typedef typename std::set<T*> InstanceSet;
|
||||
typedef LLInstanceTracker<T, T*> MyT;
|
||||
typedef typename std::set<T*> InstanceSet;
|
||||
struct StaticData: public StaticBase
|
||||
{
|
||||
InstanceSet sSet;
|
||||
};
|
||||
static StaticData& getStatic() { return LLInstanceTrackerBase::getStatic<StaticData, MyT>(); }
|
||||
static InstanceSet& getSet_() { return getStatic().sSet; }
|
||||
|
||||
public:
|
||||
/// Dereferencing key_iter gives you a T* (since T* is the key)
|
||||
typedef typename InstanceSet::iterator key_iter;
|
||||
/// Dereferencing instance_iter gives you a T&
|
||||
typedef boost::indirect_iterator<key_iter> instance_iter;
|
||||
|
||||
/// for completeness of analogy with the generic implementation
|
||||
static T* getInstance(T* k) { return k; }
|
||||
static S32 instanceCount() { return getSet_().size(); }
|
||||
|
||||
// Instantiate this to get access to iterators for this type. It's a 'guard' in the sense
|
||||
// that it treats deletes of this type as errors as long as there is an instance of
|
||||
// this class alive in scope somewhere (i.e. deleting while iterating is bad).
|
||||
class LLInstanceTrackerScopedGuard
|
||||
class instance_iter : public boost::iterator_facade<instance_iter, T, boost::forward_traversal_tag>
|
||||
{
|
||||
public:
|
||||
LLInstanceTrackerScopedGuard()
|
||||
instance_iter(const typename InstanceSet::iterator& it)
|
||||
: mIterator(it)
|
||||
{
|
||||
++sIterationNestDepth;
|
||||
++getStatic().sIterationNestDepth;
|
||||
}
|
||||
|
||||
~LLInstanceTrackerScopedGuard()
|
||||
instance_iter(const instance_iter& other)
|
||||
: mIterator(other.mIterator)
|
||||
{
|
||||
--sIterationNestDepth;
|
||||
++getStatic().sIterationNestDepth;
|
||||
}
|
||||
|
||||
static instance_iter beginInstances() { return instance_iter(getSet_().begin()); }
|
||||
static instance_iter endInstances() { return instance_iter(getSet_().end()); }
|
||||
static key_iter beginKeys() { return getSet_().begin(); }
|
||||
static key_iter endKeys() { return getSet_().end(); }
|
||||
~instance_iter()
|
||||
{
|
||||
--getStatic().sIterationNestDepth;
|
||||
}
|
||||
|
||||
private:
|
||||
friend class boost::iterator_core_access;
|
||||
|
||||
void increment() { mIterator++; }
|
||||
bool equal(instance_iter const& other) const
|
||||
{
|
||||
return mIterator == other.mIterator;
|
||||
}
|
||||
|
||||
T& dereference() const
|
||||
{
|
||||
return **mIterator;
|
||||
}
|
||||
|
||||
typename InstanceSet::iterator mIterator;
|
||||
};
|
||||
|
||||
static instance_iter beginInstances() { return instance_iter(getSet_().begin()); }
|
||||
static instance_iter endInstances() { return instance_iter(getSet_().end()); }
|
||||
|
||||
protected:
|
||||
LLInstanceTracker()
|
||||
{
|
||||
// it's safe but unpredictable to create instances of this type while all instances are being iterated over. I hate unpredictable. This assert will probably be turned on early in the next development cycle.
|
||||
//llassert(sIterationNestDepth == 0);
|
||||
// make sure static data outlives all instances
|
||||
getStatic();
|
||||
getSet_().insert(static_cast<T*>(this));
|
||||
}
|
||||
virtual ~LLInstanceTracker()
|
||||
{
|
||||
// it's unsafe to delete instances of this type while all instances are being iterated over.
|
||||
llassert(sIterationNestDepth == 0);
|
||||
llassert_always(getStatic().sIterationNestDepth == 0);
|
||||
getSet_().erase(static_cast<T*>(this));
|
||||
}
|
||||
|
||||
LLInstanceTracker(const LLInstanceTracker& other)
|
||||
{
|
||||
//llassert(sIterationNestDepth == 0);
|
||||
getSet_().insert(static_cast<T*>(this));
|
||||
}
|
||||
|
||||
static InstanceSet& getSet_()
|
||||
{
|
||||
void * & instances = getInstances(typeid(MyT));
|
||||
if (! instances)
|
||||
{
|
||||
instances = new InstanceSet;
|
||||
}
|
||||
return * static_cast<InstanceSet *>(instances);
|
||||
}
|
||||
|
||||
static S32 sIterationNestDepth;
|
||||
};
|
||||
|
||||
template <typename T> S32 LLInstanceTracker<T, T*>::sIterationNestDepth = 0;
|
||||
|
||||
#endif
|
||||
|
||||
@@ -118,6 +118,62 @@ public:
|
||||
THROTTLE_BLOCKED, // rate exceed, block key
|
||||
};
|
||||
|
||||
F64 getActionCount(const T& id)
|
||||
{
|
||||
U64 now = 0;
|
||||
if ( mIsRealtime )
|
||||
{
|
||||
now = LLKeyThrottleImpl<T>::getTime();
|
||||
}
|
||||
else
|
||||
{
|
||||
now = LLKeyThrottleImpl<T>::getFrame();
|
||||
}
|
||||
|
||||
if (now >= (m.startTime + m.intervalLength))
|
||||
{
|
||||
if (now < (m.startTime + 2 * m.intervalLength))
|
||||
{
|
||||
// prune old data
|
||||
delete m.prevMap;
|
||||
m.prevMap = m.currMap;
|
||||
m.currMap = new typename LLKeyThrottleImpl<T>::EntryMap;
|
||||
|
||||
m.startTime += m.intervalLength;
|
||||
}
|
||||
else
|
||||
{
|
||||
// lots of time has passed, all data is stale
|
||||
delete m.prevMap;
|
||||
delete m.currMap;
|
||||
m.prevMap = new typename LLKeyThrottleImpl<T>::EntryMap;
|
||||
m.currMap = new typename LLKeyThrottleImpl<T>::EntryMap;
|
||||
|
||||
m.startTime = now;
|
||||
}
|
||||
}
|
||||
|
||||
U32 prevCount = 0;
|
||||
|
||||
typename LLKeyThrottleImpl<T>::EntryMap::const_iterator prev = m.prevMap->find(id);
|
||||
if (prev != m.prevMap->end())
|
||||
{
|
||||
prevCount = prev->second.count;
|
||||
}
|
||||
|
||||
typename LLKeyThrottleImpl<T>::Entry& curr = (*m.currMap)[id];
|
||||
|
||||
// curr.count is the number of keys in
|
||||
// this current 'time slice' from the beginning of it until now
|
||||
// prevCount is the number of keys in the previous
|
||||
// time slice scaled to be one full time slice back from the current
|
||||
// (now) time.
|
||||
|
||||
// compute current, windowed rate
|
||||
F64 timeInCurrent = ((F64)(now - m.startTime) / m.intervalLength);
|
||||
F64 averageCount = curr.count + prevCount * (1.0 - timeInCurrent);
|
||||
return averageCount;
|
||||
}
|
||||
// call each time the key wants use
|
||||
State noteAction(const T& id, S32 weight = 1)
|
||||
{
|
||||
|
||||
@@ -48,6 +48,7 @@ const U32 AGENT_TYPING = 0x0200;
|
||||
const U32 AGENT_CROUCHING = 0x0400;
|
||||
const U32 AGENT_BUSY = 0x0800;
|
||||
const U32 AGENT_ALWAYS_RUN = 0x1000;
|
||||
const U32 AGENT_AUTOPILOT = 0x2000;
|
||||
|
||||
const S32 LSL_REMOTE_DATA_CHANNEL = 1;
|
||||
const S32 LSL_REMOTE_DATA_REQUEST = 2;
|
||||
@@ -184,6 +185,10 @@ const S32 OBJECT_VELOCITY = 5;
|
||||
const S32 OBJECT_OWNER = 6;
|
||||
const S32 OBJECT_GROUP = 7;
|
||||
const S32 OBJECT_CREATOR = 8;
|
||||
const S32 OBJECT_RUNNING_SCRIPT_COUNT = 9;
|
||||
const S32 OBJECT_TOTAL_SCRIPT_COUNT = 10;
|
||||
const S32 OBJECT_SCRIPT_MEMORY = 11;
|
||||
const S32 OBJECT_SCRIPT_TIME = 12;
|
||||
|
||||
// changed() event flags
|
||||
const U32 CHANGED_NONE = 0x0;
|
||||
@@ -198,5 +203,17 @@ const U32 CHANGED_OWNER = 0x80;
|
||||
const U32 CHANGED_REGION = 0x100;
|
||||
const U32 CHANGED_TELEPORT = 0x200;
|
||||
const U32 CHANGED_REGION_START = 0x400;
|
||||
const U32 CHANGED_MEDIA = 0x800;
|
||||
|
||||
// Possible error results
|
||||
const U32 LSL_STATUS_OK = 0;
|
||||
const U32 LSL_STATUS_MALFORMED_PARAMS = 1000;
|
||||
const U32 LSL_STATUS_TYPE_MISMATCH = 1001;
|
||||
const U32 LSL_STATUS_BOUNDS_ERROR = 1002;
|
||||
const U32 LSL_STATUS_NOT_FOUND = 1003;
|
||||
const U32 LSL_STATUS_NOT_SUPPORTED = 1004;
|
||||
const U32 LSL_STATUS_INTERNAL_ERROR = 1999;
|
||||
|
||||
// Start per-function errors below, starting at 2000:
|
||||
const U32 LSL_STATUS_WHITELIST_FAILED = 2001;
|
||||
#endif
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -29,21 +29,97 @@
|
||||
* COMPLETENESS OR PERFORMANCE.
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
#ifndef LL_MEMORY_H
|
||||
#define LL_MEMORY_H
|
||||
#ifndef LLMEMORY_H
|
||||
#define LLMEMORY_H
|
||||
|
||||
|
||||
#include <new>
|
||||
#include <cstdlib>
|
||||
#if !LL_WINDOWS
|
||||
#include <stdint.h> // uintptr_t
|
||||
#endif
|
||||
|
||||
#include "llerror.h"
|
||||
#if LL_DEBUG
|
||||
inline void* ll_aligned_malloc( size_t size, int align )
|
||||
{
|
||||
void* mem = malloc( size + (align - 1) + sizeof(void*) );
|
||||
char* aligned = ((char*)mem) + sizeof(void*);
|
||||
aligned += align - ((uintptr_t)aligned & (align - 1));
|
||||
|
||||
extern S32 gTotalDAlloc;
|
||||
extern S32 gTotalDAUse;
|
||||
extern S32 gDACount;
|
||||
((void**)aligned)[-1] = mem;
|
||||
return aligned;
|
||||
}
|
||||
|
||||
const U32 LLREFCOUNT_SENTINEL_VALUE = 0xAAAAAAAA;
|
||||
inline void ll_aligned_free( void* ptr )
|
||||
{
|
||||
free( ((void**)ptr)[-1] );
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
inline void* ll_aligned_malloc_16(size_t size) // returned hunk MUST be freed with ll_aligned_free_16().
|
||||
{
|
||||
#if defined(LL_WINDOWS)
|
||||
return _mm_malloc(size, 16);
|
||||
#elif defined(LL_DARWIN)
|
||||
return malloc(size); // default osx malloc is 16 byte aligned.
|
||||
#else
|
||||
void *rtn;
|
||||
if (LL_LIKELY(0 == posix_memalign(&rtn, 16, size)))
|
||||
return rtn;
|
||||
else // bad alignment requested, or out of memory
|
||||
return NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
inline void ll_aligned_free_16(void *p)
|
||||
{
|
||||
#if defined(LL_WINDOWS)
|
||||
_mm_free(p);
|
||||
#elif defined(LL_DARWIN)
|
||||
return free(p);
|
||||
#else
|
||||
free(p); // posix_memalign() is compatible with heap deallocator
|
||||
#endif
|
||||
}
|
||||
|
||||
inline void* ll_aligned_malloc_32(size_t size) // returned hunk MUST be freed with ll_aligned_free_32().
|
||||
{
|
||||
#if defined(LL_WINDOWS)
|
||||
return _mm_malloc(size, 32);
|
||||
#elif defined(LL_DARWIN)
|
||||
return ll_aligned_malloc( size, 32 );
|
||||
#else
|
||||
void *rtn;
|
||||
if (LL_LIKELY(0 == posix_memalign(&rtn, 32, size)))
|
||||
return rtn;
|
||||
else // bad alignment requested, or out of memory
|
||||
return NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
inline void ll_aligned_free_32(void *p)
|
||||
{
|
||||
#if defined(LL_WINDOWS)
|
||||
_mm_free(p);
|
||||
#elif defined(LL_DARWIN)
|
||||
ll_aligned_free( p );
|
||||
#else
|
||||
free(p); // posix_memalign() is compatible with heap deallocator
|
||||
#endif
|
||||
}
|
||||
#else // LL_DEBUG
|
||||
// ll_aligned_foo are noops now that we use tcmalloc everywhere (tcmalloc aligns automatically at appropriate intervals)
|
||||
#define ll_aligned_malloc( size, align ) malloc(size)
|
||||
#define ll_aligned_free( ptr ) free(ptr)
|
||||
#define ll_aligned_malloc_16 malloc
|
||||
#define ll_aligned_free_16 free
|
||||
#define ll_aligned_malloc_32 malloc
|
||||
#define ll_aligned_free_32 free
|
||||
#endif // LL_DEBUG
|
||||
|
||||
#ifndef __DEBUG_PRIVATE_MEM__
|
||||
#define __DEBUG_PRIVATE_MEM__ 0
|
||||
#endif
|
||||
|
||||
class LL_COMMON_API LLMemory
|
||||
{
|
||||
@@ -51,431 +127,403 @@ public:
|
||||
static void initClass();
|
||||
static void cleanupClass();
|
||||
static void freeReserve();
|
||||
// Return the resident set size of the current process, in bytes.
|
||||
// Return value is zero if not known.
|
||||
static U64 getCurrentRSS();
|
||||
static U32 getWorkingSetSize();
|
||||
static void* tryToAlloc(void* address, U32 size);
|
||||
static void initMaxHeapSizeGB(F32 max_heap_size_gb, BOOL prevent_heap_failure);
|
||||
static void updateMemoryInfo() ;
|
||||
static void logMemoryInfo(BOOL update = FALSE);
|
||||
static bool isMemoryPoolLow();
|
||||
|
||||
static U32 getAvailableMemKB() ;
|
||||
static U32 getMaxMemKB() ;
|
||||
static U32 getAllocatedMemKB() ;
|
||||
private:
|
||||
static char* reserveMem;
|
||||
static U32 sAvailPhysicalMemInKB ;
|
||||
static U32 sMaxPhysicalMemInKB ;
|
||||
static U32 sAllocatedMemInKB;
|
||||
static U32 sAllocatedPageSizeInKB ;
|
||||
|
||||
static U32 sMaxHeapSizeInKB;
|
||||
static BOOL sEnableMemoryFailurePrevention;
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// RefCount objects should generally only be accessed by way of LLPointer<>'s
|
||||
// NOTE: LLPointer<LLFoo> x = new LLFoo(); MAY NOT BE THREAD SAFE
|
||||
// if LLFoo::LLFoo() does anything like put itself in an update queue.
|
||||
// The queue may get accessed before it gets assigned to x.
|
||||
// The correct implementation is:
|
||||
// LLPointer<LLFoo> x = new LLFoo; // constructor does not do anything interesting
|
||||
// x->instantiate(); // does stuff like place x into an update queue
|
||||
|
||||
// see llthread.h for LLThreadSafeRefCount
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
class LL_COMMON_API LLRefCount
|
||||
class LLMutex ;
|
||||
#if MEM_TRACK_MEM
|
||||
class LL_COMMON_API LLMemTracker
|
||||
{
|
||||
protected:
|
||||
LLRefCount(const LLRefCount&);
|
||||
private:
|
||||
LLRefCount&operator=(const LLRefCount&);
|
||||
LLMemTracker() ;
|
||||
~LLMemTracker() ;
|
||||
|
||||
protected:
|
||||
virtual ~LLRefCount(); // use unref()
|
||||
|
||||
public:
|
||||
LLRefCount();
|
||||
static void release() ;
|
||||
static LLMemTracker* getInstance() ;
|
||||
|
||||
void ref()
|
||||
{
|
||||
mRef++;
|
||||
}
|
||||
void track(const char* function, const int line) ;
|
||||
void preDraw(BOOL pause) ;
|
||||
void postDraw() ;
|
||||
const char* getNextLine() ;
|
||||
|
||||
S32 unref()
|
||||
{
|
||||
llassert(mRef >= 1);
|
||||
if (0 == --mRef)
|
||||
{
|
||||
delete this;
|
||||
return 0;
|
||||
}
|
||||
return mRef;
|
||||
}
|
||||
|
||||
S32 getNumRefs() const
|
||||
{
|
||||
return mRef;
|
||||
}
|
||||
|
||||
private:
|
||||
S32 mRef;
|
||||
private:
|
||||
static LLMemTracker* sInstance ;
|
||||
|
||||
char** mStringBuffer ;
|
||||
S32 mCapacity ;
|
||||
U32 mLastAllocatedMem ;
|
||||
S32 mCurIndex ;
|
||||
S32 mCounter;
|
||||
S32 mDrawnIndex;
|
||||
S32 mNumOfDrawn;
|
||||
BOOL mPaused;
|
||||
LLMutex* mMutexp ;
|
||||
};
|
||||
|
||||
#define MEM_TRACK_RELEASE LLMemTracker::release() ;
|
||||
#define MEM_TRACK LLMemTracker::getInstance()->track(__FUNCTION__, __LINE__) ;
|
||||
|
||||
#else // MEM_TRACK_MEM
|
||||
|
||||
#define MEM_TRACK_RELEASE
|
||||
#define MEM_TRACK
|
||||
|
||||
#endif // MEM_TRACK_MEM
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
// Note: relies on Type having ref() and unref() methods
|
||||
template <class Type> class LLPointer
|
||||
|
||||
//
|
||||
//class LLPrivateMemoryPool defines a private memory pool for an application to use, so the application does not
|
||||
//need to access the heap directly fro each memory allocation. Throught this, the allocation speed is faster,
|
||||
//and reduces virtaul address space gragmentation problem.
|
||||
//Note: this class is thread-safe by passing true to the constructor function. However, you do not need to do this unless
|
||||
//you are sure the memory allocation and de-allocation will happen in different threads. To make the pool thread safe
|
||||
//increases allocation and deallocation cost.
|
||||
//
|
||||
class LL_COMMON_API LLPrivateMemoryPool
|
||||
{
|
||||
friend class LLPrivateMemoryPoolManager ;
|
||||
|
||||
public:
|
||||
|
||||
LLPointer() :
|
||||
mPointer(NULL)
|
||||
class LL_COMMON_API LLMemoryBlock //each block is devided into slots uniformly
|
||||
{
|
||||
}
|
||||
public:
|
||||
LLMemoryBlock() ;
|
||||
~LLMemoryBlock() ;
|
||||
|
||||
LLPointer(Type* ptr) :
|
||||
mPointer(ptr)
|
||||
{
|
||||
ref();
|
||||
}
|
||||
void init(char* buffer, U32 buffer_size, U32 slot_size) ;
|
||||
void setBuffer(char* buffer, U32 buffer_size) ;
|
||||
|
||||
LLPointer(const LLPointer<Type>& ptr) :
|
||||
mPointer(ptr.mPointer)
|
||||
{
|
||||
ref();
|
||||
}
|
||||
char* allocate() ;
|
||||
void freeMem(void* addr) ;
|
||||
|
||||
// support conversion up the type hierarchy. See Item 45 in Effective C++, 3rd Ed.
|
||||
template<typename Subclass>
|
||||
LLPointer(const LLPointer<Subclass>& ptr) :
|
||||
mPointer(ptr.get())
|
||||
{
|
||||
ref();
|
||||
}
|
||||
bool empty() {return !mAllocatedSlots;}
|
||||
bool isFull() {return mAllocatedSlots == mTotalSlots;}
|
||||
bool isFree() {return !mTotalSlots;}
|
||||
|
||||
~LLPointer()
|
||||
{
|
||||
unref();
|
||||
}
|
||||
U32 getSlotSize()const {return mSlotSize;}
|
||||
U32 getTotalSlots()const {return mTotalSlots;}
|
||||
U32 getBufferSize()const {return mBufferSize;}
|
||||
char* getBuffer() const {return mBuffer;}
|
||||
|
||||
Type* get() const { return mPointer; }
|
||||
const Type* operator->() const { return mPointer; }
|
||||
Type* operator->() { return mPointer; }
|
||||
const Type& operator*() const { return *mPointer; }
|
||||
Type& operator*() { return *mPointer; }
|
||||
//debug use
|
||||
void resetBitMap() ;
|
||||
private:
|
||||
char* mBuffer;
|
||||
U32 mSlotSize ; //when the block is not initialized, it is the buffer size.
|
||||
U32 mBufferSize ;
|
||||
U32 mUsageBits ;
|
||||
U8 mTotalSlots ;
|
||||
U8 mAllocatedSlots ;
|
||||
U8 mDummySize ; //size of extra bytes reserved for mUsageBits.
|
||||
|
||||
operator BOOL() const { return (mPointer != NULL); }
|
||||
operator bool() const { return (mPointer != NULL); }
|
||||
bool operator!() const { return (mPointer == NULL); }
|
||||
bool isNull() const { return (mPointer == NULL); }
|
||||
bool notNull() const { return (mPointer != NULL); }
|
||||
public:
|
||||
LLMemoryBlock* mPrev ;
|
||||
LLMemoryBlock* mNext ;
|
||||
LLMemoryBlock* mSelf ;
|
||||
|
||||
operator Type*() const { return mPointer; }
|
||||
operator const Type*() const { return mPointer; }
|
||||
bool operator !=(Type* ptr) const { return (mPointer != ptr); }
|
||||
bool operator ==(Type* ptr) const { return (mPointer == ptr); }
|
||||
bool operator ==(const LLPointer<Type>& ptr) const { return (mPointer == ptr.mPointer); }
|
||||
bool operator < (const LLPointer<Type>& ptr) const { return (mPointer < ptr.mPointer); }
|
||||
bool operator > (const LLPointer<Type>& ptr) const { return (mPointer > ptr.mPointer); }
|
||||
|
||||
LLPointer<Type>& operator =(Type* ptr)
|
||||
{
|
||||
if( mPointer != ptr )
|
||||
struct CompareAddress
|
||||
{
|
||||
unref();
|
||||
mPointer = ptr;
|
||||
ref();
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
LLPointer<Type>& operator =(const LLPointer<Type>& ptr)
|
||||
{
|
||||
if( mPointer != ptr.mPointer )
|
||||
{
|
||||
unref();
|
||||
mPointer = ptr.mPointer;
|
||||
ref();
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
// support assignment up the type hierarchy. See Item 45 in Effective C++, 3rd Ed.
|
||||
template<typename Subclass>
|
||||
LLPointer<Type>& operator =(const LLPointer<Subclass>& ptr)
|
||||
{
|
||||
if( mPointer != ptr.get() )
|
||||
{
|
||||
unref();
|
||||
mPointer = ptr.get();
|
||||
ref();
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Just exchange the pointers, which will not change the reference counts.
|
||||
static void swap(LLPointer<Type>& a, LLPointer<Type>& b)
|
||||
{
|
||||
Type* temp = a.mPointer;
|
||||
a.mPointer = b.mPointer;
|
||||
b.mPointer = temp;
|
||||
}
|
||||
|
||||
protected:
|
||||
void ref()
|
||||
{
|
||||
if (mPointer)
|
||||
{
|
||||
mPointer->ref();
|
||||
}
|
||||
}
|
||||
|
||||
void unref()
|
||||
{
|
||||
if (mPointer)
|
||||
{
|
||||
Type *tempp = mPointer;
|
||||
mPointer = NULL;
|
||||
tempp->unref();
|
||||
if (mPointer != NULL)
|
||||
bool operator()(const LLMemoryBlock* const& lhs, const LLMemoryBlock* const& rhs)
|
||||
{
|
||||
llwarns << "Unreference did assignment to non-NULL because of destructor" << llendl;
|
||||
unref();
|
||||
return (U32)lhs->getBuffer() < (U32)rhs->getBuffer();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
protected:
|
||||
Type* mPointer;
|
||||
class LL_COMMON_API LLMemoryChunk //is divided into memory blocks.
|
||||
{
|
||||
public:
|
||||
LLMemoryChunk() ;
|
||||
~LLMemoryChunk() ;
|
||||
|
||||
void init(char* buffer, U32 buffer_size, U32 min_slot_size, U32 max_slot_size, U32 min_block_size, U32 max_block_size) ;
|
||||
void setBuffer(char* buffer, U32 buffer_size) ;
|
||||
|
||||
bool empty() ;
|
||||
|
||||
char* allocate(U32 size) ;
|
||||
void freeMem(void* addr) ;
|
||||
|
||||
char* getBuffer() const {return mBuffer;}
|
||||
U32 getBufferSize() const {return mBufferSize;}
|
||||
U32 getAllocatedSize() const {return mAlloatedSize;}
|
||||
|
||||
bool containsAddress(const char* addr) const;
|
||||
|
||||
static U32 getMaxOverhead(U32 data_buffer_size, U32 min_slot_size,
|
||||
U32 max_slot_size, U32 min_block_size, U32 max_block_size) ;
|
||||
|
||||
void dump() ;
|
||||
|
||||
private:
|
||||
U32 getPageIndex(U32 addr) ;
|
||||
U32 getBlockLevel(U32 size) ;
|
||||
U16 getPageLevel(U32 size) ;
|
||||
LLMemoryBlock* addBlock(U32 blk_idx) ;
|
||||
void popAvailBlockList(U32 blk_idx) ;
|
||||
void addToFreeSpace(LLMemoryBlock* blk) ;
|
||||
void removeFromFreeSpace(LLMemoryBlock* blk) ;
|
||||
void removeBlock(LLMemoryBlock* blk) ;
|
||||
void addToAvailBlockList(LLMemoryBlock* blk) ;
|
||||
U32 calcBlockSize(U32 slot_size);
|
||||
LLMemoryBlock* createNewBlock(LLMemoryBlock* blk, U32 buffer_size, U32 slot_size, U32 blk_idx) ;
|
||||
|
||||
private:
|
||||
LLMemoryBlock** mAvailBlockList ;//256 by mMinSlotSize
|
||||
LLMemoryBlock** mFreeSpaceList;
|
||||
LLMemoryBlock* mBlocks ; //index of blocks by address.
|
||||
|
||||
char* mBuffer ;
|
||||
U32 mBufferSize ;
|
||||
char* mDataBuffer ;
|
||||
char* mMetaBuffer ;
|
||||
U32 mMinBlockSize ;
|
||||
U32 mMinSlotSize ;
|
||||
U32 mMaxSlotSize ;
|
||||
U32 mAlloatedSize ;
|
||||
U16 mBlockLevels;
|
||||
U16 mPartitionLevels;
|
||||
|
||||
public:
|
||||
//form a linked list
|
||||
LLMemoryChunk* mNext ;
|
||||
LLMemoryChunk* mPrev ;
|
||||
} ;
|
||||
|
||||
private:
|
||||
LLPrivateMemoryPool(S32 type, U32 max_pool_size) ;
|
||||
~LLPrivateMemoryPool() ;
|
||||
|
||||
char *allocate(U32 size) ;
|
||||
void freeMem(void* addr) ;
|
||||
|
||||
void dump() ;
|
||||
U32 getTotalAllocatedSize() ;
|
||||
U32 getTotalReservedSize() {return mReservedPoolSize;}
|
||||
S32 getType() const {return mType; }
|
||||
bool isEmpty() const {return !mNumOfChunks; }
|
||||
|
||||
private:
|
||||
void lock() ;
|
||||
void unlock() ;
|
||||
S32 getChunkIndex(U32 size) ;
|
||||
LLMemoryChunk* addChunk(S32 chunk_index) ;
|
||||
bool checkSize(U32 asked_size) ;
|
||||
void removeChunk(LLMemoryChunk* chunk) ;
|
||||
U16 findHashKey(const char* addr);
|
||||
void addToHashTable(LLMemoryChunk* chunk) ;
|
||||
void removeFromHashTable(LLMemoryChunk* chunk) ;
|
||||
void rehash() ;
|
||||
bool fillHashTable(U16 start, U16 end, LLMemoryChunk* chunk) ;
|
||||
LLMemoryChunk* findChunk(const char* addr) ;
|
||||
|
||||
void destroyPool() ;
|
||||
|
||||
public:
|
||||
enum
|
||||
{
|
||||
SMALL_ALLOCATION = 0, //from 8 bytes to 2KB(exclusive), page size 2KB, max chunk size is 4MB.
|
||||
MEDIUM_ALLOCATION, //from 2KB to 512KB(exclusive), page size 32KB, max chunk size 4MB
|
||||
LARGE_ALLOCATION, //from 512KB to 4MB(inclusive), page size 64KB, max chunk size 16MB
|
||||
SUPER_ALLOCATION //allocation larger than 4MB.
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
STATIC = 0 , //static pool(each alllocation stays for a long time) without threading support
|
||||
VOLATILE, //Volatile pool(each allocation stays for a very short time) without threading support
|
||||
STATIC_THREADED, //static pool with threading support
|
||||
VOLATILE_THREADED, //volatile pool with threading support
|
||||
MAX_TYPES
|
||||
}; //pool types
|
||||
|
||||
private:
|
||||
LLMutex* mMutexp ;
|
||||
U32 mMaxPoolSize;
|
||||
U32 mReservedPoolSize ;
|
||||
|
||||
LLMemoryChunk* mChunkList[SUPER_ALLOCATION] ; //all memory chunks reserved by this pool, sorted by address
|
||||
U16 mNumOfChunks ;
|
||||
U16 mHashFactor ;
|
||||
|
||||
S32 mType ;
|
||||
|
||||
class LLChunkHashElement
|
||||
{
|
||||
public:
|
||||
LLChunkHashElement() {mFirst = NULL ; mSecond = NULL ;}
|
||||
|
||||
bool add(LLMemoryChunk* chunk) ;
|
||||
void remove(LLMemoryChunk* chunk) ;
|
||||
LLMemoryChunk* findChunk(const char* addr) ;
|
||||
|
||||
bool empty() {return !mFirst && !mSecond; }
|
||||
bool full() {return mFirst && mSecond; }
|
||||
bool hasElement(LLMemoryChunk* chunk) {return mFirst == chunk || mSecond == chunk;}
|
||||
|
||||
private:
|
||||
LLMemoryChunk* mFirst ;
|
||||
LLMemoryChunk* mSecond ;
|
||||
};
|
||||
std::vector<LLChunkHashElement> mChunkHashList ;
|
||||
};
|
||||
|
||||
//template <class Type>
|
||||
//class LLPointerTraits
|
||||
//{
|
||||
// static Type* null();
|
||||
//};
|
||||
//
|
||||
// Expands LLPointer to return a pointer to a special instance of class Type instead of NULL.
|
||||
// This is useful in instances where operations on NULL pointers are semantically safe and/or
|
||||
// when error checking occurs at a different granularity or in a different part of the code
|
||||
// than when referencing an object via a LLSafeHandle.
|
||||
//
|
||||
|
||||
template <class Type>
|
||||
class LLSafeHandle
|
||||
class LL_COMMON_API LLPrivateMemoryPoolManager
|
||||
{
|
||||
private:
|
||||
LLPrivateMemoryPoolManager(BOOL enabled, U32 max_pool_size) ;
|
||||
~LLPrivateMemoryPoolManager() ;
|
||||
|
||||
public:
|
||||
static LLPrivateMemoryPoolManager* getInstance() ;
|
||||
static void initClass(BOOL enabled, U32 pool_size) ;
|
||||
static void destroyClass() ;
|
||||
|
||||
LLPrivateMemoryPool* newPool(S32 type) ;
|
||||
void deletePool(LLPrivateMemoryPool* pool) ;
|
||||
|
||||
private:
|
||||
std::vector<LLPrivateMemoryPool*> mPoolList ;
|
||||
U32 mMaxPrivatePoolSize;
|
||||
|
||||
static LLPrivateMemoryPoolManager* sInstance ;
|
||||
static BOOL sPrivatePoolEnabled;
|
||||
static std::vector<LLPrivateMemoryPool*> sDanglingPoolList ;
|
||||
public:
|
||||
LLSafeHandle() :
|
||||
mPointer(NULL)
|
||||
{
|
||||
}
|
||||
//debug and statistics info.
|
||||
void updateStatistics() ;
|
||||
|
||||
LLSafeHandle(Type* ptr) :
|
||||
mPointer(NULL)
|
||||
{
|
||||
assign(ptr);
|
||||
}
|
||||
|
||||
LLSafeHandle(const LLSafeHandle<Type>& ptr) :
|
||||
mPointer(NULL)
|
||||
{
|
||||
assign(ptr.mPointer);
|
||||
}
|
||||
|
||||
// support conversion up the type hierarchy. See Item 45 in Effective C++, 3rd Ed.
|
||||
template<typename Subclass>
|
||||
LLSafeHandle(const LLSafeHandle<Subclass>& ptr) :
|
||||
mPointer(NULL)
|
||||
{
|
||||
assign(ptr.get());
|
||||
}
|
||||
|
||||
~LLSafeHandle()
|
||||
{
|
||||
unref();
|
||||
}
|
||||
|
||||
const Type* operator->() const { return nonNull(mPointer); }
|
||||
Type* operator->() { return nonNull(mPointer); }
|
||||
|
||||
Type* get() const { return mPointer; }
|
||||
// we disallow these operations as they expose our null objects to direct manipulation
|
||||
// and bypass the reference counting semantics
|
||||
//const Type& operator*() const { return *nonNull(mPointer); }
|
||||
//Type& operator*() { return *nonNull(mPointer); }
|
||||
|
||||
operator BOOL() const { return mPointer != NULL; }
|
||||
operator bool() const { return mPointer != NULL; }
|
||||
bool operator!() const { return mPointer == NULL; }
|
||||
bool isNull() const { return mPointer == NULL; }
|
||||
bool notNull() const { return mPointer != NULL; }
|
||||
|
||||
|
||||
operator Type*() const { return mPointer; }
|
||||
operator const Type*() const { return mPointer; }
|
||||
bool operator !=(Type* ptr) const { return (mPointer != ptr); }
|
||||
bool operator ==(Type* ptr) const { return (mPointer == ptr); }
|
||||
bool operator ==(const LLSafeHandle<Type>& ptr) const { return (mPointer == ptr.mPointer); }
|
||||
bool operator < (const LLSafeHandle<Type>& ptr) const { return (mPointer < ptr.mPointer); }
|
||||
bool operator > (const LLSafeHandle<Type>& ptr) const { return (mPointer > ptr.mPointer); }
|
||||
|
||||
LLSafeHandle<Type>& operator =(Type* ptr)
|
||||
{
|
||||
assign(ptr);
|
||||
return *this;
|
||||
}
|
||||
|
||||
LLSafeHandle<Type>& operator =(const LLSafeHandle<Type>& ptr)
|
||||
{
|
||||
assign(ptr.mPointer);
|
||||
return *this;
|
||||
}
|
||||
|
||||
// support assignment up the type hierarchy. See Item 45 in Effective C++, 3rd Ed.
|
||||
template<typename Subclass>
|
||||
LLSafeHandle<Type>& operator =(const LLSafeHandle<Subclass>& ptr)
|
||||
{
|
||||
assign(ptr.get());
|
||||
return *this;
|
||||
}
|
||||
U32 mTotalReservedSize ;
|
||||
U32 mTotalAllocatedSize ;
|
||||
|
||||
public:
|
||||
typedef Type* (*NullFunc)();
|
||||
static const NullFunc sNullFunc;
|
||||
|
||||
protected:
|
||||
void ref()
|
||||
{
|
||||
if (mPointer)
|
||||
{
|
||||
mPointer->ref();
|
||||
}
|
||||
}
|
||||
|
||||
void unref()
|
||||
{
|
||||
if (mPointer)
|
||||
{
|
||||
Type *tempp = mPointer;
|
||||
mPointer = NULL;
|
||||
tempp->unref();
|
||||
if (mPointer != NULL)
|
||||
{
|
||||
llwarns << "Unreference did assignment to non-NULL because of destructor" << llendl;
|
||||
unref();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void assign(Type* ptr)
|
||||
{
|
||||
if( mPointer != ptr )
|
||||
{
|
||||
unref();
|
||||
mPointer = ptr;
|
||||
ref();
|
||||
}
|
||||
}
|
||||
|
||||
static Type* nonNull(Type* ptr)
|
||||
{
|
||||
return ptr == NULL ? sNullFunc() : ptr;
|
||||
}
|
||||
|
||||
protected:
|
||||
Type* mPointer;
|
||||
};
|
||||
|
||||
// LLInitializedPointer is just a pointer with a default constructor that initializes it to NULL
|
||||
// NOT a smart pointer like LLPointer<>
|
||||
// Useful for example in std::map<int,LLInitializedPointer<LLFoo> >
|
||||
// (std::map uses the default constructor for creating new entries)
|
||||
template <typename T> class LLInitializedPointer
|
||||
{
|
||||
public:
|
||||
LLInitializedPointer() : mPointer(NULL) {}
|
||||
~LLInitializedPointer() { delete mPointer; }
|
||||
#if __DEBUG_PRIVATE_MEM__
|
||||
static char* allocate(LLPrivateMemoryPool* poolp, U32 size, const char* function, const int line) ;
|
||||
|
||||
const T* operator->() const { return mPointer; }
|
||||
T* operator->() { return mPointer; }
|
||||
const T& operator*() const { return *mPointer; }
|
||||
T& operator*() { return *mPointer; }
|
||||
operator const T*() const { return mPointer; }
|
||||
operator T*() { return mPointer; }
|
||||
T* operator=(T* x) { return (mPointer = x); }
|
||||
operator bool() const { return mPointer != NULL; }
|
||||
bool operator!() const { return mPointer == NULL; }
|
||||
bool operator==(T* rhs) { return mPointer == rhs; }
|
||||
bool operator==(const LLInitializedPointer<T>* rhs) { return mPointer == rhs.mPointer; }
|
||||
|
||||
protected:
|
||||
T* mPointer;
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
// LLSingleton implements the getInstance() method part of the Singleton
|
||||
// pattern. It can't make the derived class constructors protected, though, so
|
||||
// you have to do that yourself.
|
||||
//
|
||||
// There are two ways to use LLSingleton. The first way is to inherit from it
|
||||
// while using the typename that you'd like to be static as the template
|
||||
// parameter, like so:
|
||||
//
|
||||
// class Foo: public LLSingleton<Foo>{};
|
||||
//
|
||||
// Foo& instance = Foo::instance();
|
||||
//
|
||||
// The second way is to use the singleton class directly, without inheritance:
|
||||
//
|
||||
// typedef LLSingleton<Foo> FooSingleton;
|
||||
//
|
||||
// Foo& instance = FooSingleton::instance();
|
||||
//
|
||||
// In this case, the class being managed as a singleton needs to provide an
|
||||
// initSingleton() method since the LLSingleton virtual method won't be
|
||||
// available
|
||||
//
|
||||
// As currently written, it is not thread-safe.
|
||||
template <typename T>
|
||||
class LLSingleton
|
||||
{
|
||||
static bool &needsInit()
|
||||
{
|
||||
static bool needs_init = true;
|
||||
return needs_init;
|
||||
}
|
||||
public:
|
||||
static bool instanceExists()
|
||||
{
|
||||
return !needsInit();
|
||||
}
|
||||
virtual ~LLSingleton() {}
|
||||
#ifdef LL_MSVC7
|
||||
// workaround for VC7 compiler bug
|
||||
// adapted from http://www.codeproject.com/KB/tips/VC2003MeyersSingletonBug.aspx
|
||||
// our version doesn't introduce a nested struct so that you can still declare LLSingleton<MyClass>
|
||||
// a friend and hide your constructor
|
||||
static T* getInstance()
|
||||
{
|
||||
LLSingleton<T> singleton;
|
||||
return singleton.vsHack();
|
||||
}
|
||||
|
||||
T* vsHack()
|
||||
typedef std::map<char*, std::string> mem_allocation_info_t ;
|
||||
static mem_allocation_info_t sMemAllocationTracker;
|
||||
#else
|
||||
static T* getInstance()
|
||||
static char* allocate(LLPrivateMemoryPool* poolp, U32 size) ;
|
||||
#endif
|
||||
{
|
||||
static T instance;
|
||||
bool &needs_init = needsInit();
|
||||
if (needs_init)
|
||||
{
|
||||
needs_init = false;
|
||||
instance.initSingleton();
|
||||
}
|
||||
return &instance;
|
||||
}
|
||||
|
||||
static T& instance()
|
||||
{
|
||||
return *getInstance();
|
||||
}
|
||||
|
||||
private:
|
||||
virtual void initSingleton() {}
|
||||
static void freeMem(LLPrivateMemoryPool* poolp, void* addr) ;
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
// Return the resident set size of the current process, in bytes.
|
||||
// Return value is zero if not known.
|
||||
LL_COMMON_API U64 getCurrentRSS();
|
||||
|
||||
//-------------------------------------------------------------------------------------
|
||||
#if __DEBUG_PRIVATE_MEM__
|
||||
#define ALLOCATE_MEM(poolp, size) LLPrivateMemoryPoolManager::allocate((poolp), (size), __FUNCTION__, __LINE__)
|
||||
#else
|
||||
#define ALLOCATE_MEM(poolp, size) LLPrivateMemoryPoolManager::allocate((poolp), (size))
|
||||
//#define ALLOCATE_MEM(poolp, size) new char[size]
|
||||
#endif
|
||||
#define FREE_MEM(poolp, addr) LLPrivateMemoryPoolManager::freeMem((poolp), (addr))
|
||||
//#define FREE_MEM(poolp, addr) delete[] addr;
|
||||
//-------------------------------------------------------------------------------------
|
||||
|
||||
//
|
||||
//the below singleton is used to test the private memory pool.
|
||||
//
|
||||
#if 0
|
||||
class LL_COMMON_API LLPrivateMemoryPoolTester
|
||||
{
|
||||
private:
|
||||
LLPrivateMemoryPoolTester() ;
|
||||
~LLPrivateMemoryPoolTester() ;
|
||||
|
||||
public:
|
||||
static LLPrivateMemoryPoolTester* getInstance() ;
|
||||
static void destroy() ;
|
||||
|
||||
void run(S32 type) ;
|
||||
|
||||
private:
|
||||
void correctnessTest() ;
|
||||
void performanceTest() ;
|
||||
void fragmentationtest() ;
|
||||
|
||||
void test(U32 min_size, U32 max_size, U32 stride, U32 times, bool random_deletion, bool output_statistics) ;
|
||||
void testAndTime(U32 size, U32 times) ;
|
||||
|
||||
#if 0
|
||||
public:
|
||||
void* operator new(size_t size)
|
||||
{
|
||||
return (void*)sPool->allocate(size) ;
|
||||
}
|
||||
void operator delete(void* addr)
|
||||
{
|
||||
sPool->freeMem(addr) ;
|
||||
}
|
||||
void* operator new[](size_t size)
|
||||
{
|
||||
return (void*)sPool->allocate(size) ;
|
||||
}
|
||||
void operator delete[](void* addr)
|
||||
{
|
||||
sPool->freeMem(addr) ;
|
||||
}
|
||||
#endif
|
||||
|
||||
private:
|
||||
static LLPrivateMemoryPoolTester* sInstance;
|
||||
static LLPrivateMemoryPool* sPool ;
|
||||
static LLPrivateMemoryPool* sThreadedPool ;
|
||||
};
|
||||
#if 0
|
||||
//static
|
||||
void* LLPrivateMemoryPoolTester::operator new(size_t size)
|
||||
{
|
||||
return (void*)sPool->allocate(size) ;
|
||||
}
|
||||
|
||||
//static
|
||||
void LLPrivateMemoryPoolTester::operator delete(void* addr)
|
||||
{
|
||||
sPool->free(addr) ;
|
||||
}
|
||||
|
||||
//static
|
||||
void* LLPrivateMemoryPoolTester::operator new[](size_t size)
|
||||
{
|
||||
return (void*)sPool->allocate(size) ;
|
||||
}
|
||||
|
||||
//static
|
||||
void LLPrivateMemoryPoolTester::operator delete[](void* addr)
|
||||
{
|
||||
sPool->free(addr) ;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
//EVENTUALLY REMOVE THESE:
|
||||
#include "llpointer.h"
|
||||
#include "llrefcount.h"
|
||||
#include "llsingleton.h"
|
||||
#include "llsafehandle.h"
|
||||
|
||||
#endif
|
||||
@@ -74,9 +74,3 @@ void LLMortician::setZealous(BOOL b)
|
||||
{
|
||||
sDestroyImmediate = b;
|
||||
}
|
||||
|
||||
// static
|
||||
BOOL LLMortician::getZealous()
|
||||
{
|
||||
return sDestroyImmediate;
|
||||
}
|
||||
|
||||
@@ -46,7 +46,6 @@ public:
|
||||
|
||||
// sets destroy immediate true
|
||||
static void setZealous(BOOL b);
|
||||
static BOOL getZealous();
|
||||
|
||||
private:
|
||||
static BOOL sDestroyImmediate;
|
||||
|
||||
170
indra/llcommon/llpointer.h
Normal file
170
indra/llcommon/llpointer.h
Normal file
@@ -0,0 +1,170 @@
|
||||
/**
|
||||
* @file llpointer.h
|
||||
* @brief A reference-counted pointer for objects derived from LLRefCount
|
||||
*
|
||||
* $LicenseInfo:firstyear=2002&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2010, Linden Research, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
#ifndef LLPOINTER_H
|
||||
#define LLPOINTER_H
|
||||
|
||||
#include "llerror.h" // *TODO: consider eliminating this
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// RefCount objects should generally only be accessed by way of LLPointer<>'s
|
||||
// NOTE: LLPointer<LLFoo> x = new LLFoo(); MAY NOT BE THREAD SAFE
|
||||
// if LLFoo::LLFoo() does anything like put itself in an update queue.
|
||||
// The queue may get accessed before it gets assigned to x.
|
||||
// The correct implementation is:
|
||||
// LLPointer<LLFoo> x = new LLFoo; // constructor does not do anything interesting
|
||||
// x->instantiate(); // does stuff like place x into an update queue
|
||||
|
||||
// see llthread.h for LLThreadSafeRefCount
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
// Note: relies on Type having ref() and unref() methods
|
||||
template <class Type> class LLPointer
|
||||
{
|
||||
public:
|
||||
|
||||
LLPointer() :
|
||||
mPointer(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
LLPointer(Type* ptr) :
|
||||
mPointer(ptr)
|
||||
{
|
||||
ref();
|
||||
}
|
||||
|
||||
LLPointer(const LLPointer<Type>& ptr) :
|
||||
mPointer(ptr.mPointer)
|
||||
{
|
||||
ref();
|
||||
}
|
||||
|
||||
// support conversion up the type hierarchy. See Item 45 in Effective C++, 3rd Ed.
|
||||
template<typename Subclass>
|
||||
LLPointer(const LLPointer<Subclass>& ptr) :
|
||||
mPointer(ptr.get())
|
||||
{
|
||||
ref();
|
||||
}
|
||||
|
||||
~LLPointer()
|
||||
{
|
||||
unref();
|
||||
}
|
||||
|
||||
Type* get() const { return mPointer; }
|
||||
const Type* operator->() const { return mPointer; }
|
||||
Type* operator->() { return mPointer; }
|
||||
const Type& operator*() const { return *mPointer; }
|
||||
Type& operator*() { return *mPointer; }
|
||||
|
||||
operator BOOL() const { return (mPointer != NULL); }
|
||||
operator bool() const { return (mPointer != NULL); }
|
||||
bool operator!() const { return (mPointer == NULL); }
|
||||
bool isNull() const { return (mPointer == NULL); }
|
||||
bool notNull() const { return (mPointer != NULL); }
|
||||
|
||||
operator Type*() const { return mPointer; }
|
||||
bool operator !=(Type* ptr) const { return (mPointer != ptr); }
|
||||
bool operator ==(Type* ptr) const { return (mPointer == ptr); }
|
||||
bool operator ==(const LLPointer<Type>& ptr) const { return (mPointer == ptr.mPointer); }
|
||||
bool operator < (const LLPointer<Type>& ptr) const { return (mPointer < ptr.mPointer); }
|
||||
bool operator > (const LLPointer<Type>& ptr) const { return (mPointer > ptr.mPointer); }
|
||||
|
||||
LLPointer<Type>& operator =(Type* ptr)
|
||||
{
|
||||
if( mPointer != ptr )
|
||||
{
|
||||
unref();
|
||||
mPointer = ptr;
|
||||
ref();
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
LLPointer<Type>& operator =(const LLPointer<Type>& ptr)
|
||||
{
|
||||
if( mPointer != ptr.mPointer )
|
||||
{
|
||||
unref();
|
||||
mPointer = ptr.mPointer;
|
||||
ref();
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
// support assignment up the type hierarchy. See Item 45 in Effective C++, 3rd Ed.
|
||||
template<typename Subclass>
|
||||
LLPointer<Type>& operator =(const LLPointer<Subclass>& ptr)
|
||||
{
|
||||
if( mPointer != ptr.get() )
|
||||
{
|
||||
unref();
|
||||
mPointer = ptr.get();
|
||||
ref();
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Just exchange the pointers, which will not change the reference counts.
|
||||
static void swap(LLPointer<Type>& a, LLPointer<Type>& b)
|
||||
{
|
||||
Type* temp = a.mPointer;
|
||||
a.mPointer = b.mPointer;
|
||||
b.mPointer = temp;
|
||||
}
|
||||
|
||||
protected:
|
||||
void ref()
|
||||
{
|
||||
if (mPointer)
|
||||
{
|
||||
mPointer->ref();
|
||||
}
|
||||
}
|
||||
|
||||
void unref()
|
||||
{
|
||||
if (mPointer)
|
||||
{
|
||||
Type *tempp = mPointer;
|
||||
mPointer = NULL;
|
||||
tempp->unref();
|
||||
if (mPointer != NULL)
|
||||
{
|
||||
llwarns << "Unreference did assignment to non-NULL because of destructor" << llendl;
|
||||
unref();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
Type* mPointer;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -107,7 +107,17 @@
|
||||
|
||||
#endif
|
||||
|
||||
// Deal with the differences on Windows
|
||||
|
||||
// Static linking with apr on windows needs to be declared.
|
||||
#if LL_WINDOWS && !LL_COMMON_LINK_SHARED
|
||||
#ifndef APR_DECLARE_STATIC
|
||||
#define APR_DECLARE_STATIC // For APR on Windows
|
||||
#endif
|
||||
#ifndef APU_DECLARE_STATIC
|
||||
#define APU_DECLARE_STATIC // For APR util on Windows
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(LL_WINDOWS)
|
||||
#define BOOST_REGEX_NO_LIB 1
|
||||
#define CURL_STATICLIB 1
|
||||
@@ -159,12 +169,19 @@
|
||||
#define LL_DLLIMPORT
|
||||
#endif // LL_WINDOWS
|
||||
|
||||
#ifdef llcommon_EXPORTS
|
||||
// Compiling llcommon (shared)
|
||||
#define LL_COMMON_API LL_DLLEXPORT
|
||||
#else // llcommon_EXPORTS
|
||||
// Using llcommon (shared)
|
||||
#define LL_COMMON_API LL_DLLIMPORT
|
||||
#endif // llcommon_EXPORTS
|
||||
#if LL_COMMON_LINK_SHARED
|
||||
// CMake automagically defines llcommon_EXPORTS only when building llcommon
|
||||
// sources, and only when llcommon is a shared library (i.e. when
|
||||
// LL_COMMON_LINK_SHARED). We must still test LL_COMMON_LINK_SHARED because
|
||||
// otherwise we can't distinguish between (non-llcommon source) and (llcommon
|
||||
// not shared).
|
||||
# if defined(llcommon_EXPORTS)
|
||||
# define LL_COMMON_API LL_DLLEXPORT
|
||||
# else //llcommon_EXPORTS
|
||||
# define LL_COMMON_API LL_DLLIMPORT
|
||||
# endif //llcommon_EXPORTS
|
||||
#else // LL_COMMON_LINK_SHARED
|
||||
# define LL_COMMON_API
|
||||
#endif // LL_COMMON_LINK_SHARED
|
||||
|
||||
#endif // not LL_LINDEN_PREPROCESSOR_H
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
#include <apr_file_io.h>
|
||||
#include <apr_thread_proc.h>
|
||||
#include "llprocesslauncher.h"
|
||||
#include "aiaprpool.h"
|
||||
#include "llaprpool.h"
|
||||
|
||||
#include <iostream>
|
||||
#if LL_DARWIN || LL_LINUX
|
||||
@@ -102,7 +102,7 @@ int LLProcessLauncher::launch(void)
|
||||
STARTUPINFOA sinfo;
|
||||
memset(&sinfo, 0, sizeof(sinfo));
|
||||
|
||||
std::string args = "\"" + mExecutable + "\"";
|
||||
std::string args = mExecutable;
|
||||
for(int i = 0; i < (int)mLaunchArguments.size(); i++)
|
||||
{
|
||||
args += " ";
|
||||
@@ -114,10 +114,30 @@ int LLProcessLauncher::launch(void)
|
||||
char *args2 = new char[args.size() + 1];
|
||||
strcpy(args2, args.c_str());
|
||||
|
||||
if( ! CreateProcessA( NULL, args2, NULL, NULL, FALSE, 0, NULL, NULL, &sinfo, &pinfo ) )
|
||||
const char * working_directory = 0;
|
||||
if(!mWorkingDir.empty()) working_directory = mWorkingDir.c_str();
|
||||
if( ! CreateProcessA( NULL, args2, NULL, NULL, FALSE, 0, NULL, working_directory, &sinfo, &pinfo ) )
|
||||
{
|
||||
// TODO: do better than returning the OS-specific error code on failure...
|
||||
result = GetLastError();
|
||||
|
||||
LPTSTR error_str = 0;
|
||||
if(
|
||||
FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
|
||||
NULL,
|
||||
result,
|
||||
0,
|
||||
(LPTSTR)&error_str,
|
||||
0,
|
||||
NULL)
|
||||
!= 0)
|
||||
{
|
||||
char message[256];
|
||||
wcstombs(message, error_str, 256);
|
||||
message[255] = 0;
|
||||
llwarns << "CreateProcessA failed: " << message << llendl;
|
||||
LocalFree(error_str);
|
||||
}
|
||||
|
||||
if(result == 0)
|
||||
{
|
||||
// Make absolutely certain we return a non-zero value on failure.
|
||||
@@ -326,7 +346,7 @@ int LLProcessLauncher::launch(void)
|
||||
// Set up a pipe to the child process for error reporting.
|
||||
apr_file_t* in;
|
||||
apr_file_t* out;
|
||||
AIAPRPool pool;
|
||||
LLAPRPool pool;
|
||||
pool.create();
|
||||
#if(APR_VERSION_MAJOR==1 && APR_VERSION_MINOR>=3 || APR_VERSION_MAJOR>1)
|
||||
apr_status_t status = apr_file_pipe_create_ex(&in, &out, APR_FULL_BLOCK, pool());
|
||||
|
||||
@@ -31,20 +31,27 @@
|
||||
|
||||
#include "linden_common.h"
|
||||
#include "llqueuedthread.h"
|
||||
|
||||
#include "llstl.h"
|
||||
#include "lltimer.h"
|
||||
#include "lltimer.h" // ms_sleep()
|
||||
|
||||
//============================================================================
|
||||
|
||||
// MAIN THREAD
|
||||
LLQueuedThread::LLQueuedThread(const std::string& name, bool threaded) :
|
||||
LLQueuedThread::LLQueuedThread(const std::string& name, bool threaded, bool should_pause) :
|
||||
LLThread(name),
|
||||
mThreaded(threaded),
|
||||
mIdleThread(TRUE),
|
||||
mNextHandle(0)
|
||||
mNextHandle(0),
|
||||
mStarted(FALSE)
|
||||
{
|
||||
if (mThreaded)
|
||||
{
|
||||
if(should_pause)
|
||||
{
|
||||
pause() ; //call this before start the thread.
|
||||
}
|
||||
|
||||
start();
|
||||
}
|
||||
}
|
||||
@@ -52,6 +59,10 @@ LLQueuedThread::LLQueuedThread(const std::string& name, bool threaded) :
|
||||
// MAIN THREAD
|
||||
LLQueuedThread::~LLQueuedThread()
|
||||
{
|
||||
if (!mThreaded)
|
||||
{
|
||||
endThread();
|
||||
}
|
||||
shutdown();
|
||||
// ~LLThread() will be called here
|
||||
}
|
||||
@@ -90,6 +101,7 @@ void LLQueuedThread::shutdown()
|
||||
if (req->getStatus() == STATUS_QUEUED || req->getStatus() == STATUS_INPROGRESS)
|
||||
{
|
||||
++active_count;
|
||||
req->setStatus(STATUS_ABORTED); // avoid assert in deleteRequest
|
||||
}
|
||||
req->deleteRequest();
|
||||
}
|
||||
@@ -105,6 +117,14 @@ void LLQueuedThread::shutdown()
|
||||
// virtual
|
||||
S32 LLQueuedThread::update(U32 max_time_ms)
|
||||
{
|
||||
if (!mStarted)
|
||||
{
|
||||
if (!mThreaded)
|
||||
{
|
||||
startThread();
|
||||
mStarted = TRUE;
|
||||
}
|
||||
}
|
||||
return updateQueue(max_time_ms);
|
||||
}
|
||||
|
||||
@@ -118,8 +138,11 @@ S32 LLQueuedThread::updateQueue(U32 max_time_ms)
|
||||
if (mThreaded)
|
||||
{
|
||||
pending = getPending();
|
||||
if(pending > 0)
|
||||
{
|
||||
unpause();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
while (pending > 0)
|
||||
@@ -349,9 +372,9 @@ bool LLQueuedThread::completeRequest(handle_t handle)
|
||||
#if _DEBUG
|
||||
// llinfos << llformat("LLQueuedThread::Completed req [%08d]",handle) << llendl;
|
||||
#endif
|
||||
//re insert to the queue to schedule for a delete later
|
||||
req->setStatus(STATUS_DELETE);
|
||||
mRequestQueue.insert(req);
|
||||
mRequestHash.erase(handle);
|
||||
req->deleteRequest();
|
||||
// check();
|
||||
res = true;
|
||||
}
|
||||
unlockData();
|
||||
@@ -395,19 +418,11 @@ S32 LLQueuedThread::processNextRequest()
|
||||
}
|
||||
req = *mRequestQueue.begin();
|
||||
mRequestQueue.erase(mRequestQueue.begin());
|
||||
|
||||
if(req->getStatus() == STATUS_DELETE)
|
||||
{
|
||||
mRequestHash.erase(req);
|
||||
req->deleteRequest();
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((req->getFlags() & FLAG_ABORT) || (mStatus == QUITTING))
|
||||
{
|
||||
req->setStatus(STATUS_ABORTED);
|
||||
req->finishRequest(false);
|
||||
if ((req->getFlags() & FLAG_AUTO_COMPLETE))
|
||||
if (req->getFlags() & FLAG_AUTO_COMPLETE)
|
||||
{
|
||||
mRequestHash.erase(req);
|
||||
req->deleteRequest();
|
||||
@@ -418,9 +433,11 @@ S32 LLQueuedThread::processNextRequest()
|
||||
llassert_always(req->getStatus() == STATUS_QUEUED);
|
||||
break;
|
||||
}
|
||||
U32 start_priority = 0 ;
|
||||
if (req)
|
||||
{
|
||||
req->setStatus(STATUS_INPROGRESS);
|
||||
start_priority = req->getPriority();
|
||||
}
|
||||
unlockData();
|
||||
|
||||
@@ -436,13 +453,12 @@ S32 LLQueuedThread::processNextRequest()
|
||||
{
|
||||
lockData();
|
||||
req->setStatus(STATUS_COMPLETE);
|
||||
|
||||
req->finishRequest(true);
|
||||
|
||||
if ((req->getFlags() & FLAG_AUTO_COMPLETE))
|
||||
if (req->getFlags() & FLAG_AUTO_COMPLETE)
|
||||
{
|
||||
mRequestHash.erase(req);
|
||||
req->deleteRequest();
|
||||
// check();
|
||||
}
|
||||
unlockData();
|
||||
}
|
||||
@@ -451,9 +467,8 @@ S32 LLQueuedThread::processNextRequest()
|
||||
lockData();
|
||||
req->setStatus(STATUS_QUEUED);
|
||||
mRequestQueue.insert(req);
|
||||
U32 priority = req->getPriority();
|
||||
unlockData();
|
||||
if (priority < PRIORITY_NORMAL)
|
||||
if (mThreaded && start_priority < PRIORITY_NORMAL)
|
||||
{
|
||||
ms_sleep(1); // sleep the thread a little
|
||||
}
|
||||
@@ -481,6 +496,7 @@ void LLQueuedThread::run()
|
||||
// call checPause() immediately so we don't try to do anything before the class is fully constructed
|
||||
checkPause();
|
||||
startThread();
|
||||
mStarted = TRUE;
|
||||
|
||||
while (1)
|
||||
{
|
||||
|
||||
@@ -154,7 +154,7 @@ public:
|
||||
static handle_t nullHandle() { return handle_t(0); }
|
||||
|
||||
public:
|
||||
LLQueuedThread(const std::string& name, bool threaded = true);
|
||||
LLQueuedThread(const std::string& name, bool threaded = true, bool should_pause = false);
|
||||
virtual ~LLQueuedThread();
|
||||
virtual void shutdown();
|
||||
|
||||
@@ -184,7 +184,7 @@ public:
|
||||
void waitOnPending();
|
||||
void printQueueStats();
|
||||
|
||||
S32 getPending();
|
||||
virtual S32 getPending();
|
||||
bool getThreaded() { return mThreaded ? true : false; }
|
||||
|
||||
// Request accessors
|
||||
@@ -202,6 +202,7 @@ public:
|
||||
|
||||
protected:
|
||||
BOOL mThreaded; // if false, run on main thread and do updates during update()
|
||||
BOOL mStarted; // required when mThreaded is false to call startThread() from update()
|
||||
LLAtomic32<BOOL> mIdleThread; // request queue is empty (or we are quitting) and the thread is idle
|
||||
|
||||
typedef std::set<QueuedRequest*, queued_request_less> request_queue_t;
|
||||
|
||||
164
indra/llcommon/llrefcount.cpp
Normal file
164
indra/llcommon/llrefcount.cpp
Normal file
@@ -0,0 +1,164 @@
|
||||
/**
|
||||
* @file llrefcount.cpp
|
||||
* @brief Base class for reference counted objects for use with LLPointer
|
||||
*
|
||||
* $LicenseInfo:firstyear=2002&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2010, Linden Research, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
#include "linden_common.h"
|
||||
|
||||
#include "llrefcount.h"
|
||||
|
||||
#include "llerror.h"
|
||||
|
||||
#if LL_REF_COUNT_DEBUG
|
||||
#include "llthread.h"
|
||||
#include "llapr.h"
|
||||
#endif
|
||||
|
||||
LLRefCount::LLRefCount(const LLRefCount& other)
|
||||
: mRef(0)
|
||||
{
|
||||
#if LL_REF_COUNT_DEBUG
|
||||
if(gAPRPoolp)
|
||||
{
|
||||
mMutexp = new LLMutex(gAPRPoolp) ;
|
||||
}
|
||||
else
|
||||
{
|
||||
mMutexp = NULL ;
|
||||
}
|
||||
mCrashAtUnlock = FALSE ;
|
||||
#endif
|
||||
}
|
||||
|
||||
LLRefCount& LLRefCount::operator=(const LLRefCount&)
|
||||
{
|
||||
// do nothing, since ref count is specific to *this* reference
|
||||
return *this;
|
||||
}
|
||||
|
||||
LLRefCount::LLRefCount() :
|
||||
mRef(0)
|
||||
{
|
||||
#if LL_REF_COUNT_DEBUG
|
||||
if(gAPRPoolp)
|
||||
{
|
||||
mMutexp = new LLMutex(gAPRPoolp) ;
|
||||
}
|
||||
else
|
||||
{
|
||||
mMutexp = NULL ;
|
||||
}
|
||||
mCrashAtUnlock = FALSE ;
|
||||
#endif
|
||||
}
|
||||
|
||||
LLRefCount::~LLRefCount()
|
||||
{
|
||||
if (mRef != 0)
|
||||
{
|
||||
llerrs << "deleting non-zero reference" << llendl;
|
||||
}
|
||||
|
||||
#if LL_REF_COUNT_DEBUG
|
||||
if(gAPRPoolp)
|
||||
{
|
||||
delete mMutexp ;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#if LL_REF_COUNT_DEBUG
|
||||
void LLRefCount::ref() const
|
||||
{
|
||||
if(mMutexp)
|
||||
{
|
||||
if(mMutexp->isLocked())
|
||||
{
|
||||
mCrashAtUnlock = TRUE ;
|
||||
llerrs << "the mutex is locked by the thread: " << mLockedThreadID
|
||||
<< " Current thread: " << LLThread::currentID() << llendl ;
|
||||
}
|
||||
|
||||
mMutexp->lock() ;
|
||||
mLockedThreadID = LLThread::currentID() ;
|
||||
|
||||
mRef++;
|
||||
|
||||
if(mCrashAtUnlock)
|
||||
{
|
||||
while(1); //crash here.
|
||||
}
|
||||
mMutexp->unlock() ;
|
||||
}
|
||||
else
|
||||
{
|
||||
mRef++;
|
||||
}
|
||||
}
|
||||
|
||||
S32 LLRefCount::unref() const
|
||||
{
|
||||
if(mMutexp)
|
||||
{
|
||||
if(mMutexp->isLocked())
|
||||
{
|
||||
mCrashAtUnlock = TRUE ;
|
||||
llerrs << "the mutex is locked by the thread: " << mLockedThreadID
|
||||
<< " Current thread: " << LLThread::currentID() << llendl ;
|
||||
}
|
||||
|
||||
mMutexp->lock() ;
|
||||
mLockedThreadID = LLThread::currentID() ;
|
||||
|
||||
llassert(mRef >= 1);
|
||||
if (0 == --mRef)
|
||||
{
|
||||
if(mCrashAtUnlock)
|
||||
{
|
||||
while(1); //crash here.
|
||||
}
|
||||
mMutexp->unlock() ;
|
||||
|
||||
delete this;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(mCrashAtUnlock)
|
||||
{
|
||||
while(1); //crash here.
|
||||
}
|
||||
mMutexp->unlock() ;
|
||||
return mRef;
|
||||
}
|
||||
else
|
||||
{
|
||||
llassert(mRef >= 1);
|
||||
if (0 == --mRef)
|
||||
{
|
||||
delete this;
|
||||
return 0;
|
||||
}
|
||||
return mRef;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
89
indra/llcommon/llrefcount.h
Normal file
89
indra/llcommon/llrefcount.h
Normal file
@@ -0,0 +1,89 @@
|
||||
/**
|
||||
* @file llrefcount.h
|
||||
* @brief Base class for reference counted objects for use with LLPointer
|
||||
*
|
||||
* $LicenseInfo:firstyear=2002&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2010, Linden Research, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
#ifndef LLREFCOUNT_H
|
||||
#define LLREFCOUNT_H
|
||||
|
||||
#include <boost/noncopyable.hpp>
|
||||
|
||||
#define LL_REF_COUNT_DEBUG 0
|
||||
#if LL_REF_COUNT_DEBUG
|
||||
class LLMutex ;
|
||||
#endif
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// RefCount objects should generally only be accessed by way of LLPointer<>'s
|
||||
// see llthread.h for LLThreadSafeRefCount
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
class LL_COMMON_API LLRefCount
|
||||
{
|
||||
protected:
|
||||
LLRefCount(const LLRefCount& other);
|
||||
LLRefCount& operator=(const LLRefCount&);
|
||||
virtual ~LLRefCount(); // use unref()
|
||||
|
||||
public:
|
||||
LLRefCount();
|
||||
|
||||
#if LL_REF_COUNT_DEBUG
|
||||
void ref() const ;
|
||||
S32 unref() const ;
|
||||
#else
|
||||
inline void ref() const
|
||||
{
|
||||
mRef++;
|
||||
}
|
||||
|
||||
inline S32 unref() const
|
||||
{
|
||||
llassert(mRef >= 1);
|
||||
if (0 == --mRef)
|
||||
{
|
||||
delete this;
|
||||
return 0;
|
||||
}
|
||||
return mRef;
|
||||
}
|
||||
#endif
|
||||
|
||||
//NOTE: when passing around a const LLRefCount object, this can return different results
|
||||
// at different types, since mRef is mutable
|
||||
S32 getNumRefs() const
|
||||
{
|
||||
return mRef;
|
||||
}
|
||||
|
||||
private:
|
||||
mutable S32 mRef;
|
||||
|
||||
#if LL_REF_COUNT_DEBUG
|
||||
LLMutex* mMutexp ;
|
||||
mutable U32 mLockedThreadID ;
|
||||
mutable BOOL mCrashAtUnlock ;
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif
|
||||
162
indra/llcommon/llsafehandle.h
Normal file
162
indra/llcommon/llsafehandle.h
Normal file
@@ -0,0 +1,162 @@
|
||||
/**
|
||||
* @file llsafehandle.h
|
||||
* @brief Reference-counted object where Object() is valid, not NULL.
|
||||
*
|
||||
* $LicenseInfo:firstyear=2002&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2010, Linden Research, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
#ifndef LLSAFEHANDLE_H
|
||||
#define LLSAFEHANDLE_H
|
||||
|
||||
#include "llerror.h" // *TODO: consider eliminating this
|
||||
|
||||
// Expands LLPointer to return a pointer to a special instance of class Type instead of NULL.
|
||||
// This is useful in instances where operations on NULL pointers are semantically safe and/or
|
||||
// when error checking occurs at a different granularity or in a different part of the code
|
||||
// than when referencing an object via a LLSafeHandle.
|
||||
|
||||
template <class Type>
|
||||
class LLSafeHandle
|
||||
{
|
||||
public:
|
||||
LLSafeHandle() :
|
||||
mPointer(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
LLSafeHandle(Type* ptr) :
|
||||
mPointer(NULL)
|
||||
{
|
||||
assign(ptr);
|
||||
}
|
||||
|
||||
LLSafeHandle(const LLSafeHandle<Type>& ptr) :
|
||||
mPointer(NULL)
|
||||
{
|
||||
assign(ptr.mPointer);
|
||||
}
|
||||
|
||||
// support conversion up the type hierarchy. See Item 45 in Effective C++, 3rd Ed.
|
||||
template<typename Subclass>
|
||||
LLSafeHandle(const LLSafeHandle<Subclass>& ptr) :
|
||||
mPointer(NULL)
|
||||
{
|
||||
assign(ptr.get());
|
||||
}
|
||||
|
||||
~LLSafeHandle()
|
||||
{
|
||||
unref();
|
||||
}
|
||||
|
||||
const Type* operator->() const { return nonNull(mPointer); }
|
||||
Type* operator->() { return nonNull(mPointer); }
|
||||
|
||||
Type* get() const { return mPointer; }
|
||||
void clear() { assign(NULL); }
|
||||
// we disallow these operations as they expose our null objects to direct manipulation
|
||||
// and bypass the reference counting semantics
|
||||
//const Type& operator*() const { return *nonNull(mPointer); }
|
||||
//Type& operator*() { return *nonNull(mPointer); }
|
||||
|
||||
operator BOOL() const { return mPointer != NULL; }
|
||||
operator bool() const { return mPointer != NULL; }
|
||||
bool operator!() const { return mPointer == NULL; }
|
||||
bool isNull() const { return mPointer == NULL; }
|
||||
bool notNull() const { return mPointer != NULL; }
|
||||
|
||||
|
||||
operator Type*() const { return mPointer; }
|
||||
operator const Type*() const { return mPointer; }
|
||||
bool operator !=(Type* ptr) const { return (mPointer != ptr); }
|
||||
bool operator ==(Type* ptr) const { return (mPointer == ptr); }
|
||||
bool operator ==(const LLSafeHandle<Type>& ptr) const { return (mPointer == ptr.mPointer); }
|
||||
bool operator < (const LLSafeHandle<Type>& ptr) const { return (mPointer < ptr.mPointer); }
|
||||
bool operator > (const LLSafeHandle<Type>& ptr) const { return (mPointer > ptr.mPointer); }
|
||||
|
||||
LLSafeHandle<Type>& operator =(Type* ptr)
|
||||
{
|
||||
assign(ptr);
|
||||
return *this;
|
||||
}
|
||||
|
||||
LLSafeHandle<Type>& operator =(const LLSafeHandle<Type>& ptr)
|
||||
{
|
||||
assign(ptr.mPointer);
|
||||
return *this;
|
||||
}
|
||||
|
||||
// support assignment up the type hierarchy. See Item 45 in Effective C++, 3rd Ed.
|
||||
template<typename Subclass>
|
||||
LLSafeHandle<Type>& operator =(const LLSafeHandle<Subclass>& ptr)
|
||||
{
|
||||
assign(ptr.get());
|
||||
return *this;
|
||||
}
|
||||
|
||||
public:
|
||||
typedef Type* (*NullFunc)();
|
||||
static const NullFunc sNullFunc;
|
||||
|
||||
protected:
|
||||
void ref()
|
||||
{
|
||||
if (mPointer)
|
||||
{
|
||||
mPointer->ref();
|
||||
}
|
||||
}
|
||||
|
||||
void unref()
|
||||
{
|
||||
if (mPointer)
|
||||
{
|
||||
Type *tempp = mPointer;
|
||||
mPointer = NULL;
|
||||
tempp->unref();
|
||||
if (mPointer != NULL)
|
||||
{
|
||||
llwarns << "Unreference did assignment to non-NULL because of destructor" << llendl;
|
||||
unref();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void assign(Type* ptr)
|
||||
{
|
||||
if( mPointer != ptr )
|
||||
{
|
||||
unref();
|
||||
mPointer = ptr;
|
||||
ref();
|
||||
}
|
||||
}
|
||||
|
||||
static Type* nonNull(Type* ptr)
|
||||
{
|
||||
return ptr == NULL ? sNullFunc() : ptr;
|
||||
}
|
||||
|
||||
protected:
|
||||
Type* mPointer;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -35,21 +35,21 @@
|
||||
|
||||
#include "llthread.h"
|
||||
|
||||
//! Scoped volatile memory pool.
|
||||
//
|
||||
// As the AIVolatileAPRPool should never keep allocations very
|
||||
// long, it's most common use is for allocations with a lifetime
|
||||
// equal to it's scope.
|
||||
//
|
||||
// This is a convenience class that makes just a little easier to type.
|
||||
//
|
||||
class LLScopedVolatileAPRPool
|
||||
/** Scoped volatile memory pool.
|
||||
*
|
||||
* As the LLVolatileAPRPool should never keep allocations very
|
||||
* long, its most common use is for allocations with a lifetime
|
||||
* equal to it's scope.
|
||||
*
|
||||
* This is a convenience class that makes just a little easier to type.
|
||||
*/
|
||||
class LL_COMMON_API LLScopedVolatileAPRPool
|
||||
{
|
||||
private:
|
||||
AIVolatileAPRPool& mPool;
|
||||
LLVolatileAPRPool& mPool;
|
||||
apr_pool_t* mScopedAPRpool;
|
||||
public:
|
||||
LLScopedVolatileAPRPool() : mPool(AIThreadLocalData::tldata().mVolatileAPRPool), mScopedAPRpool(mPool.getVolatileAPRPool()) { }
|
||||
LLScopedVolatileAPRPool() : mPool(LLThreadLocalData::tldata().mVolatileAPRPool), mScopedAPRpool(mPool.getVolatileAPRPool()) { }
|
||||
~LLScopedVolatileAPRPool() { mPool.clearVolatileAPRPool(); }
|
||||
// Only use this to pass the pointer to a libapr-1 function that requires it.
|
||||
operator apr_pool_t*() const { return mScopedAPRpool; }
|
||||
|
||||
@@ -754,11 +754,7 @@ void LLSD::insert(const String& k, const LLSD& v) { makeMap(impl).insert(k, v);
|
||||
LLSD& LLSD::with(const String& k, const LLSD& v)
|
||||
{
|
||||
makeMap(impl).insert(k, v);
|
||||
#ifdef LL_MSVC7
|
||||
return *dynamic_cast<LLSD*>(this);
|
||||
#else
|
||||
return *this;
|
||||
#endif
|
||||
return *this;
|
||||
}
|
||||
void LLSD::erase(const String& k) { makeMap(impl).erase(k); }
|
||||
|
||||
@@ -784,11 +780,7 @@ void LLSD::insert(Integer i, const LLSD& v) { makeArray(impl).insert(i, v); }
|
||||
LLSD& LLSD::with(Integer i, const LLSD& v)
|
||||
{
|
||||
makeArray(impl).insert(i, v);
|
||||
#ifdef LL_MSVC7
|
||||
return *dynamic_cast<LLSD*>(this);
|
||||
#else
|
||||
return *this;
|
||||
#endif
|
||||
return *this;
|
||||
}
|
||||
void LLSD::append(const LLSD& v) { makeArray(impl).append(v); }
|
||||
void LLSD::erase(Integer i) { makeArray(impl).erase(i); }
|
||||
|
||||
@@ -34,11 +34,16 @@
|
||||
|
||||
#include "linden_common.h"
|
||||
#include "llsdserialize.h"
|
||||
#include "llmemory.h"
|
||||
#include "llpointer.h"
|
||||
#include "llstreamtools.h" // for fullread
|
||||
|
||||
#include <iostream>
|
||||
#include "apr_base64.h"
|
||||
#ifdef LL_STANDALONE
|
||||
# include <zlib.h>
|
||||
#else
|
||||
# include "zlib/zlib.h" // for davep's dirty little zip functions
|
||||
#endif
|
||||
|
||||
#if !LL_WINDOWS
|
||||
#include <netinet/in.h> // htonl & ntohl
|
||||
@@ -1447,12 +1452,12 @@ S32 LLSDBinaryFormatter::format(const LLSD& data, std::ostream& ostr, U32 option
|
||||
}
|
||||
|
||||
case LLSD::TypeUUID:
|
||||
{
|
||||
{
|
||||
ostr.put('u');
|
||||
LLUUID d = data.asUUID();
|
||||
ostr.write((const char*)(&(d.mData)), UUID_BYTES);
|
||||
LLUUID value = data.asUUID();
|
||||
ostr.write((const char*)(&value.mData), UUID_BYTES);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
case LLSD::TypeString:
|
||||
ostr.put('s');
|
||||
@@ -1505,7 +1510,7 @@ void LLSDBinaryFormatter::formatString(
|
||||
*/
|
||||
int deserialize_string(std::istream& istr, std::string& value, S32 max_bytes)
|
||||
{
|
||||
char c = istr.get();
|
||||
int c = istr.get();
|
||||
if(istr.fail())
|
||||
{
|
||||
// No data in stream, bail out but mention the character we
|
||||
@@ -1547,7 +1552,7 @@ int deserialize_string_delim(
|
||||
|
||||
while (true)
|
||||
{
|
||||
char next_char = istr.get();
|
||||
int next_byte = istr.get();
|
||||
++count;
|
||||
|
||||
if(istr.fail())
|
||||
@@ -1556,6 +1561,8 @@ int deserialize_string_delim(
|
||||
value = write_buffer.str();
|
||||
return LLSDParser::PARSE_FAILURE;
|
||||
}
|
||||
|
||||
char next_char = (char)next_byte; // Now that we know it's not EOF
|
||||
|
||||
if(found_escape)
|
||||
{
|
||||
@@ -1644,7 +1651,7 @@ int deserialize_string_raw(
|
||||
char buf[BUF_LEN]; /* Flawfinder: ignore */
|
||||
istr.get(buf, BUF_LEN - 1, ')');
|
||||
count += istr.gcount();
|
||||
char c = istr.get();
|
||||
int c = istr.get();
|
||||
c = istr.get();
|
||||
count += 2;
|
||||
if(((c == '"') || (c == '\'')) && (buf[0] == '('))
|
||||
@@ -1990,3 +1997,178 @@ std::ostream& operator<<(std::ostream& s, const LLSD& llsd)
|
||||
return s;
|
||||
}
|
||||
|
||||
//dirty little zippers -- yell at davep if these are horrid
|
||||
|
||||
//return a string containing gzipped bytes of binary serialized LLSD
|
||||
// VERY inefficient -- creates several copies of LLSD block in memory
|
||||
std::string zip_llsd(LLSD& data)
|
||||
{
|
||||
std::stringstream llsd_strm;
|
||||
|
||||
LLSDSerialize::toBinary(data, llsd_strm);
|
||||
|
||||
const U32 CHUNK = 65536;
|
||||
|
||||
z_stream strm;
|
||||
strm.zalloc = Z_NULL;
|
||||
strm.zfree = Z_NULL;
|
||||
strm.opaque = Z_NULL;
|
||||
|
||||
S32 ret = deflateInit(&strm, Z_BEST_COMPRESSION);
|
||||
if (ret != Z_OK)
|
||||
{
|
||||
llwarns << "Failed to compress LLSD block." << llendl;
|
||||
return std::string();
|
||||
}
|
||||
|
||||
std::string source = llsd_strm.str();
|
||||
|
||||
U8 out[CHUNK];
|
||||
|
||||
strm.avail_in = source.size();
|
||||
strm.next_in = (U8*) source.data();
|
||||
U8* output = NULL;
|
||||
|
||||
U32 cur_size = 0;
|
||||
|
||||
U32 have = 0;
|
||||
|
||||
do
|
||||
{
|
||||
strm.avail_out = CHUNK;
|
||||
strm.next_out = out;
|
||||
|
||||
ret = deflate(&strm, Z_FINISH);
|
||||
if (ret == Z_OK || ret == Z_STREAM_END)
|
||||
{ //copy result into output
|
||||
if (strm.avail_out >= CHUNK)
|
||||
{
|
||||
free(output);
|
||||
llwarns << "Failed to compress LLSD block." << llendl;
|
||||
return std::string();
|
||||
}
|
||||
|
||||
have = CHUNK-strm.avail_out;
|
||||
output = (U8*) realloc(output, cur_size+have);
|
||||
memcpy(output+cur_size, out, have);
|
||||
cur_size += have;
|
||||
}
|
||||
else
|
||||
{
|
||||
free(output);
|
||||
llwarns << "Failed to compress LLSD block." << llendl;
|
||||
return std::string();
|
||||
}
|
||||
}
|
||||
while (ret == Z_OK);
|
||||
|
||||
std::string::size_type size = cur_size;
|
||||
|
||||
std::string result((char*) output, size);
|
||||
deflateEnd(&strm);
|
||||
free(output);
|
||||
|
||||
#if 0 //verify results work with unzip_llsd
|
||||
std::istringstream test(result);
|
||||
LLSD test_sd;
|
||||
if (!unzip_llsd(test_sd, test, result.size()))
|
||||
{
|
||||
llerrs << "Invalid compression result!" << llendl;
|
||||
}
|
||||
#endif
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
//decompress a block of LLSD from provided istream
|
||||
// not very efficient -- creats a copy of decompressed LLSD block in memory
|
||||
// and deserializes from that copy using LLSDSerialize
|
||||
bool unzip_llsd(LLSD& data, std::istream& is, S32 size)
|
||||
{
|
||||
U8* result = NULL;
|
||||
U32 cur_size = 0;
|
||||
z_stream strm;
|
||||
|
||||
const U32 CHUNK = 65536;
|
||||
|
||||
U8 *in = new U8[size];
|
||||
is.read((char*) in, size);
|
||||
|
||||
U8 out[CHUNK];
|
||||
|
||||
strm.zalloc = Z_NULL;
|
||||
strm.zfree = Z_NULL;
|
||||
strm.opaque = Z_NULL;
|
||||
strm.avail_in = size;
|
||||
strm.next_in = in;
|
||||
|
||||
S32 ret = inflateInit(&strm);
|
||||
|
||||
do
|
||||
{
|
||||
strm.avail_out = CHUNK;
|
||||
strm.next_out = out;
|
||||
ret = inflate(&strm, Z_NO_FLUSH);
|
||||
if (ret == Z_STREAM_ERROR)
|
||||
{
|
||||
inflateEnd(&strm);
|
||||
free(result);
|
||||
delete [] in;
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (ret)
|
||||
{
|
||||
case Z_NEED_DICT:
|
||||
ret = Z_DATA_ERROR;
|
||||
case Z_DATA_ERROR:
|
||||
case Z_MEM_ERROR:
|
||||
inflateEnd(&strm);
|
||||
free(result);
|
||||
delete [] in;
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
|
||||
U32 have = CHUNK-strm.avail_out;
|
||||
|
||||
result = (U8*) realloc(result, cur_size + have);
|
||||
memcpy(result+cur_size, out, have);
|
||||
cur_size += have;
|
||||
|
||||
} while (ret == Z_OK);
|
||||
|
||||
inflateEnd(&strm);
|
||||
delete [] in;
|
||||
|
||||
if (ret != Z_STREAM_END)
|
||||
{
|
||||
free(result);
|
||||
return false;
|
||||
}
|
||||
|
||||
//result now points to the decompressed LLSD block
|
||||
{
|
||||
std::string res_str((char*) result, cur_size);
|
||||
|
||||
std::string deprecated_header("<? LLSD/Binary ?>");
|
||||
|
||||
if (res_str.substr(0, deprecated_header.size()) == deprecated_header)
|
||||
{
|
||||
res_str = res_str.substr(deprecated_header.size()+1, cur_size);
|
||||
}
|
||||
cur_size = res_str.size();
|
||||
|
||||
std::istringstream istr(res_str);
|
||||
|
||||
if (!LLSDSerialize::fromBinary(data, istr, cur_size))
|
||||
{
|
||||
llwarns << "Failed to unzip LLSD block" << llendl;
|
||||
free(result);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
free(result);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -36,8 +36,9 @@
|
||||
#define LL_LLSDSERIALIZE_H
|
||||
|
||||
#include <iosfwd>
|
||||
#include "llpointer.h"
|
||||
#include "llrefcount.h"
|
||||
#include "llsd.h"
|
||||
#include "llmemory.h"
|
||||
|
||||
/**
|
||||
* @class LLSDParser
|
||||
@@ -787,4 +788,7 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
//dirty little zip functions -- yell at davep
|
||||
LL_COMMON_API std::string zip_llsd(LLSD& data);
|
||||
LL_COMMON_API bool unzip_llsd(LLSD& data, std::istream& is, S32 size);
|
||||
#endif // LL_LLSDSERIALIZE_H
|
||||
|
||||
@@ -37,6 +37,7 @@
|
||||
#include <deque>
|
||||
|
||||
#include "apr_base64.h"
|
||||
#include <boost/regex.hpp>
|
||||
|
||||
extern "C"
|
||||
{
|
||||
@@ -734,6 +735,7 @@ void LLSDXMLParser::Impl::endElementHandler(const XML_Char* name)
|
||||
case ELEMENT_INTEGER:
|
||||
{
|
||||
S32 i;
|
||||
// sscanf okay here with different locales - ints don't change for different locale settings like floats do.
|
||||
if ( sscanf(mCurrentContent.c_str(), "%d", &i ) == 1 )
|
||||
{ // See if sscanf works - it's faster
|
||||
value = i;
|
||||
@@ -747,15 +749,19 @@ void LLSDXMLParser::Impl::endElementHandler(const XML_Char* name)
|
||||
|
||||
case ELEMENT_REAL:
|
||||
{
|
||||
F64 r;
|
||||
if ( sscanf(mCurrentContent.c_str(), "%lf", &r ) == 1 )
|
||||
{ // See if sscanf works - it's faster
|
||||
value = r;
|
||||
}
|
||||
else
|
||||
{
|
||||
value = LLSD(mCurrentContent).asReal();
|
||||
}
|
||||
value = LLSD(mCurrentContent).asReal();
|
||||
// removed since this breaks when locale has decimal separator that isn't '.'
|
||||
// investigated changing local to something compatible each time but deemed higher
|
||||
// risk that just using LLSD.asReal() each time.
|
||||
//F64 r;
|
||||
//if ( sscanf(mCurrentContent.c_str(), "%lf", &r ) == 1 )
|
||||
//{ // See if sscanf works - it's faster
|
||||
// value = r;
|
||||
//}
|
||||
//else
|
||||
//{
|
||||
// value = LLSD(mCurrentContent).asReal();
|
||||
//}
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -777,10 +783,17 @@ void LLSDXMLParser::Impl::endElementHandler(const XML_Char* name)
|
||||
|
||||
case ELEMENT_BINARY:
|
||||
{
|
||||
S32 len = apr_base64_decode_len(mCurrentContent.c_str());
|
||||
// Regex is expensive, but only fix for whitespace in base64,
|
||||
// created by python and other non-linden systems - DEV-39358
|
||||
// Fortunately we have very little binary passing now,
|
||||
// so performance impact shold be negligible. + poppy 2009-09-04
|
||||
boost::regex r;
|
||||
r.assign("\\s");
|
||||
std::string stripped = boost::regex_replace(mCurrentContent, r, "");
|
||||
S32 len = apr_base64_decode_len(stripped.c_str());
|
||||
std::vector<U8> data;
|
||||
data.resize(len);
|
||||
len = apr_base64_decode_binary(&data[0], mCurrentContent.c_str());
|
||||
len = apr_base64_decode_binary(&data[0], stripped.c_str());
|
||||
data.resize(len);
|
||||
value = data;
|
||||
break;
|
||||
|
||||
@@ -46,6 +46,12 @@
|
||||
#endif
|
||||
|
||||
#include "llsdserialize.h"
|
||||
#include "stringize.h"
|
||||
#include "is_approx_equal_fraction.h"
|
||||
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <boost/range.hpp>
|
||||
|
||||
// U32
|
||||
LLSD ll_sd_from_U32(const U32 val)
|
||||
@@ -171,6 +177,15 @@ char* ll_print_sd(const LLSD& sd)
|
||||
return buffer;
|
||||
}
|
||||
|
||||
char* ll_pretty_print_sd_ptr(const LLSD* sd)
|
||||
{
|
||||
if (sd)
|
||||
{
|
||||
return ll_pretty_print_sd(*sd);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char* ll_pretty_print_sd(const LLSD& sd)
|
||||
{
|
||||
const U32 bufferSize = 10 * 1024;
|
||||
@@ -304,3 +319,363 @@ BOOL compare_llsd_with_template(
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* Helpers for llsd_matches()
|
||||
*****************************************************************************/
|
||||
// raw data used for LLSD::Type lookup
|
||||
struct Data
|
||||
{
|
||||
LLSD::Type type;
|
||||
const char* name;
|
||||
} typedata[] =
|
||||
{
|
||||
#define def(type) { LLSD::type, #type + 4 }
|
||||
def(TypeUndefined),
|
||||
def(TypeBoolean),
|
||||
def(TypeInteger),
|
||||
def(TypeReal),
|
||||
def(TypeString),
|
||||
def(TypeUUID),
|
||||
def(TypeDate),
|
||||
def(TypeURI),
|
||||
def(TypeBinary),
|
||||
def(TypeMap),
|
||||
def(TypeArray)
|
||||
#undef def
|
||||
};
|
||||
|
||||
// LLSD::Type lookup class into which we load the above static data
|
||||
class TypeLookup
|
||||
{
|
||||
typedef std::map<LLSD::Type, std::string> MapType;
|
||||
|
||||
public:
|
||||
TypeLookup()
|
||||
{
|
||||
for (const Data *di(boost::begin(typedata)), *dend(boost::end(typedata)); di != dend; ++di)
|
||||
{
|
||||
mMap[di->type] = di->name;
|
||||
}
|
||||
}
|
||||
|
||||
std::string lookup(LLSD::Type type) const
|
||||
{
|
||||
MapType::const_iterator found = mMap.find(type);
|
||||
if (found != mMap.end())
|
||||
{
|
||||
return found->second;
|
||||
}
|
||||
return STRINGIZE("<unknown LLSD type " << type << ">");
|
||||
}
|
||||
|
||||
private:
|
||||
MapType mMap;
|
||||
};
|
||||
|
||||
// static instance of the lookup class
|
||||
static const TypeLookup sTypes;
|
||||
|
||||
// describe a mismatch; phrasing may want tweaking
|
||||
const std::string op(" required instead of ");
|
||||
|
||||
// llsd_matches() wants to identify specifically where in a complex prototype
|
||||
// structure the mismatch occurred. This entails passing a prefix string,
|
||||
// empty for the top-level call. If the prototype contains an array of maps,
|
||||
// and the mismatch occurs in the second map in a key 'foo', we want to
|
||||
// decorate the returned string with: "[1]['foo']: etc." On the other hand, we
|
||||
// want to omit the entire prefix -- including colon -- if the mismatch is at
|
||||
// top level. This helper accepts the (possibly empty) recursively-accumulated
|
||||
// prefix string, returning either empty or the original string with colon
|
||||
// appended.
|
||||
static std::string colon(const std::string& pfx)
|
||||
{
|
||||
if (pfx.empty())
|
||||
return pfx;
|
||||
return pfx + ": ";
|
||||
}
|
||||
|
||||
// param type for match_types
|
||||
typedef std::vector<LLSD::Type> TypeVector;
|
||||
|
||||
// The scalar cases in llsd_matches() use this helper. In most cases, we can
|
||||
// accept not only the exact type specified in the prototype, but also other
|
||||
// types convertible to the expected type. That implies looping over an array
|
||||
// of such types. If the actual type doesn't match any of them, we want to
|
||||
// provide a list of acceptable conversions as well as the exact type, e.g.:
|
||||
// "Integer (or Boolean, Real, String) required instead of UUID". Both the
|
||||
// implementation and the calling logic are simplified by separating out the
|
||||
// expected type from the convertible types.
|
||||
static std::string match_types(LLSD::Type expect, // prototype.type()
|
||||
const TypeVector& accept, // types convertible to that type
|
||||
LLSD::Type actual, // type we're checking
|
||||
const std::string& pfx) // as for llsd_matches
|
||||
{
|
||||
// Trivial case: if the actual type is exactly what we expect, we're good.
|
||||
if (actual == expect)
|
||||
return "";
|
||||
|
||||
// For the rest of the logic, build up a suitable error string as we go so
|
||||
// we only have to make a single pass over the list of acceptable types.
|
||||
// If we detect success along the way, we'll simply discard the partial
|
||||
// error string.
|
||||
std::ostringstream out;
|
||||
out << colon(pfx) << sTypes.lookup(expect);
|
||||
|
||||
// If there are any convertible types, append that list.
|
||||
if (! accept.empty())
|
||||
{
|
||||
out << " (";
|
||||
const char* sep = "or ";
|
||||
for (TypeVector::const_iterator ai(accept.begin()), aend(accept.end());
|
||||
ai != aend; ++ai, sep = ", ")
|
||||
{
|
||||
// Don't forget to return success if we match any of those types...
|
||||
if (actual == *ai)
|
||||
return "";
|
||||
out << sep << sTypes.lookup(*ai);
|
||||
}
|
||||
out << ')';
|
||||
}
|
||||
// If we got this far, it's because 'actual' was not one of the acceptable
|
||||
// types, so we must return an error. 'out' already contains colon(pfx)
|
||||
// and the formatted list of acceptable types, so just append the mismatch
|
||||
// phrase and the actual type.
|
||||
out << op << sTypes.lookup(actual);
|
||||
return out.str();
|
||||
}
|
||||
|
||||
// see docstring in .h file
|
||||
std::string llsd_matches(const LLSD& prototype, const LLSD& data, const std::string& pfx)
|
||||
{
|
||||
// An undefined prototype means that any data is valid.
|
||||
// An undefined slot in an array or map prototype means that any data
|
||||
// may fill that slot.
|
||||
if (prototype.isUndefined())
|
||||
return "";
|
||||
// A prototype array must match a data array with at least as many
|
||||
// entries. Moreover, every prototype entry must match the
|
||||
// corresponding data entry.
|
||||
if (prototype.isArray())
|
||||
{
|
||||
if (! data.isArray())
|
||||
{
|
||||
return STRINGIZE(colon(pfx) << "Array" << op << sTypes.lookup(data.type()));
|
||||
}
|
||||
if (data.size() < prototype.size())
|
||||
{
|
||||
return STRINGIZE(colon(pfx) << "Array size " << prototype.size() << op
|
||||
<< "Array size " << data.size());
|
||||
}
|
||||
for (LLSD::Integer i = 0; i < prototype.size(); ++i)
|
||||
{
|
||||
std::string match(llsd_matches(prototype[i], data[i], STRINGIZE('[' << i << ']')));
|
||||
if (! match.empty())
|
||||
{
|
||||
return match;
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
// A prototype map must match a data map. Every key in the prototype
|
||||
// must have a corresponding key in the data map; every value in the
|
||||
// prototype must match the corresponding key's value in the data.
|
||||
if (prototype.isMap())
|
||||
{
|
||||
if (! data.isMap())
|
||||
{
|
||||
return STRINGIZE(colon(pfx) << "Map" << op << sTypes.lookup(data.type()));
|
||||
}
|
||||
// If there are a number of keys missing from the data, it would be
|
||||
// frustrating to a coder to discover them one at a time, with a big
|
||||
// build each time. Enumerate all missing keys.
|
||||
std::ostringstream out;
|
||||
out << colon(pfx);
|
||||
const char* init = "Map missing keys: ";
|
||||
const char* sep = init;
|
||||
for (LLSD::map_const_iterator mi = prototype.beginMap(); mi != prototype.endMap(); ++mi)
|
||||
{
|
||||
if (! data.has(mi->first))
|
||||
{
|
||||
out << sep << mi->first;
|
||||
sep = ", ";
|
||||
}
|
||||
}
|
||||
// So... are we missing any keys?
|
||||
if (sep != init)
|
||||
{
|
||||
return out.str();
|
||||
}
|
||||
// Good, the data block contains all the keys required by the
|
||||
// prototype. Now match the prototype entries.
|
||||
for (LLSD::map_const_iterator mi2 = prototype.beginMap(); mi2 != prototype.endMap(); ++mi2)
|
||||
{
|
||||
std::string match(llsd_matches(mi2->second, data[mi2->first],
|
||||
STRINGIZE("['" << mi2->first << "']")));
|
||||
if (! match.empty())
|
||||
{
|
||||
return match;
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
// A String prototype can match String, Boolean, Integer, Real, UUID,
|
||||
// Date and URI, because any of these can be converted to String.
|
||||
if (prototype.isString())
|
||||
{
|
||||
static LLSD::Type accept[] =
|
||||
{
|
||||
LLSD::TypeBoolean,
|
||||
LLSD::TypeInteger,
|
||||
LLSD::TypeReal,
|
||||
LLSD::TypeUUID,
|
||||
LLSD::TypeDate,
|
||||
LLSD::TypeURI
|
||||
};
|
||||
return match_types(prototype.type(),
|
||||
TypeVector(boost::begin(accept), boost::end(accept)),
|
||||
data.type(),
|
||||
pfx);
|
||||
}
|
||||
// Boolean, Integer, Real match each other or String. TBD: ensure that
|
||||
// a String value is numeric.
|
||||
if (prototype.isBoolean() || prototype.isInteger() || prototype.isReal())
|
||||
{
|
||||
static LLSD::Type all[] =
|
||||
{
|
||||
LLSD::TypeBoolean,
|
||||
LLSD::TypeInteger,
|
||||
LLSD::TypeReal,
|
||||
LLSD::TypeString
|
||||
};
|
||||
// Funny business: shuffle the set of acceptable types to include all
|
||||
// but the prototype's type. Get the acceptable types in a set.
|
||||
std::set<LLSD::Type> rest(boost::begin(all), boost::end(all));
|
||||
// Remove the prototype's type because we pass that separately.
|
||||
rest.erase(prototype.type());
|
||||
return match_types(prototype.type(),
|
||||
TypeVector(rest.begin(), rest.end()),
|
||||
data.type(),
|
||||
pfx);
|
||||
}
|
||||
// UUID, Date and URI match themselves or String.
|
||||
if (prototype.isUUID() || prototype.isDate() || prototype.isURI())
|
||||
{
|
||||
static LLSD::Type accept[] =
|
||||
{
|
||||
LLSD::TypeString
|
||||
};
|
||||
return match_types(prototype.type(),
|
||||
TypeVector(boost::begin(accept), boost::end(accept)),
|
||||
data.type(),
|
||||
pfx);
|
||||
}
|
||||
// We don't yet know the conversion semantics associated with any new LLSD
|
||||
// data type that might be added, so until we've been extended to handle
|
||||
// them, assume it's strict: the new type matches only itself. (This is
|
||||
// true of Binary, which is why we don't handle that case separately.) Too
|
||||
// bad LLSD doesn't define isConvertible(Type to, Type from).
|
||||
return match_types(prototype.type(), TypeVector(), data.type(), pfx);
|
||||
}
|
||||
|
||||
bool llsd_equals(const LLSD& lhs, const LLSD& rhs, unsigned bits)
|
||||
{
|
||||
// We're comparing strict equality of LLSD representation rather than
|
||||
// performing any conversions. So if the types aren't equal, the LLSD
|
||||
// values aren't equal.
|
||||
if (lhs.type() != rhs.type())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Here we know both types are equal. Now compare values.
|
||||
switch (lhs.type())
|
||||
{
|
||||
case LLSD::TypeUndefined:
|
||||
// Both are TypeUndefined. There's nothing more to know.
|
||||
return true;
|
||||
|
||||
case LLSD::TypeReal:
|
||||
// This is where the 'bits' argument comes in handy. If passed
|
||||
// explicitly, it means to use is_approx_equal_fraction() to compare.
|
||||
if (bits >= 0)
|
||||
{
|
||||
return is_approx_equal_fraction(lhs.asReal(), rhs.asReal(), bits);
|
||||
}
|
||||
// Otherwise we compare bit representations, and the usual caveats
|
||||
// about comparing floating-point numbers apply. Omitting 'bits' when
|
||||
// comparing Real values is only useful when we expect identical bit
|
||||
// representation for a given Real value, e.g. for integer-valued
|
||||
// Reals.
|
||||
return (lhs.asReal() == rhs.asReal());
|
||||
|
||||
#define COMPARE_SCALAR(type) \
|
||||
case LLSD::Type##type: \
|
||||
/* LLSD::URI has operator!=() but not operator==() */ \
|
||||
/* rely on the optimizer for all others */ \
|
||||
return (! (lhs.as##type() != rhs.as##type()))
|
||||
|
||||
COMPARE_SCALAR(Boolean);
|
||||
COMPARE_SCALAR(Integer);
|
||||
COMPARE_SCALAR(String);
|
||||
COMPARE_SCALAR(UUID);
|
||||
COMPARE_SCALAR(Date);
|
||||
COMPARE_SCALAR(URI);
|
||||
COMPARE_SCALAR(Binary);
|
||||
|
||||
#undef COMPARE_SCALAR
|
||||
|
||||
case LLSD::TypeArray:
|
||||
{
|
||||
LLSD::array_const_iterator
|
||||
lai(lhs.beginArray()), laend(lhs.endArray()),
|
||||
rai(rhs.beginArray()), raend(rhs.endArray());
|
||||
// Compare array elements, walking the two arrays in parallel.
|
||||
for ( ; lai != laend && rai != raend; ++lai, ++rai)
|
||||
{
|
||||
// If any one array element is unequal, the arrays are unequal.
|
||||
if (! llsd_equals(*lai, *rai, bits))
|
||||
return false;
|
||||
}
|
||||
// Here we've reached the end of one or the other array. They're equal
|
||||
// only if they're BOTH at end: that is, if they have equal length too.
|
||||
return (lai == laend && rai == raend);
|
||||
}
|
||||
|
||||
case LLSD::TypeMap:
|
||||
{
|
||||
// Build a set of all rhs keys.
|
||||
std::set<LLSD::String> rhskeys;
|
||||
for (LLSD::map_const_iterator rmi(rhs.beginMap()), rmend(rhs.endMap());
|
||||
rmi != rmend; ++rmi)
|
||||
{
|
||||
rhskeys.insert(rmi->first);
|
||||
}
|
||||
// Now walk all the lhs keys.
|
||||
for (LLSD::map_const_iterator lmi(lhs.beginMap()), lmend(lhs.endMap());
|
||||
lmi != lmend; ++lmi)
|
||||
{
|
||||
// Try to erase this lhs key from the set of rhs keys. If rhs has
|
||||
// no such key, the maps are unequal. erase(key) returns count of
|
||||
// items erased.
|
||||
if (rhskeys.erase(lmi->first) != 1)
|
||||
return false;
|
||||
// Both maps have the current key. Compare values.
|
||||
if (! llsd_equals(lmi->second, rhs[lmi->first], bits))
|
||||
return false;
|
||||
}
|
||||
// We've now established that all the lhs keys have equal values in
|
||||
// both maps. The maps are equal unless rhs contains a superset of
|
||||
// those keys.
|
||||
return rhskeys.empty();
|
||||
}
|
||||
|
||||
default:
|
||||
// We expect that every possible type() value is specifically handled
|
||||
// above. Failing to extend this switch to support a new LLSD type is
|
||||
// an error that must be brought to the coder's attention.
|
||||
LL_ERRS("llsd_equals") << "llsd_equals(" << lhs << ", " << rhs << ", " << bits << "): "
|
||||
"unknown type " << lhs.type() << LL_ENDL;
|
||||
return false; // pacify the compiler
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
#ifndef LL_LLSDUTIL_H
|
||||
#define LL_LLSDUTIL_H
|
||||
|
||||
#include "llsd.h"
|
||||
class LLSD;
|
||||
|
||||
// U32
|
||||
LL_COMMON_API LLSD ll_sd_from_U32(const U32);
|
||||
@@ -59,6 +59,7 @@ LL_COMMON_API LLSD ll_binary_from_string(const LLSD& sd);
|
||||
LL_COMMON_API char* ll_print_sd(const LLSD& sd);
|
||||
|
||||
// Serializes sd to static buffer and returns pointer, using "pretty printing" mode.
|
||||
LL_COMMON_API char* ll_pretty_print_sd_ptr(const LLSD* sd);
|
||||
LL_COMMON_API char* ll_pretty_print_sd(const LLSD& sd);
|
||||
|
||||
//compares the structure of an LLSD to a template LLSD and stores the
|
||||
@@ -73,6 +74,66 @@ LL_COMMON_API BOOL compare_llsd_with_template(
|
||||
const LLSD& template_llsd,
|
||||
LLSD& resultant_llsd);
|
||||
|
||||
/**
|
||||
* Recursively determine whether a given LLSD data block "matches" another
|
||||
* LLSD prototype. The returned string is empty() on success, non-empty() on
|
||||
* mismatch.
|
||||
*
|
||||
* This function tests structure (types) rather than data values. It is
|
||||
* intended for when a consumer expects an LLSD block with a particular
|
||||
* structure, and must succinctly detect whether the arriving block is
|
||||
* well-formed. For instance, a test of the form:
|
||||
* @code
|
||||
* if (! (data.has("request") && data.has("target") && data.has("modifier") ...))
|
||||
* @endcode
|
||||
* could instead be expressed by initializing a prototype LLSD map with the
|
||||
* required keys and writing:
|
||||
* @code
|
||||
* if (! llsd_matches(prototype, data).empty())
|
||||
* @endcode
|
||||
*
|
||||
* A non-empty return value is an error-message fragment intended to indicate
|
||||
* to (English-speaking) developers where in the prototype structure the
|
||||
* mismatch occurred.
|
||||
*
|
||||
* * If a slot in the prototype isUndefined(), then anything is valid at that
|
||||
* place in the real object. (Passing prototype == LLSD() matches anything
|
||||
* at all.)
|
||||
* * An array in the prototype must match a data array at least that large.
|
||||
* (Additional entries in the data array are ignored.) Every isDefined()
|
||||
* entry in the prototype array must match the corresponding entry in the
|
||||
* data array.
|
||||
* * A map in the prototype must match a map in the data. Every key in the
|
||||
* prototype map must match a corresponding key in the data map. (Additional
|
||||
* keys in the data map are ignored.) Every isDefined() value in the
|
||||
* prototype map must match the corresponding key's value in the data map.
|
||||
* * Scalar values in the prototype are tested for @em type rather than value.
|
||||
* For instance, a String in the prototype matches any String at all. In
|
||||
* effect, storing an Integer at a particular place in the prototype asserts
|
||||
* that the caller intends to apply asInteger() to the corresponding slot in
|
||||
* the data.
|
||||
* * A String in the prototype matches String, Boolean, Integer, Real, UUID,
|
||||
* Date and URI, because asString() applied to any of these produces a
|
||||
* meaningful result.
|
||||
* * Similarly, a Boolean, Integer or Real in the prototype can match any of
|
||||
* Boolean, Integer or Real in the data -- or even String.
|
||||
* * UUID matches UUID or String.
|
||||
* * Date matches Date or String.
|
||||
* * URI matches URI or String.
|
||||
* * Binary in the prototype matches only Binary in the data.
|
||||
*
|
||||
* @TODO: when a Boolean, Integer or Real in the prototype matches a String in
|
||||
* the data, we should examine the String @em value to ensure it can be
|
||||
* meaningfully converted to the requested type. The same goes for UUID, Date
|
||||
* and URI.
|
||||
*/
|
||||
LL_COMMON_API std::string llsd_matches(const LLSD& prototype, const LLSD& data, const std::string& pfx="");
|
||||
|
||||
/// Deep equality. If you want to compare LLSD::Real values for approximate
|
||||
/// equality rather than bitwise equality, pass @a bits as for
|
||||
/// is_approx_equal_fraction().
|
||||
LL_COMMON_API bool llsd_equals(const LLSD& lhs, const LLSD& rhs, unsigned bits=-1);
|
||||
|
||||
// Simple function to copy data out of input & output iterators if
|
||||
// there is no need for casting.
|
||||
template<typename Input> LLSD llsd_copy_array(Input iter, Input end)
|
||||
@@ -85,4 +146,283 @@ template<typename Input> LLSD llsd_copy_array(Input iter, Input end)
|
||||
return dest;
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* LLSDArray
|
||||
*****************************************************************************/
|
||||
/**
|
||||
* Construct an LLSD::Array inline, with implicit conversion to LLSD. Usage:
|
||||
*
|
||||
* @code
|
||||
* void somefunc(const LLSD&);
|
||||
* ...
|
||||
* somefunc(LLSDArray("text")(17)(3.14));
|
||||
* @endcode
|
||||
*
|
||||
* For completeness, LLSDArray() with no args constructs an empty array, so
|
||||
* <tt>LLSDArray()("text")(17)(3.14)</tt> produces an array equivalent to the
|
||||
* above. But for most purposes, LLSD() is already equivalent to an empty
|
||||
* array, and if you explicitly want an empty isArray(), there's
|
||||
* LLSD::emptyArray(). However, supporting a no-args LLSDArray() constructor
|
||||
* follows the principle of least astonishment.
|
||||
*/
|
||||
class LLSDArray
|
||||
{
|
||||
public:
|
||||
LLSDArray():
|
||||
_data(LLSD::emptyArray())
|
||||
{}
|
||||
|
||||
/**
|
||||
* Need an explicit copy constructor. Consider the following:
|
||||
*
|
||||
* @code
|
||||
* LLSD array_of_arrays(LLSDArray(LLSDArray(17)(34))
|
||||
* (LLSDArray("x")("y")));
|
||||
* @endcode
|
||||
*
|
||||
* The coder intends to construct [[17, 34], ["x", "y"]].
|
||||
*
|
||||
* With the compiler's implicit copy constructor, s/he gets instead
|
||||
* [17, 34, ["x", "y"]].
|
||||
*
|
||||
* The expression LLSDArray(17)(34) constructs an LLSDArray with those two
|
||||
* values. The reader assumes it should be converted to LLSD, as we always
|
||||
* want with LLSDArray, before passing it to the @em outer LLSDArray
|
||||
* constructor! This copy constructor makes that happen.
|
||||
*/
|
||||
LLSDArray(const LLSDArray& inner):
|
||||
_data(LLSD::emptyArray())
|
||||
{
|
||||
_data.append(inner);
|
||||
}
|
||||
|
||||
LLSDArray(const LLSD& value):
|
||||
_data(LLSD::emptyArray())
|
||||
{
|
||||
_data.append(value);
|
||||
}
|
||||
|
||||
LLSDArray& operator()(const LLSD& value)
|
||||
{
|
||||
_data.append(value);
|
||||
return *this;
|
||||
}
|
||||
|
||||
operator LLSD() const { return _data; }
|
||||
LLSD get() const { return _data; }
|
||||
|
||||
private:
|
||||
LLSD _data;
|
||||
};
|
||||
|
||||
/*****************************************************************************
|
||||
* LLSDMap
|
||||
*****************************************************************************/
|
||||
/**
|
||||
* Construct an LLSD::Map inline, with implicit conversion to LLSD. Usage:
|
||||
*
|
||||
* @code
|
||||
* void somefunc(const LLSD&);
|
||||
* ...
|
||||
* somefunc(LLSDMap("alpha", "abc")("number", 17)("pi", 3.14));
|
||||
* @endcode
|
||||
*
|
||||
* For completeness, LLSDMap() with no args constructs an empty map, so
|
||||
* <tt>LLSDMap()("alpha", "abc")("number", 17)("pi", 3.14)</tt> produces a map
|
||||
* equivalent to the above. But for most purposes, LLSD() is already
|
||||
* equivalent to an empty map, and if you explicitly want an empty isMap(),
|
||||
* there's LLSD::emptyMap(). However, supporting a no-args LLSDMap()
|
||||
* constructor follows the principle of least astonishment.
|
||||
*/
|
||||
class LLSDMap
|
||||
{
|
||||
public:
|
||||
LLSDMap():
|
||||
_data(LLSD::emptyMap())
|
||||
{}
|
||||
LLSDMap(const LLSD::String& key, const LLSD& value):
|
||||
_data(LLSD::emptyMap())
|
||||
{
|
||||
_data[key] = value;
|
||||
}
|
||||
|
||||
LLSDMap& operator()(const LLSD::String& key, const LLSD& value)
|
||||
{
|
||||
_data[key] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
operator LLSD() const { return _data; }
|
||||
LLSD get() const { return _data; }
|
||||
|
||||
private:
|
||||
LLSD _data;
|
||||
};
|
||||
|
||||
/*****************************************************************************
|
||||
* LLSDParam
|
||||
*****************************************************************************/
|
||||
/**
|
||||
* LLSDParam is a customization point for passing LLSD values to function
|
||||
* parameters of more or less arbitrary type. LLSD provides a small set of
|
||||
* native conversions; but if a generic algorithm explicitly constructs an
|
||||
* LLSDParam object in the function's argument list, a consumer can provide
|
||||
* LLSDParam specializations to support more different parameter types than
|
||||
* LLSD's native conversions.
|
||||
*
|
||||
* Usage:
|
||||
*
|
||||
* @code
|
||||
* void somefunc(const paramtype&);
|
||||
* ...
|
||||
* somefunc(..., LLSDParam<paramtype>(someLLSD), ...);
|
||||
* @endcode
|
||||
*/
|
||||
template <typename T>
|
||||
class LLSDParam
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Default implementation converts to T on construction, saves converted
|
||||
* value for later retrieval
|
||||
*/
|
||||
LLSDParam(const LLSD& value):
|
||||
_value(value)
|
||||
{}
|
||||
|
||||
operator T() const { return _value; }
|
||||
|
||||
private:
|
||||
T _value;
|
||||
};
|
||||
|
||||
/**
|
||||
* Turns out that several target types could accept an LLSD param using any of
|
||||
* a few different conversions, e.g. LLUUID's constructor can accept LLUUID or
|
||||
* std::string. Therefore, the compiler can't decide which LLSD conversion
|
||||
* operator to choose, even though to us it seems obvious. But that's okay, we
|
||||
* can specialize LLSDParam for such target types, explicitly specifying the
|
||||
* desired conversion -- that's part of what LLSDParam is all about. Turns out
|
||||
* we have to do that enough to make it worthwhile generalizing. Use a macro
|
||||
* because I need to specify one of the asReal, etc., explicit conversion
|
||||
* methods as well as a type. If I'm overlooking a clever way to implement
|
||||
* that using a template instead, feel free to reimplement.
|
||||
*/
|
||||
#define LLSDParam_for(T, AS) \
|
||||
template <> \
|
||||
class LLSDParam<T> \
|
||||
{ \
|
||||
public: \
|
||||
LLSDParam(const LLSD& value): \
|
||||
_value(value.AS()) \
|
||||
{} \
|
||||
\
|
||||
operator T() const { return _value; } \
|
||||
\
|
||||
private: \
|
||||
T _value; \
|
||||
}
|
||||
|
||||
LLSDParam_for(float, asReal);
|
||||
LLSDParam_for(LLUUID, asUUID);
|
||||
LLSDParam_for(LLDate, asDate);
|
||||
LLSDParam_for(LLURI, asURI);
|
||||
LLSDParam_for(LLSD::Binary, asBinary);
|
||||
|
||||
/**
|
||||
* LLSDParam<const char*> is an example of the kind of conversion you can
|
||||
* support with LLSDParam beyond native LLSD conversions. Normally you can't
|
||||
* pass an LLSD object to a function accepting const char* -- but you can
|
||||
* safely pass an LLSDParam<const char*>(yourLLSD).
|
||||
*/
|
||||
template <>
|
||||
class LLSDParam<const char*>
|
||||
{
|
||||
private:
|
||||
// The difference here is that we store a std::string rather than a const
|
||||
// char*. It's important that the LLSDParam object own the std::string.
|
||||
std::string _value;
|
||||
// We don't bother storing the incoming LLSD object, but we do have to
|
||||
// distinguish whether _value is an empty string because the LLSD object
|
||||
// contains an empty string or because it's isUndefined().
|
||||
bool _undefined;
|
||||
|
||||
public:
|
||||
LLSDParam(const LLSD& value):
|
||||
_value(value),
|
||||
_undefined(value.isUndefined())
|
||||
{}
|
||||
|
||||
// The const char* we retrieve is for storage owned by our _value member.
|
||||
// That's how we guarantee that the const char* is valid for the lifetime
|
||||
// of this LLSDParam object. Constructing your LLSDParam in the argument
|
||||
// list should ensure that the LLSDParam object will persist for the
|
||||
// duration of the function call.
|
||||
operator const char*() const
|
||||
{
|
||||
if (_undefined)
|
||||
{
|
||||
// By default, an isUndefined() LLSD object's asString() method
|
||||
// will produce an empty string. But for a function accepting
|
||||
// const char*, it's often important to be able to pass NULL, and
|
||||
// isUndefined() seems like the best way. If you want to pass an
|
||||
// empty string, you can still pass LLSD(""). Without this special
|
||||
// case, though, no LLSD value could pass NULL.
|
||||
return NULL;
|
||||
}
|
||||
return _value.c_str();
|
||||
}
|
||||
};
|
||||
|
||||
namespace llsd
|
||||
{
|
||||
|
||||
/*****************************************************************************
|
||||
* BOOST_FOREACH() helpers for LLSD
|
||||
*****************************************************************************/
|
||||
/// Usage: BOOST_FOREACH(LLSD item, inArray(someLLSDarray)) { ... }
|
||||
class inArray
|
||||
{
|
||||
public:
|
||||
inArray(const LLSD& array):
|
||||
_array(array)
|
||||
{}
|
||||
|
||||
typedef LLSD::array_const_iterator const_iterator;
|
||||
typedef LLSD::array_iterator iterator;
|
||||
|
||||
iterator begin() { return _array.beginArray(); }
|
||||
iterator end() { return _array.endArray(); }
|
||||
const_iterator begin() const { return _array.beginArray(); }
|
||||
const_iterator end() const { return _array.endArray(); }
|
||||
|
||||
private:
|
||||
LLSD _array;
|
||||
};
|
||||
|
||||
/// MapEntry is what you get from dereferencing an LLSD::map_[const_]iterator.
|
||||
typedef std::map<LLSD::String, LLSD>::value_type MapEntry;
|
||||
|
||||
/// Usage: BOOST_FOREACH([const] MapEntry& e, inMap(someLLSDmap)) { ... }
|
||||
class inMap
|
||||
{
|
||||
public:
|
||||
inMap(const LLSD& map):
|
||||
_map(map)
|
||||
{}
|
||||
|
||||
typedef LLSD::map_const_iterator const_iterator;
|
||||
typedef LLSD::map_iterator iterator;
|
||||
|
||||
iterator begin() { return _map.beginMap(); }
|
||||
iterator end() { return _map.endMap(); }
|
||||
const_iterator begin() const { return _map.beginMap(); }
|
||||
const_iterator end() const { return _map.endMap(); }
|
||||
|
||||
private:
|
||||
LLSD _map;
|
||||
};
|
||||
|
||||
} // namespace llsd
|
||||
|
||||
#endif // LL_LLSDUTIL_H
|
||||
|
||||
32
indra/llcommon/llsingleton.cpp
Normal file
32
indra/llcommon/llsingleton.cpp
Normal file
@@ -0,0 +1,32 @@
|
||||
/**
|
||||
* @file llsingleton.cpp
|
||||
* @author Brad Kittenbrink
|
||||
*
|
||||
* $LicenseInfo:firstyear=2009&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2010, Linden Research, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#include "linden_common.h"
|
||||
|
||||
#include "llsingleton.h"
|
||||
|
||||
std::map<std::string, void *> * LLSingletonRegistry::sSingletonMap = NULL;
|
||||
|
||||
225
indra/llcommon/llsingleton.h
Normal file
225
indra/llcommon/llsingleton.h
Normal file
@@ -0,0 +1,225 @@
|
||||
/**
|
||||
* @file llsingleton.h
|
||||
*
|
||||
* $LicenseInfo:firstyear=2002&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2010, Linden Research, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
#ifndef LLSINGLETON_H
|
||||
#define LLSINGLETON_H
|
||||
|
||||
#include "llerror.h" // *TODO: eliminate this
|
||||
|
||||
#include <typeinfo>
|
||||
#include <boost/noncopyable.hpp>
|
||||
|
||||
/// @brief A global registry of all singletons to prevent duplicate allocations
|
||||
/// across shared library boundaries
|
||||
class LL_COMMON_API LLSingletonRegistry {
|
||||
private:
|
||||
typedef std::map<std::string, void *> TypeMap;
|
||||
static TypeMap * sSingletonMap;
|
||||
|
||||
static void checkInit()
|
||||
{
|
||||
if(sSingletonMap == NULL)
|
||||
{
|
||||
sSingletonMap = new TypeMap();
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
template<typename T> static void * & get()
|
||||
{
|
||||
std::string name(typeid(T).name());
|
||||
|
||||
checkInit();
|
||||
|
||||
// the first entry of the pair returned by insert will be either the existing
|
||||
// iterator matching our key, or the newly inserted NULL initialized entry
|
||||
// see "Insert element" in http://www.sgi.com/tech/stl/UniqueAssociativeContainer.html
|
||||
TypeMap::iterator result =
|
||||
sSingletonMap->insert(std::make_pair(name, (void*)NULL)).first;
|
||||
|
||||
return result->second;
|
||||
}
|
||||
};
|
||||
|
||||
// LLSingleton implements the getInstance() method part of the Singleton
|
||||
// pattern. It can't make the derived class constructors protected, though, so
|
||||
// you have to do that yourself.
|
||||
//
|
||||
// There are two ways to use LLSingleton. The first way is to inherit from it
|
||||
// while using the typename that you'd like to be static as the template
|
||||
// parameter, like so:
|
||||
//
|
||||
// class Foo: public LLSingleton<Foo>{};
|
||||
//
|
||||
// Foo& instance = Foo::instance();
|
||||
//
|
||||
// The second way is to use the singleton class directly, without inheritance:
|
||||
//
|
||||
// typedef LLSingleton<Foo> FooSingleton;
|
||||
//
|
||||
// Foo& instance = FooSingleton::instance();
|
||||
//
|
||||
// In this case, the class being managed as a singleton needs to provide an
|
||||
// initSingleton() method since the LLSingleton virtual method won't be
|
||||
// available
|
||||
//
|
||||
// As currently written, it is not thread-safe.
|
||||
|
||||
template <typename DERIVED_TYPE>
|
||||
class LLSingleton : private boost::noncopyable
|
||||
{
|
||||
|
||||
private:
|
||||
typedef enum e_init_state
|
||||
{
|
||||
UNINITIALIZED,
|
||||
CONSTRUCTING,
|
||||
INITIALIZING,
|
||||
INITIALIZED,
|
||||
DELETED
|
||||
} EInitState;
|
||||
|
||||
// stores pointer to singleton instance
|
||||
// and tracks initialization state of singleton
|
||||
struct SingletonInstanceData
|
||||
{
|
||||
EInitState mInitState;
|
||||
DERIVED_TYPE* mSingletonInstance;
|
||||
|
||||
SingletonInstanceData()
|
||||
: mSingletonInstance(NULL),
|
||||
mInitState(UNINITIALIZED)
|
||||
{}
|
||||
|
||||
~SingletonInstanceData()
|
||||
{
|
||||
if (mInitState != DELETED)
|
||||
{
|
||||
deleteSingleton();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
public:
|
||||
virtual ~LLSingleton()
|
||||
{
|
||||
SingletonInstanceData& data = getData();
|
||||
data.mSingletonInstance = NULL;
|
||||
data.mInitState = DELETED;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Immediately delete the singleton.
|
||||
*
|
||||
* A subsequent call to LLProxy::getInstance() will construct a new
|
||||
* instance of the class.
|
||||
*
|
||||
* LLSingletons are normally destroyed after main() has exited and the C++
|
||||
* runtime is cleaning up statically-constructed objects. Some classes
|
||||
* derived from LLSingleton have objects that are part of a runtime system
|
||||
* that is terminated before main() exits. Calling the destructor of those
|
||||
* objects after the termination of their respective systems can cause
|
||||
* crashes and other problems during termination of the project. Using this
|
||||
* method to destroy the singleton early can prevent these crashes.
|
||||
*
|
||||
* An example where this is needed is for a LLSingleton that has an APR
|
||||
* object as a member that makes APR calls on destruction. The APR system is
|
||||
* shut down explicitly before main() exits. This causes a crash on exit.
|
||||
* Using this method before the call to apr_terminate() and NOT calling
|
||||
* getInstance() again will prevent the crash.
|
||||
*/
|
||||
static void deleteSingleton()
|
||||
{
|
||||
delete getData().mSingletonInstance;
|
||||
getData().mSingletonInstance = NULL;
|
||||
getData().mInitState = DELETED;
|
||||
}
|
||||
|
||||
static SingletonInstanceData& getData()
|
||||
{
|
||||
// this is static to cache the lookup results
|
||||
static void * & registry = LLSingletonRegistry::get<DERIVED_TYPE>();
|
||||
|
||||
// *TODO - look into making this threadsafe
|
||||
if(NULL == registry)
|
||||
{
|
||||
static SingletonInstanceData data;
|
||||
registry = &data;
|
||||
}
|
||||
|
||||
return *static_cast<SingletonInstanceData *>(registry);
|
||||
}
|
||||
|
||||
static DERIVED_TYPE* getInstance()
|
||||
{
|
||||
SingletonInstanceData& data = getData();
|
||||
|
||||
if (data.mInitState == CONSTRUCTING)
|
||||
{
|
||||
llerrs << "Tried to access singleton " << typeid(DERIVED_TYPE).name() << " from singleton constructor!" << llendl;
|
||||
}
|
||||
|
||||
if (data.mInitState == DELETED)
|
||||
{
|
||||
llwarns << "Trying to access deleted singleton " << typeid(DERIVED_TYPE).name() << " creating new instance" << llendl;
|
||||
}
|
||||
|
||||
if (!data.mSingletonInstance)
|
||||
{
|
||||
data.mInitState = CONSTRUCTING;
|
||||
data.mSingletonInstance = new DERIVED_TYPE();
|
||||
data.mInitState = INITIALIZING;
|
||||
data.mSingletonInstance->initSingleton();
|
||||
data.mInitState = INITIALIZED;
|
||||
}
|
||||
|
||||
return data.mSingletonInstance;
|
||||
}
|
||||
|
||||
// Reference version of getInstance()
|
||||
// Preferred over getInstance() as it disallows checking for NULL
|
||||
static DERIVED_TYPE& instance()
|
||||
{
|
||||
return *getInstance();
|
||||
}
|
||||
|
||||
// Has this singleton been created uet?
|
||||
// Use this to avoid accessing singletons before the can safely be constructed
|
||||
static bool instanceExists()
|
||||
{
|
||||
return getData().mInitState == INITIALIZED;
|
||||
}
|
||||
|
||||
// Has this singleton already been deleted?
|
||||
// Use this to avoid accessing singletons from a static object's destructor
|
||||
static bool destroyed()
|
||||
{
|
||||
return getData().mInitState == DELETED;
|
||||
}
|
||||
|
||||
private:
|
||||
virtual void initSingleton() {}
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -43,9 +43,10 @@
|
||||
|
||||
|
||||
// statics
|
||||
BOOL LLPerfBlock::sStatsEnabled = FALSE; // Flag for detailed information
|
||||
S32 LLPerfBlock::sStatsFlags = LLPerfBlock::LLSTATS_NO_OPTIONAL_STATS; // Control what is being recorded
|
||||
LLPerfBlock::stat_map_t LLPerfBlock::sStatMap; // Map full path string to LLStatTime objects, tracks all active objects
|
||||
std::string LLPerfBlock::sCurrentStatPath = ""; // Something like "/total_time/physics/physics step"
|
||||
LLStat::stat_map_t LLStat::sStatList;
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// Live config file to trigger stats logging
|
||||
@@ -129,6 +130,7 @@ bool LLStatsConfigFile::loadFile()
|
||||
|
||||
F32 duration = 0.f;
|
||||
F32 interval = 0.f;
|
||||
S32 flags = LLPerfBlock::LLSTATS_BASIC_STATS;
|
||||
|
||||
const char * w = "duration";
|
||||
if (stats_config.has(w))
|
||||
@@ -140,8 +142,18 @@ bool LLStatsConfigFile::loadFile()
|
||||
{
|
||||
interval = (F32)stats_config[w].asReal();
|
||||
}
|
||||
w = "flags";
|
||||
if (stats_config.has(w))
|
||||
{
|
||||
flags = (S32)stats_config[w].asInteger();
|
||||
if (flags == LLPerfBlock::LLSTATS_NO_OPTIONAL_STATS &&
|
||||
duration > 0)
|
||||
{ // No flags passed in, but have a duration, so reset to basic stats
|
||||
flags = LLPerfBlock::LLSTATS_BASIC_STATS;
|
||||
}
|
||||
}
|
||||
|
||||
mStatsp->setReportPerformanceDuration( duration );
|
||||
mStatsp->setReportPerformanceDuration( duration, flags );
|
||||
mStatsp->setReportPerformanceInterval( interval );
|
||||
|
||||
if ( duration > 0 )
|
||||
@@ -253,13 +265,14 @@ void LLPerfStats::dumpIntervalPerformanceStats()
|
||||
}
|
||||
}
|
||||
|
||||
// Set length of performance stat recording
|
||||
void LLPerfStats::setReportPerformanceDuration( F32 seconds )
|
||||
// Set length of performance stat recording.
|
||||
// If turning stats on, caller must provide flags
|
||||
void LLPerfStats::setReportPerformanceDuration( F32 seconds, S32 flags /* = LLSTATS_NO_OPTIONAL_STATS */ )
|
||||
{
|
||||
if ( seconds <= 0.f )
|
||||
{
|
||||
mReportPerformanceStatEnd = 0.0;
|
||||
LLPerfBlock::setStatsEnabled( FALSE );
|
||||
LLPerfBlock::setStatsFlags(LLPerfBlock::LLSTATS_NO_OPTIONAL_STATS); // Make sure all recording is off
|
||||
mFrameStatsFile.close();
|
||||
LLPerfBlock::clearDynamicStats();
|
||||
}
|
||||
@@ -268,8 +281,8 @@ void LLPerfStats::setReportPerformanceDuration( F32 seconds )
|
||||
mReportPerformanceStatEnd = LLFrameTimer::getElapsedSeconds() + ((F64) seconds);
|
||||
// Clear failure flag to try and create the log file once
|
||||
mFrameStatsFileFailure = FALSE;
|
||||
LLPerfBlock::setStatsEnabled( TRUE );
|
||||
mSkipFirstFrameStats = TRUE; // Skip the first report (at the end of this frame)
|
||||
LLPerfBlock::setStatsFlags(flags);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -611,11 +624,26 @@ LLPerfBlock::LLPerfBlock(LLStatTime* stat ) : mPredefinedStat(stat), mDynamicSta
|
||||
}
|
||||
}
|
||||
|
||||
// Use this constructor for dynamically created LLStatTime objects (not pre-defined) with a multi-part key.
|
||||
// These are also turned on or off via the switch passed in
|
||||
LLPerfBlock::LLPerfBlock( const char* key1, const char* key2 ) : mPredefinedStat(NULL), mDynamicStat(NULL)
|
||||
// Use this constructor for normal, optional LLPerfBlock time slices
|
||||
LLPerfBlock::LLPerfBlock( const char* key ) : mPredefinedStat(NULL), mDynamicStat(NULL)
|
||||
{
|
||||
if (!sStatsEnabled) return;
|
||||
if ((sStatsFlags & LLSTATS_BASIC_STATS) == 0)
|
||||
{ // These are off unless the base set is enabled
|
||||
return;
|
||||
}
|
||||
|
||||
initDynamicStat(key);
|
||||
}
|
||||
|
||||
|
||||
// Use this constructor for dynamically created LLPerfBlock time slices
|
||||
// that are only enabled by specific control flags
|
||||
LLPerfBlock::LLPerfBlock( const char* key1, const char* key2, S32 flags ) : mPredefinedStat(NULL), mDynamicStat(NULL)
|
||||
{
|
||||
if ((sStatsFlags & flags) == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (NULL == key2 || strlen(key2) == 0)
|
||||
{
|
||||
@@ -629,10 +657,12 @@ LLPerfBlock::LLPerfBlock( const char* key1, const char* key2 ) : mPredefinedStat
|
||||
}
|
||||
}
|
||||
|
||||
// Set up the result data map if dynamic stats are enabled
|
||||
void LLPerfBlock::initDynamicStat(const std::string& key)
|
||||
{
|
||||
// Early exit if dynamic stats aren't enabled.
|
||||
if (!sStatsEnabled) return;
|
||||
if (sStatsFlags == LLSTATS_NO_OPTIONAL_STATS)
|
||||
return;
|
||||
|
||||
mLastPath = sCurrentStatPath; // Save and restore current path
|
||||
sCurrentStatPath += "/" + key; // Add key to current path
|
||||
@@ -713,7 +743,7 @@ void LLPerfBlock::addStatsToLLSDandReset( LLSD & stats,
|
||||
}
|
||||
}
|
||||
else
|
||||
{ // WTF? Shouldn't have a NULL pointer in the map.
|
||||
{ // Shouldn't have a NULL pointer in the map.
|
||||
llwarns << "Unexpected NULL dynamic stat at '" << stats_full_path << "'" << llendl;
|
||||
}
|
||||
}
|
||||
@@ -725,14 +755,12 @@ void LLPerfBlock::addStatsToLLSDandReset( LLSD & stats,
|
||||
LLTimer LLStat::sTimer;
|
||||
LLFrameTimer LLStat::sFrameTimer;
|
||||
|
||||
LLStat::LLStat(const U32 num_bins, const BOOL use_frame_timer)
|
||||
void LLStat::init()
|
||||
{
|
||||
llassert(num_bins > 0);
|
||||
mUseFrameTimer = use_frame_timer;
|
||||
llassert(mNumBins > 0);
|
||||
mNumValues = 0;
|
||||
mLastValue = 0.f;
|
||||
mLastTime = 0.f;
|
||||
mNumBins = num_bins;
|
||||
mCurBin = (mNumBins-1);
|
||||
mNextBin = 0;
|
||||
mBins = new F32[mNumBins];
|
||||
@@ -746,6 +774,29 @@ LLStat::LLStat(const U32 num_bins, const BOOL use_frame_timer)
|
||||
mTime[i] = 0.0;
|
||||
mDT[i] = 0.f;
|
||||
}
|
||||
|
||||
if (!mName.empty())
|
||||
{
|
||||
stat_map_t::iterator iter = sStatList.find(mName);
|
||||
if (iter != sStatList.end())
|
||||
llwarns << "LLStat with duplicate name: " << mName << llendl;
|
||||
sStatList.insert(std::make_pair(mName, this));
|
||||
}
|
||||
}
|
||||
|
||||
LLStat::LLStat(const U32 num_bins, const BOOL use_frame_timer)
|
||||
: mUseFrameTimer(use_frame_timer),
|
||||
mNumBins(num_bins)
|
||||
{
|
||||
init();
|
||||
}
|
||||
|
||||
LLStat::LLStat(std::string name, U32 num_bins, BOOL use_frame_timer)
|
||||
: mUseFrameTimer(use_frame_timer),
|
||||
mNumBins(num_bins),
|
||||
mName(name)
|
||||
{
|
||||
init();
|
||||
}
|
||||
|
||||
LLStat::~LLStat()
|
||||
@@ -754,6 +805,15 @@ LLStat::~LLStat()
|
||||
delete[] mBeginTime;
|
||||
delete[] mTime;
|
||||
delete[] mDT;
|
||||
|
||||
if (!mName.empty())
|
||||
{
|
||||
// handle multiple entries with the same name
|
||||
stat_map_t::iterator iter = sStatList.find(mName);
|
||||
while (iter != sStatList.end() && iter->second != this)
|
||||
++iter;
|
||||
sStatList.erase(iter);
|
||||
}
|
||||
}
|
||||
|
||||
void LLStat::reset()
|
||||
|
||||
@@ -192,14 +192,23 @@ public:
|
||||
// Use this constructor for pre-defined LLStatTime objects
|
||||
LLPerfBlock(LLStatTime* stat);
|
||||
|
||||
// Use this constructor for dynamically created LLStatTime objects (not pre-defined) with a multi-part key
|
||||
LLPerfBlock( const char* key1, const char* key2 = NULL);
|
||||
// Use this constructor for normal, optional LLPerfBlock time slices
|
||||
LLPerfBlock( const char* key );
|
||||
|
||||
// Use this constructor for dynamically created LLPerfBlock time slices
|
||||
// that are only enabled by specific control flags
|
||||
LLPerfBlock( const char* key1, const char* key2, S32 flags = LLSTATS_BASIC_STATS );
|
||||
|
||||
~LLPerfBlock();
|
||||
|
||||
static void setStatsEnabled( BOOL enable ) { sStatsEnabled = enable; };
|
||||
static S32 getStatsEnabled() { return sStatsEnabled; };
|
||||
enum
|
||||
{ // Stats bitfield flags
|
||||
LLSTATS_NO_OPTIONAL_STATS = 0x00, // No optional stats gathering, just pre-defined LLStatTime objects
|
||||
LLSTATS_BASIC_STATS = 0x01, // Gather basic optional runtime stats
|
||||
LLSTATS_SCRIPT_FUNCTIONS = 0x02, // Include LSL function calls
|
||||
};
|
||||
static void setStatsFlags( S32 flags ) { sStatsFlags = flags; };
|
||||
static S32 getStatsFlags() { return sStatsFlags; };
|
||||
|
||||
static void clearDynamicStats(); // Reset maps to clear out dynamic objects
|
||||
static void addStatsToLLSDandReset( LLSD & stats, // Get current information and clear time bin
|
||||
@@ -213,7 +222,7 @@ private:
|
||||
LLStatTime * mPredefinedStat; // LLStatTime object to get data
|
||||
StatEntry * mDynamicStat; // StatEntryobject to get data
|
||||
|
||||
static BOOL sStatsEnabled; // Normally FALSE
|
||||
static S32 sStatsFlags; // Control what is being recorded
|
||||
static stat_map_t sStatMap; // Map full path string to LLStatTime objects
|
||||
static std::string sCurrentStatPath; // Something like "frame/physics/physics step"
|
||||
};
|
||||
@@ -236,7 +245,7 @@ public:
|
||||
BOOL frameStatsIsRunning() { return (mReportPerformanceStatEnd > 0.); };
|
||||
F32 getReportPerformanceInterval() const { return mReportPerformanceStatInterval; };
|
||||
void setReportPerformanceInterval( F32 interval ) { mReportPerformanceStatInterval = interval; };
|
||||
void setReportPerformanceDuration( F32 seconds );
|
||||
void setReportPerformanceDuration( F32 seconds, S32 flags = LLPerfBlock::LLSTATS_NO_OPTIONAL_STATS );
|
||||
void setProcessName(const std::string& process_name) { mProcessName = process_name; }
|
||||
void setProcessPID(S32 process_pid) { mProcessPID = process_pid; }
|
||||
|
||||
@@ -258,8 +267,15 @@ private:
|
||||
// ----------------------------------------------------------------------------
|
||||
class LL_COMMON_API LLStat
|
||||
{
|
||||
private:
|
||||
typedef std::multimap<std::string, LLStat*> stat_map_t;
|
||||
static stat_map_t sStatList;
|
||||
|
||||
void init();
|
||||
|
||||
public:
|
||||
LLStat(const U32 num_bins = 32, BOOL use_frame_timer = FALSE);
|
||||
LLStat(U32 num_bins = 32, BOOL use_frame_timer = FALSE);
|
||||
LLStat(std::string name, U32 num_bins = 32, BOOL use_frame_timer = FALSE);
|
||||
~LLStat();
|
||||
|
||||
void reset();
|
||||
@@ -322,8 +338,22 @@ private:
|
||||
F32 *mDT;
|
||||
S32 mCurBin;
|
||||
S32 mNextBin;
|
||||
|
||||
std::string mName;
|
||||
|
||||
static LLTimer sTimer;
|
||||
static LLFrameTimer sFrameTimer;
|
||||
|
||||
public:
|
||||
static LLStat* getStat(const std::string& name)
|
||||
{
|
||||
// return the first stat that matches 'name'
|
||||
stat_map_t::iterator iter = sStatList.find(name);
|
||||
if (iter != sStatList.end())
|
||||
return iter->second;
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
#endif // LL_STAT_
|
||||
|
||||
@@ -45,7 +45,7 @@
|
||||
// skips spaces and tabs
|
||||
bool skip_whitespace(std::istream& input_stream)
|
||||
{
|
||||
char c = input_stream.peek();
|
||||
int c = input_stream.peek();
|
||||
while (('\t' == c || ' ' == c) && input_stream.good())
|
||||
{
|
||||
input_stream.get();
|
||||
@@ -57,7 +57,7 @@ bool skip_whitespace(std::istream& input_stream)
|
||||
// skips whitespace, newlines, and carriage returns
|
||||
bool skip_emptyspace(std::istream& input_stream)
|
||||
{
|
||||
char c = input_stream.peek();
|
||||
int c = input_stream.peek();
|
||||
while ( input_stream.good()
|
||||
&& ('\t' == c || ' ' == c || '\n' == c || '\r' == c) )
|
||||
{
|
||||
@@ -72,7 +72,7 @@ bool skip_comments_and_emptyspace(std::istream& input_stream)
|
||||
{
|
||||
while (skip_emptyspace(input_stream))
|
||||
{
|
||||
char c = input_stream.peek();
|
||||
int c = input_stream.peek();
|
||||
if ('#' == c )
|
||||
{
|
||||
while ('\n' != c && input_stream.good())
|
||||
@@ -90,7 +90,7 @@ bool skip_comments_and_emptyspace(std::istream& input_stream)
|
||||
|
||||
bool skip_line(std::istream& input_stream)
|
||||
{
|
||||
char c;
|
||||
int c;
|
||||
do
|
||||
{
|
||||
c = input_stream.get();
|
||||
@@ -100,7 +100,7 @@ bool skip_line(std::istream& input_stream)
|
||||
|
||||
bool skip_to_next_word(std::istream& input_stream)
|
||||
{
|
||||
char c = input_stream.peek();
|
||||
int c = input_stream.peek();
|
||||
while ( input_stream.good()
|
||||
&& ( (c >= 'a' && c <= 'z')
|
||||
|| (c >= 'A' && c <= 'Z')
|
||||
@@ -132,7 +132,7 @@ bool skip_to_end_of_next_keyword(const char* keyword, std::istream& input_stream
|
||||
while (input_stream.good())
|
||||
{
|
||||
skip_emptyspace(input_stream);
|
||||
char c = input_stream.get();
|
||||
int c = input_stream.get();
|
||||
if (keyword[0] != c)
|
||||
{
|
||||
skip_line(input_stream);
|
||||
@@ -181,7 +181,7 @@ bool skip_to_start_of_next_keyword(const char* keyword, std::istream& input_stre
|
||||
while (input_stream.good())
|
||||
{
|
||||
skip_emptyspace(input_stream);
|
||||
char c = input_stream.get();
|
||||
int c = input_stream.get();
|
||||
if (keyword[0] != c)
|
||||
{
|
||||
skip_line(input_stream);
|
||||
@@ -229,7 +229,7 @@ bool skip_to_start_of_next_keyword(const char* keyword, std::istream& input_stre
|
||||
bool get_word(std::string& output_string, std::istream& input_stream)
|
||||
{
|
||||
skip_emptyspace(input_stream);
|
||||
char c = input_stream.peek();
|
||||
int c = input_stream.peek();
|
||||
while ( !isspace(c)
|
||||
&& '\n' != c
|
||||
&& '\r' != c
|
||||
@@ -246,7 +246,7 @@ bool get_word(std::string& output_string, std::istream& input_stream, int n)
|
||||
{
|
||||
skip_emptyspace(input_stream);
|
||||
int char_count = 0;
|
||||
char c = input_stream.peek();
|
||||
int c = input_stream.peek();
|
||||
while (!isspace(c)
|
||||
&& '\n' != c
|
||||
&& '\r' != c
|
||||
@@ -265,7 +265,7 @@ bool get_word(std::string& output_string, std::istream& input_stream, int n)
|
||||
bool get_line(std::string& output_string, std::istream& input_stream)
|
||||
{
|
||||
output_string.clear();
|
||||
char c = input_stream.get();
|
||||
int c = input_stream.get();
|
||||
while (input_stream.good())
|
||||
{
|
||||
output_string += c;
|
||||
@@ -285,7 +285,7 @@ bool get_line(std::string& output_string, std::istream& input_stream, int n)
|
||||
{
|
||||
output_string.clear();
|
||||
int char_count = 0;
|
||||
char c = input_stream.get();
|
||||
int c = input_stream.get();
|
||||
while (input_stream.good() && char_count < n)
|
||||
{
|
||||
char_count++;
|
||||
|
||||
@@ -42,14 +42,17 @@ template <class Object> class LLStrider
|
||||
U8* mBytep;
|
||||
};
|
||||
U32 mSkip;
|
||||
//U32 mTypeSize;
|
||||
public:
|
||||
|
||||
LLStrider() { mObjectp = NULL; mSkip = sizeof(Object); }
|
||||
LLStrider() { mObjectp = NULL; /*mTypeSize = */mSkip = sizeof(Object); }
|
||||
~LLStrider() { }
|
||||
|
||||
const LLStrider<Object>& operator = (Object *first) { mObjectp = first; return *this;}
|
||||
void setStride (S32 skipBytes) { mSkip = (skipBytes ? skipBytes : sizeof(Object));}
|
||||
//void setTypeSize (S32 typeBytes){ mTypeSize = (typeBytes ? typeBytes : sizeof(Object)); }
|
||||
|
||||
//bool isStrided() const { return mTypeSize != mSkip; }
|
||||
void skip(const U32 index) { mBytep += mSkip*index;}
|
||||
U32 getSkip() const { return mSkip; }
|
||||
Object* get() { return mObjectp; }
|
||||
@@ -58,6 +61,71 @@ public:
|
||||
Object* operator ++(int) { Object* old = mObjectp; mBytep += mSkip; return old; }
|
||||
Object* operator +=(int i) { mBytep += mSkip*i; return mObjectp; }
|
||||
Object& operator[](U32 index) { return *(Object*)(mBytep + (mSkip * index)); }
|
||||
/*void assignArray(U8* __restrict source, const size_t elem_size, const size_t elem_count)
|
||||
{
|
||||
llassert_always(sizeof(Object) <= elem_size);
|
||||
|
||||
U8* __restrict dest = mBytep; //refer to dest instead of mBytep to benefit from __restrict hint
|
||||
const U32 bytes = elem_size * elem_count; //total bytes to copy from source to dest
|
||||
|
||||
//stride == sizeof(element) implies entire buffer is unstrided and thus memcpy-able, provided source buffer elements match in size.
|
||||
//Because LLStrider is often passed an LLVector3 even if the reprensentation is LLVector4 in the vertex buffer, mTypeSize is set to
|
||||
//the TRUE vbo datatype size via VertexBufferStrider::get
|
||||
if(!isStrided() && mTypeSize == elem_size)
|
||||
{
|
||||
if(bytes >= sizeof(LLVector4) * 4) //Should be able to pull at least 3 16byte blocks from this. Smaller isn't really beneficial.
|
||||
{
|
||||
U8* __restrict aligned_source = LL_NEXT_ALIGNED_ADDRESS(source);
|
||||
U8* __restrict aligned_dest = LL_NEXT_ALIGNED_ADDRESS(dest);
|
||||
const U32 source_offset = aligned_source - source; //Offset to first aligned location in source buffer.
|
||||
const U32 dest_offset = aligned_dest - dest; //Offset to first aligned location in dest buffer.
|
||||
llassert_always(source_offset < 16);
|
||||
llassert_always(dest_offset < 16);
|
||||
if(source_offset == dest_offset) //delta to aligned location matches between source and destination! _mm_*_ps should be viable.
|
||||
{
|
||||
const U32 end_offset = (bytes - source_offset) % sizeof(LLVector4); //buffers may not neatly end on a 16byte alignment boundary.
|
||||
const U32 aligned_bytes = bytes - source_offset - end_offset; //how many bytes to copy from aligned start to aligned end.
|
||||
|
||||
llassert_always(aligned_bytes > 0);
|
||||
|
||||
if(source_offset) //memcpy up to the aligned location if needed
|
||||
memcpy(dest,source,source_offset);
|
||||
LLVector4a::memcpyNonAliased16((F32*) aligned_dest, (F32*) aligned_source, aligned_bytes);
|
||||
if(end_offset) //memcpy to the very end if needed.
|
||||
memcpy(aligned_dest+aligned_bytes,aligned_source+aligned_bytes,end_offset);
|
||||
}
|
||||
else //buffers non-uniformly offset from aligned location. Using _mm_*u_ps.
|
||||
{
|
||||
U32 end = bytes/sizeof(LLVector4); //sizeof(LLVector4) = 16 bytes = 128 bits
|
||||
|
||||
llassert_always(end > 0);
|
||||
|
||||
__m128* dst = (__m128*) dest;
|
||||
__m128* src = (__m128*) source;
|
||||
|
||||
for (U32 i = 0; i < end; i++) //copy 128bit chunks
|
||||
{
|
||||
__m128 res = _mm_loadu_ps((F32*)&src[i]);
|
||||
_mm_storeu_ps((F32*)&dst[i], res);
|
||||
}
|
||||
end*=16;//Convert to real byte offset
|
||||
if(end < bytes) //just memcopy the rest
|
||||
memcpy(dest+end,source+end,bytes-end);
|
||||
}
|
||||
}
|
||||
else //Too small. just do a simple memcpy.
|
||||
memcpy(dest,source,bytes);
|
||||
}
|
||||
else
|
||||
{
|
||||
for(U32 i=0;i<elem_count;i++)
|
||||
{
|
||||
memcpy(dest,source,sizeof(Object));
|
||||
dest+=mSkip;
|
||||
source+=elem_size;
|
||||
}
|
||||
}
|
||||
}*/
|
||||
};
|
||||
|
||||
#endif // LL_LLSTRIDER_H
|
||||
|
||||
@@ -957,13 +957,18 @@ LLStringUtil::size_type LLStringUtil::getSubstitution(const std::string& instr,
|
||||
{
|
||||
const std::string delims (",");
|
||||
|
||||
// Find the first ]
|
||||
size_type pos2 = instr.find(']', start);
|
||||
// Find the first [
|
||||
size_type pos1 = instr.find('[', start);
|
||||
if (pos1 == std::string::npos)
|
||||
return std::string::npos;
|
||||
|
||||
//Find the first ] after the initial [
|
||||
size_type pos2 = instr.find(']', pos1);
|
||||
if (pos2 == std::string::npos)
|
||||
return std::string::npos;
|
||||
|
||||
// Find the last [ before ]
|
||||
size_type pos1 = instr.find_last_of('[', pos2-1);
|
||||
// Find the last [ before ] in case of nested [[]]
|
||||
pos1 = instr.find_last_of('[', pos2-1);
|
||||
if (pos1 == std::string::npos || pos1 < start)
|
||||
return std::string::npos;
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user