Merge branch 'future' of git://github.com/siana/SingularityViewer.git into future
This commit is contained in:
@@ -88,7 +88,7 @@ if (VIEWER)
|
|||||||
add_subdirectory(${VIEWER_PREFIX}linux_crash_logger)
|
add_subdirectory(${VIEWER_PREFIX}linux_crash_logger)
|
||||||
add_dependencies(viewer linux-crash-logger-strip-target)
|
add_dependencies(viewer linux-crash-logger-strip-target)
|
||||||
elseif (DARWIN)
|
elseif (DARWIN)
|
||||||
add_subdirectory(${VIEWER_PREFIX}mac_crash_logger)
|
#add_subdirectory(${VIEWER_PREFIX}mac_crash_logger)
|
||||||
#add_subdirectory(${VIEWER_PREFIX}mac_updater)
|
#add_subdirectory(${VIEWER_PREFIX}mac_updater)
|
||||||
add_dependencies(viewer mac-crash-logger)
|
add_dependencies(viewer mac-crash-logger)
|
||||||
#add_dependencies(viewer mac-updater)
|
#add_dependencies(viewer mac-updater)
|
||||||
|
|||||||
@@ -31,10 +31,10 @@ if (WINDOWS)
|
|||||||
# Don't build DLLs.
|
# Don't build DLLs.
|
||||||
set(BUILD_SHARED_LIBS OFF)
|
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)
|
CACHE STRING "C++ compiler debug options" FORCE)
|
||||||
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO
|
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)
|
CACHE STRING "C++ compiler release-with-debug options" FORCE)
|
||||||
set(CMAKE_CXX_FLAGS_RELEASE
|
set(CMAKE_CXX_FLAGS_RELEASE
|
||||||
"${CMAKE_CXX_FLAGS_RELEASE} ${LL_CXX_FLAGS} /O2 /Zi /MD /MP /arch:SSE /fp:fast"
|
"${CMAKE_CXX_FLAGS_RELEASE} ${LL_CXX_FLAGS} /O2 /Zi /MD /MP /arch:SSE /fp:fast"
|
||||||
@@ -220,14 +220,17 @@ if (LINUX)
|
|||||||
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_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")
|
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")
|
else (${ARCH} STREQUAL "x86_64")
|
||||||
set(CMAKE_CXX_FLAGS_RELEASESSE2 "${CMAKE_CXX_FLAGS_RELEASESSE2} -march=pentium4 -mfpmath=sse -msse2 ${GCC_EXTRA_OPTIMIZATIONS}")
|
if (NOT STANDALONE)
|
||||||
set(CMAKE_C_FLAGS_RELEASESSE2 "${CMAKE_C_FLAGS_RELEASESSE2} -march=pentium4 -mfpmath=sse -msse2 "${GCC_EXTRA_OPTIMIZATIONS})
|
set(MARCH_FLAG " -march=pentium4")
|
||||||
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} -march=pentium4 -mfpmath=sse -msse2 ${GCC_EXTRA_OPTIMIZATIONS}")
|
endif (NOT STANDALONE)
|
||||||
set(CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO} -march=pentium4 -mfpmath=sse -msse2 "${GCC_EXTRA_OPTIMIZATIONS})
|
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 (${ARCH} STREQUAL "x86_64")
|
||||||
endif (VIEWER)
|
endif (VIEWER)
|
||||||
|
|
||||||
set(CMAKE_CXX_FLAGS_DEBUG "-fno-inline ${CMAKE_CXX_FLAGS_DEBUG}")
|
set(CMAKE_CXX_FLAGS_DEBUG "-fno-inline ${CMAKE_CXX_FLAGS_DEBUG} -msse2")
|
||||||
set(CMAKE_CXX_FLAGS_RELEASE "-O3 ${CMAKE_CXX_FLAGS_RELEASE}")
|
set(CMAKE_CXX_FLAGS_RELEASE "-O3 ${CMAKE_CXX_FLAGS_RELEASE}")
|
||||||
set(CMAKE_C_FLAGS_RELEASE "-O3 ${CMAKE_C_FLAGS_RELEASE}")
|
set(CMAKE_C_FLAGS_RELEASE "-O3 ${CMAKE_C_FLAGS_RELEASE}")
|
||||||
set(CMAKE_CXX_FLAGS_RELEASESSE2 "-O3 ${CMAKE_CXX_FLAGS_RELEASESSE2}")
|
set(CMAKE_CXX_FLAGS_RELEASESSE2 "-O3 ${CMAKE_CXX_FLAGS_RELEASESSE2}")
|
||||||
@@ -245,8 +248,8 @@ if (DARWIN)
|
|||||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mlong-branch")
|
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mlong-branch")
|
||||||
# NOTE: it's critical that the optimization flag is put in front.
|
# NOTE: it's critical that the optimization flag is put in front.
|
||||||
# NOTE: it's critical to have both CXX_FLAGS and C_FLAGS covered.
|
# NOTE: it's critical to have both CXX_FLAGS and C_FLAGS covered.
|
||||||
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-O0 ${CMAKE_CXX_FLAGS_RELWITHDEBINFO}")
|
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} -O3 -msse3 -mtune=generic -mfpmath=sse ${GCC_EXTRA_OPTIMIZATIONS}")
|
||||||
set(CMAKE_C_FLAGS_RELWITHDEBINFO "-O0 ${CMAKE_C_FLAGS_RELWITHDEBINFO}")
|
set(CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO} -03 -msse3 -mtune=generic -mfpmath=sse ${GCC_EXTRA_OPTIMIZATIONS}")
|
||||||
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O3 -msse3 -mtune=generic -mfpmath=sse ${GCC_EXTRA_OPTIMIZATIONS}")
|
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O3 -msse3 -mtune=generic -mfpmath=sse ${GCC_EXTRA_OPTIMIZATIONS}")
|
||||||
set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -03 -msse3 -mtune=generic -mfpmath=sse ${GCC_EXTRA_OPTIMIZATIONS}")
|
set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -03 -msse3 -mtune=generic -mfpmath=sse ${GCC_EXTRA_OPTIMIZATIONS}")
|
||||||
set(CMAKE_CXX_FLAGS_RELEASESSE2 "${CMAKE_CXX_FLAGS_RELEASESSE2} -O3 -msse2 -mtune=generic -mfpmath=sse ${GCC_EXTRA_OPTIMIZATIONS}")
|
set(CMAKE_CXX_FLAGS_RELEASESSE2 "${CMAKE_CXX_FLAGS_RELEASESSE2} -O3 -msse2 -mtune=generic -mfpmath=sse ${GCC_EXTRA_OPTIMIZATIONS}")
|
||||||
@@ -278,11 +281,6 @@ endif (LINUX OR DARWIN)
|
|||||||
|
|
||||||
if (STANDALONE)
|
if (STANDALONE)
|
||||||
add_definitions(-DLL_STANDALONE=1)
|
add_definitions(-DLL_STANDALONE=1)
|
||||||
|
|
||||||
if (LINUX AND ${ARCH} STREQUAL "i686")
|
|
||||||
add_definitions(-march=pentiumpro)
|
|
||||||
endif (LINUX AND ${ARCH} STREQUAL "i686")
|
|
||||||
|
|
||||||
else (STANDALONE)
|
else (STANDALONE)
|
||||||
set(${ARCH}_linux_INCLUDES
|
set(${ARCH}_linux_INCLUDES
|
||||||
ELFIO
|
ELFIO
|
||||||
@@ -297,6 +295,7 @@ endif (STANDALONE)
|
|||||||
|
|
||||||
if(1 EQUAL 1)
|
if(1 EQUAL 1)
|
||||||
add_definitions(-DOPENSIM_RULES=1)
|
add_definitions(-DOPENSIM_RULES=1)
|
||||||
|
add_definitions(-DMESH_ENABLED=1)
|
||||||
endif(1 EQUAL 1)
|
endif(1 EQUAL 1)
|
||||||
|
|
||||||
if(SERVER)
|
if(SERVER)
|
||||||
|
|||||||
@@ -43,6 +43,7 @@ endif (NOT FMOD_LIBRARY)
|
|||||||
|
|
||||||
find_path(FMOD_INCLUDE_DIR fmod.h
|
find_path(FMOD_INCLUDE_DIR fmod.h
|
||||||
${LIBS_PREBUILT_DIR}/include
|
${LIBS_PREBUILT_DIR}/include
|
||||||
|
${LIBS_PREBUILT_DIR}/${LL_ARCH_DIR}/include
|
||||||
${FMOD_SDK_DIR}/api/inc
|
${FMOD_SDK_DIR}/api/inc
|
||||||
${FMOD_SDK_DIR}/inc
|
${FMOD_SDK_DIR}/inc
|
||||||
${FMOD_SDK_DIR}
|
${FMOD_SDK_DIR}
|
||||||
|
|||||||
@@ -24,11 +24,11 @@ else (STANDALONE)
|
|||||||
endif (LINUX)
|
endif (LINUX)
|
||||||
endif (STANDALONE)
|
endif (STANDALONE)
|
||||||
|
|
||||||
if (GOOGLE_PERFTOOLS_FOUND)
|
if (GOOGLE_PERFTOOLS_FOUND AND STANDALONE)
|
||||||
set(USE_GOOGLE_PERFTOOLS ON CACHE BOOL "Build with Google PerfTools support.")
|
set(USE_GOOGLE_PERFTOOLS ON CACHE BOOL "Build with Google PerfTools support.")
|
||||||
else (GOOGLE_PERFTOOLS_FOUND)
|
else ()
|
||||||
set(USE_GOOGLE_PERFTOOLS OFF)
|
set(USE_GOOGLE_PERFTOOLS OFF)
|
||||||
endif (GOOGLE_PERFTOOLS_FOUND)
|
endif ()
|
||||||
|
|
||||||
# XXX Disable temporarily, until we have compilation issues on 64-bit
|
# XXX Disable temporarily, until we have compilation issues on 64-bit
|
||||||
# Etch sorted.
|
# Etch sorted.
|
||||||
|
|||||||
@@ -5,6 +5,12 @@ include(Boost)
|
|||||||
include(EXPAT)
|
include(EXPAT)
|
||||||
include(ZLIB)
|
include(ZLIB)
|
||||||
|
|
||||||
|
if (DARWIN)
|
||||||
|
include(CMakeFindFrameworks)
|
||||||
|
find_library(CORESERVICES_LIBRARY CoreServices)
|
||||||
|
endif (DARWIN)
|
||||||
|
|
||||||
|
|
||||||
set(LLCOMMON_INCLUDE_DIRS
|
set(LLCOMMON_INCLUDE_DIRS
|
||||||
${LIBS_OPEN_DIR}/cwdebug
|
${LIBS_OPEN_DIR}/cwdebug
|
||||||
${LIBS_OPEN_DIR}/llcommon
|
${LIBS_OPEN_DIR}/llcommon
|
||||||
@@ -13,3 +19,8 @@ set(LLCOMMON_INCLUDE_DIRS
|
|||||||
)
|
)
|
||||||
|
|
||||||
set(LLCOMMON_LIBRARIES llcommon)
|
set(LLCOMMON_LIBRARIES llcommon)
|
||||||
|
|
||||||
|
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)
|
||||||
|
|||||||
@@ -2,9 +2,9 @@
|
|||||||
include(Prebuilt)
|
include(Prebuilt)
|
||||||
|
|
||||||
if (NOT STANDALONE)
|
if (NOT STANDALONE)
|
||||||
use_prebuilt_binary(GL)
|
use_prebuilt_binary(glext)
|
||||||
# possible glh_linear should have its own .cmake file instead
|
# possible glh_linear should have its own .cmake file instead
|
||||||
#use_prebuilt_binary(glh_linear)
|
#use_prebuilt_binary(glh_linear)
|
||||||
# actually... not any longer, it's now in git -SG
|
# actually... not any longer, it's now in git -SG
|
||||||
set(GLEXT_INCLUDE_DIR ${LIBS_PREBUILT_DIR}/${LL_ARCH_DIR}/include)
|
set(GLEXT_INCLUDE_DIR ${LIBS_PREBUILT_DIR}/include)
|
||||||
endif (NOT STANDALONE)
|
endif (NOT STANDALONE)
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ set(LIBS_SERVER_DIR ${CMAKE_SOURCE_DIR}/${LIBS_SERVER_PREFIX})
|
|||||||
set(SCRIPTS_DIR ${CMAKE_SOURCE_DIR}/${SCRIPTS_PREFIX})
|
set(SCRIPTS_DIR ${CMAKE_SOURCE_DIR}/${SCRIPTS_PREFIX})
|
||||||
set(SERVER_DIR ${CMAKE_SOURCE_DIR}/${SERVER_PREFIX})
|
set(SERVER_DIR ${CMAKE_SOURCE_DIR}/${SERVER_PREFIX})
|
||||||
set(VIEWER_DIR ${CMAKE_SOURCE_DIR}/${VIEWER_PREFIX})
|
set(VIEWER_DIR ${CMAKE_SOURCE_DIR}/${VIEWER_PREFIX})
|
||||||
set(LL_TESTS ON CACHE BOOL "Build and run unit and integration tests (disable for build timing runs to reduce variation)")
|
set(LL_TESTS OFF CACHE BOOL "Build and run unit and integration tests (disable for build timing runs to reduce variation)")
|
||||||
set(VISTA_ICON OFF CACHE BOOL "Allow vista icon with pre 2008 Visual Studio IDEs. (Assumes replacement old rcdll.dll with new rcdll.dll from win sdk 7.0 or later)")
|
set(VISTA_ICON OFF CACHE BOOL "Allow vista icon with pre 2008 Visual Studio IDEs. (Assumes replacement old rcdll.dll with new rcdll.dll from win sdk 7.0 or later)")
|
||||||
|
|
||||||
set(LIBS_PREBUILT_DIR ${CMAKE_SOURCE_DIR}/../libraries CACHE PATH
|
set(LIBS_PREBUILT_DIR ${CMAKE_SOURCE_DIR}/../libraries CACHE PATH
|
||||||
|
|||||||
Binary file not shown.
@@ -89,7 +89,7 @@ S32 check_for_invalid_wav_formats(const std::string& in_fname, std::string& erro
|
|||||||
|
|
||||||
//********************************
|
//********************************
|
||||||
LLAPRFile infile ;
|
LLAPRFile infile ;
|
||||||
infile.open(in_fname,LL_APR_RB, LLAPRFile::global);
|
infile.open(in_fname,LL_APR_RB);
|
||||||
//********************************
|
//********************************
|
||||||
if (!infile.getFileHandle())
|
if (!infile.getFileHandle())
|
||||||
{
|
{
|
||||||
@@ -240,7 +240,7 @@ S32 encode_vorbis_file(const std::string& in_fname, const std::string& out_fname
|
|||||||
S32 data_left = 0;
|
S32 data_left = 0;
|
||||||
|
|
||||||
LLAPRFile infile ;
|
LLAPRFile infile ;
|
||||||
infile.open(in_fname,LL_APR_RB, LLAPRFile::global);
|
infile.open(in_fname,LL_APR_RB);
|
||||||
if (!infile.getFileHandle())
|
if (!infile.getFileHandle())
|
||||||
{
|
{
|
||||||
llwarns << "Couldn't open temporary ogg file for writing: " << in_fname
|
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 ;
|
LLAPRFile outfile ;
|
||||||
outfile.open(out_fname,LL_APR_WPB, LLAPRFile::global);
|
outfile.open(out_fname,LL_APR_WPB);
|
||||||
if (!outfile.getFileHandle())
|
if (!outfile.getFileHandle())
|
||||||
{
|
{
|
||||||
llwarns << "Couldn't open upload sound file for reading: " << in_fname
|
llwarns << "Couldn't open upload sound file for reading: " << in_fname
|
||||||
|
|||||||
@@ -226,7 +226,7 @@ ELoadStatus LLBVHLoader::loadTranslationTable(const char *fileName)
|
|||||||
std::string path = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS,fileName);
|
std::string path = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS,fileName);
|
||||||
|
|
||||||
LLAPRFile infile ;
|
LLAPRFile infile ;
|
||||||
infile.open(path, LL_APR_R, LLAPRFile::global);
|
infile.open(path, LL_APR_R);
|
||||||
apr_file_t *fp = infile.getFileHandle();
|
apr_file_t *fp = infile.getFileHandle();
|
||||||
if (!fp)
|
if (!fp)
|
||||||
return E_ST_NO_XLT_FILE;
|
return E_ST_NO_XLT_FILE;
|
||||||
|
|||||||
@@ -45,7 +45,7 @@
|
|||||||
LLStringTable LLCharacter::sVisualParamNames(1024);
|
LLStringTable LLCharacter::sVisualParamNames(1024);
|
||||||
|
|
||||||
std::vector< LLCharacter* > LLCharacter::sInstances;
|
std::vector< LLCharacter* > LLCharacter::sInstances;
|
||||||
|
BOOL LLCharacter::sAllowInstancesChange = TRUE ;
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
// LLCharacter()
|
// LLCharacter()
|
||||||
@@ -59,8 +59,10 @@ LLCharacter::LLCharacter()
|
|||||||
mSkeletonSerialNum( 0 ),
|
mSkeletonSerialNum( 0 ),
|
||||||
mInAppearance( false )
|
mInAppearance( false )
|
||||||
{
|
{
|
||||||
mMotionController.setCharacter( this );
|
llassert_always(sAllowInstancesChange) ;
|
||||||
sInstances.push_back(this);
|
sInstances.push_back(this);
|
||||||
|
|
||||||
|
mMotionController.setCharacter( this );
|
||||||
mPauseRequest = new LLPauseRequestHandle();
|
mPauseRequest = new LLPauseRequestHandle();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -77,11 +79,22 @@ LLCharacter::~LLCharacter()
|
|||||||
{
|
{
|
||||||
delete param;
|
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 "llmotioncontroller.h"
|
||||||
#include "llvisualparam.h"
|
#include "llvisualparam.h"
|
||||||
#include "string_table.h"
|
#include "string_table.h"
|
||||||
#include "llmemory.h"
|
#include "llpointer.h"
|
||||||
#include "llthread.h"
|
#include "llthread.h"
|
||||||
|
|
||||||
class LLPolyMesh;
|
class LLPolyMesh;
|
||||||
@@ -279,6 +279,7 @@ public:
|
|||||||
void setSkeletonSerialNum( U32 num ) { mSkeletonSerialNum = num; }
|
void setSkeletonSerialNum( U32 num ) { mSkeletonSerialNum = num; }
|
||||||
|
|
||||||
static std::vector< LLCharacter* > sInstances;
|
static std::vector< LLCharacter* > sInstances;
|
||||||
|
static BOOL sAllowInstancesChange ; //debug use
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
LLMotionController mMotionController;
|
LLMotionController mMotionController;
|
||||||
|
|||||||
@@ -56,6 +56,9 @@ LLJoint::LLJoint()
|
|||||||
mUpdateXform = TRUE;
|
mUpdateXform = TRUE;
|
||||||
mJointNum = -1;
|
mJointNum = -1;
|
||||||
touch();
|
touch();
|
||||||
|
#if MESH_ENABLED
|
||||||
|
mResetAfterRestoreOldXform = false;
|
||||||
|
#endif //MESH_ENABLED
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -239,6 +242,43 @@ void LLJoint::setPosition( const LLVector3& pos )
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if MESH_ENABLED
|
||||||
|
//--------------------------------------------------------------------
|
||||||
|
// 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() );
|
||||||
|
}
|
||||||
|
#endif //MESH_ENABLED
|
||||||
|
|
||||||
//--------------------------------------------------------------------
|
//--------------------------------------------------------------------
|
||||||
// getWorldPosition()
|
// getWorldPosition()
|
||||||
|
|||||||
@@ -86,10 +86,19 @@ protected:
|
|||||||
|
|
||||||
// explicit transformation members
|
// explicit transformation members
|
||||||
LLXformMatrix mXform;
|
LLXformMatrix mXform;
|
||||||
|
#if MESH_ENABLED
|
||||||
|
LLXformMatrix mOldXform;
|
||||||
|
LLXformMatrix mDefaultXform;
|
||||||
|
|
||||||
|
LLUUID mId;
|
||||||
|
#endif //MESH_ENABLED
|
||||||
public:
|
public:
|
||||||
U32 mDirtyFlags;
|
U32 mDirtyFlags;
|
||||||
BOOL mUpdateXform;
|
BOOL mUpdateXform;
|
||||||
|
|
||||||
|
#if MESH_ENABLED
|
||||||
|
BOOL mResetAfterRestoreOldXform;
|
||||||
|
#endif //MESH_ENABLED
|
||||||
|
|
||||||
// describes the skin binding pose
|
// describes the skin binding pose
|
||||||
LLVector3 mSkinOffset;
|
LLVector3 mSkinOffset;
|
||||||
@@ -179,6 +188,24 @@ public:
|
|||||||
S32 getJointNum() const { return mJointNum; }
|
S32 getJointNum() const { return mJointNum; }
|
||||||
void setJointNum(S32 joint_num) { mJointNum = joint_num; }
|
void setJointNum(S32 joint_num) { mJointNum = joint_num; }
|
||||||
|
|
||||||
|
#if MESH_ENABLED
|
||||||
|
|
||||||
|
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; }
|
||||||
|
#endif //MESH_ENABLED
|
||||||
|
|
||||||
// <edit>
|
// <edit>
|
||||||
std::string exportString(U32 tabs = 0);
|
std::string exportString(U32 tabs = 0);
|
||||||
// </edit>
|
// </edit>
|
||||||
|
|||||||
@@ -37,7 +37,7 @@
|
|||||||
// Header Files
|
// Header Files
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
#include "lljoint.h"
|
#include "lljoint.h"
|
||||||
#include "llmemory.h"
|
#include "llrefcount.h"
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
// class LLJointState
|
// class LLJointState
|
||||||
|
|||||||
@@ -89,6 +89,7 @@ LLJointState *LLPose::getNextJointState()
|
|||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
BOOL LLPose::addJointState(const LLPointer<LLJointState>& jointState)
|
BOOL LLPose::addJointState(const LLPointer<LLJointState>& jointState)
|
||||||
{
|
{
|
||||||
|
llassert_always(jointState.notNull());
|
||||||
if (mJointMap.find(jointState->getJoint()->getName()) == mJointMap.end())
|
if (mJointMap.find(jointState->getJoint()->getName()) == mJointMap.end())
|
||||||
{
|
{
|
||||||
mJointMap[jointState->getJoint()->getName()] = jointState;
|
mJointMap[jointState->getJoint()->getName()] = jointState;
|
||||||
@@ -161,6 +162,7 @@ void LLPose::setWeight(F32 weight)
|
|||||||
// <edit>
|
// <edit>
|
||||||
// there was a crash here
|
// there was a crash here
|
||||||
// </edit>
|
// </edit>
|
||||||
|
llassert_always(iter->second.notNull());
|
||||||
iter->second->setWeight(weight);
|
iter->second->setWeight(weight);
|
||||||
}
|
}
|
||||||
mWeight = weight;
|
mWeight = weight;
|
||||||
|
|||||||
@@ -40,6 +40,8 @@
|
|||||||
#include "lljointstate.h"
|
#include "lljointstate.h"
|
||||||
#include "lljoint.h"
|
#include "lljoint.h"
|
||||||
#include "llmap.h"
|
#include "llmap.h"
|
||||||
|
#include "llpointer.h"
|
||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
|||||||
@@ -211,7 +211,7 @@ LLFSMState* LLStateDiagram::getState(U32 state_id)
|
|||||||
BOOL LLStateDiagram::saveDotFile(const std::string& filename)
|
BOOL LLStateDiagram::saveDotFile(const std::string& filename)
|
||||||
{
|
{
|
||||||
LLAPRFile outfile ;
|
LLAPRFile outfile ;
|
||||||
outfile.open(filename, LL_APR_W, LLAPRFile::global);
|
outfile.open(filename, LL_APR_W);
|
||||||
apr_file_t* dot_file = outfile.getFileHandle() ;
|
apr_file_t* dot_file = outfile.getFileHandle() ;
|
||||||
|
|
||||||
if (!dot_file)
|
if (!dot_file)
|
||||||
|
|||||||
@@ -58,12 +58,14 @@ set(llcommon_SOURCE_FILES
|
|||||||
llprocessor.cpp
|
llprocessor.cpp
|
||||||
llqueuedthread.cpp
|
llqueuedthread.cpp
|
||||||
llrand.cpp
|
llrand.cpp
|
||||||
|
llrefcount.cpp
|
||||||
llrun.cpp
|
llrun.cpp
|
||||||
llsd.cpp
|
llsd.cpp
|
||||||
llsdserialize.cpp
|
llsdserialize.cpp
|
||||||
llsdserialize_xml.cpp
|
llsdserialize_xml.cpp
|
||||||
llsdutil.cpp
|
llsdutil.cpp
|
||||||
llsecondlifeurls.cpp
|
llsecondlifeurls.cpp
|
||||||
|
llsingleton.cpp
|
||||||
llstat.cpp
|
llstat.cpp
|
||||||
llstacktrace.cpp
|
llstacktrace.cpp
|
||||||
llstreamtools.cpp
|
llstreamtools.cpp
|
||||||
@@ -94,6 +96,7 @@ set(llcommon_HEADER_FILES
|
|||||||
indra_constants.h
|
indra_constants.h
|
||||||
linden_common.h
|
linden_common.h
|
||||||
linked_lists.h
|
linked_lists.h
|
||||||
|
llaccountingcost.h
|
||||||
llagentconstants.h
|
llagentconstants.h
|
||||||
llavatarname.h
|
llavatarname.h
|
||||||
llapp.h
|
llapp.h
|
||||||
@@ -159,6 +162,7 @@ set(llcommon_HEADER_FILES
|
|||||||
llmortician.h
|
llmortician.h
|
||||||
llnametable.h
|
llnametable.h
|
||||||
lloptioninterface.h
|
lloptioninterface.h
|
||||||
|
llpointer.h
|
||||||
llpreprocessor.h
|
llpreprocessor.h
|
||||||
llpriqueuemap.h
|
llpriqueuemap.h
|
||||||
llprocesslauncher.h
|
llprocesslauncher.h
|
||||||
@@ -168,6 +172,8 @@ set(llcommon_HEADER_FILES
|
|||||||
llqueuedthread.h
|
llqueuedthread.h
|
||||||
llrand.h
|
llrand.h
|
||||||
llrun.h
|
llrun.h
|
||||||
|
llrefcount.h
|
||||||
|
llsafehandle.h
|
||||||
llscopedvolatileaprpool.h
|
llscopedvolatileaprpool.h
|
||||||
llsd.h
|
llsd.h
|
||||||
llsdserialize.h
|
llsdserialize.h
|
||||||
@@ -175,6 +181,7 @@ set(llcommon_HEADER_FILES
|
|||||||
llsdutil.h
|
llsdutil.h
|
||||||
llsecondlifeurls.h
|
llsecondlifeurls.h
|
||||||
llsimplehash.h
|
llsimplehash.h
|
||||||
|
llsingleton.h
|
||||||
llskiplist.h
|
llskiplist.h
|
||||||
llskipmap.h
|
llskipmap.h
|
||||||
llstack.h
|
llstack.h
|
||||||
@@ -189,6 +196,7 @@ set(llcommon_HEADER_FILES
|
|||||||
llsys.h
|
llsys.h
|
||||||
llthread.h
|
llthread.h
|
||||||
lltimer.h
|
lltimer.h
|
||||||
|
lltreeiterators.h
|
||||||
lluri.h
|
lluri.h
|
||||||
lluuid.h
|
lluuid.h
|
||||||
lluuidhashmap.h
|
lluuidhashmap.h
|
||||||
@@ -205,6 +213,7 @@ set(llcommon_HEADER_FILES
|
|||||||
stdenums.h
|
stdenums.h
|
||||||
stdtypes.h
|
stdtypes.h
|
||||||
string_table.h
|
string_table.h
|
||||||
|
stringize.h
|
||||||
timer.h
|
timer.h
|
||||||
timing.h
|
timing.h
|
||||||
u64.h
|
u64.h
|
||||||
@@ -224,7 +233,9 @@ target_link_libraries(
|
|||||||
${EXPAT_LIBRARIES}
|
${EXPAT_LIBRARIES}
|
||||||
${ZLIB_LIBRARIES}
|
${ZLIB_LIBRARIES}
|
||||||
${WINDOWS_LIBRARIES}
|
${WINDOWS_LIBRARIES}
|
||||||
|
${BOOST_REGEX_LIBRARY}
|
||||||
${CWDEBUG_LIBRARIES}
|
${CWDEBUG_LIBRARIES}
|
||||||
|
${CORESERVICES_LIBRARY}
|
||||||
)
|
)
|
||||||
|
|
||||||
if (LINUX)
|
if (LINUX)
|
||||||
|
|||||||
@@ -153,6 +153,11 @@ const char LAND_LAYER_CODE = 'L';
|
|||||||
const char WATER_LAYER_CODE = 'W';
|
const char WATER_LAYER_CODE = 'W';
|
||||||
const char WIND_LAYER_CODE = '7';
|
const char WIND_LAYER_CODE = '7';
|
||||||
const char CLOUD_LAYER_CODE = '8';
|
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
|
// keys
|
||||||
// Bit masks for various keyboard modifier keys.
|
// Bit masks for various keyboard modifier keys.
|
||||||
|
|||||||
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
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -249,15 +249,6 @@ LLSD LLApp::getOptionData(OptionPriority level)
|
|||||||
return mOptions[level];
|
return mOptions[level];
|
||||||
}
|
}
|
||||||
|
|
||||||
void LLApp::stepFrame()
|
|
||||||
{
|
|
||||||
LLFrameTimer::updateFrameTime();
|
|
||||||
LLFrameTimer::updateFrameCount();
|
|
||||||
LLEventTimer::updateClass();
|
|
||||||
mRunner.run();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void LLApp::setupErrorHandling()
|
void LLApp::setupErrorHandling()
|
||||||
{
|
{
|
||||||
// Error handling is done by starting up an error handling thread, which just sleeps and
|
// Error handling is done by starting up an error handling thread, which just sleeps and
|
||||||
@@ -297,10 +288,13 @@ void LLApp::startErrorThread()
|
|||||||
// Start the error handling thread, which is responsible for taking action
|
// Start the error handling thread, which is responsible for taking action
|
||||||
// when the app goes into the APP_STATUS_ERROR state
|
// when the app goes into the APP_STATUS_ERROR state
|
||||||
//
|
//
|
||||||
llinfos << "Starting error thread" << llendl;
|
if(!mThreadErrorp)
|
||||||
mThreadErrorp = new LLErrorThread();
|
{
|
||||||
mThreadErrorp->setUserData((void *) this);
|
llinfos << "Starting error thread" << llendl;
|
||||||
mThreadErrorp->start();
|
mThreadErrorp = new LLErrorThread();
|
||||||
|
mThreadErrorp->setUserData((void *) this);
|
||||||
|
mThreadErrorp->start();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void LLApp::setErrorHandler(LLAppErrorHandler handler)
|
void LLApp::setErrorHandler(LLAppErrorHandler handler)
|
||||||
|
|||||||
@@ -236,17 +236,6 @@ public:
|
|||||||
pid_t fork();
|
pid_t fork();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Get a reference to the application runner
|
|
||||||
*
|
|
||||||
* Please use the runner with caution. Since the Runner usage
|
|
||||||
* pattern is not yet clear, this method just gives access to it
|
|
||||||
* to add and remove runnables.
|
|
||||||
* @return Returns the application runner. Do not save the
|
|
||||||
* pointer past the caller's stack frame.
|
|
||||||
*/
|
|
||||||
LLRunner& getRunner() { return mRunner; }
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
typedef std::map<std::string, std::string> string_map;
|
typedef std::map<std::string, std::string> string_map;
|
||||||
string_map mOptionMap; // Contains all command-line options and arguments in a map
|
string_map mOptionMap; // Contains all command-line options and arguments in a map
|
||||||
@@ -264,11 +253,6 @@ protected:
|
|||||||
static LLAppChildCallback sDefaultChildCallback;
|
static LLAppChildCallback sDefaultChildCallback;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief This method is called once a frame to do once a frame tasks.
|
|
||||||
*/
|
|
||||||
void stepFrame();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @ brief This method is called once as soon as logging is initialized.
|
* @ brief This method is called once as soon as logging is initialized.
|
||||||
*/
|
*/
|
||||||
@@ -289,9 +273,6 @@ private:
|
|||||||
// Default application threads
|
// Default application threads
|
||||||
LLErrorThread* mThreadErrorp; // Waits for app to go to status ERROR, then runs the error callback
|
LLErrorThread* mThreadErrorp; // Waits for app to go to status ERROR, then runs the error callback
|
||||||
|
|
||||||
// This is the application level runnable scheduler.
|
|
||||||
LLRunner mRunner;
|
|
||||||
|
|
||||||
/** @name Runtime option implementation */
|
/** @name Runtime option implementation */
|
||||||
//@{
|
//@{
|
||||||
|
|
||||||
|
|||||||
@@ -191,6 +191,10 @@ apr_status_t LLAPRFile::open(std::string const& filename, apr_int32_t flags, acc
|
|||||||
return status;
|
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::global : LLAPRFile::local);
|
||||||
|
}
|
||||||
// File I/O
|
// File I/O
|
||||||
S32 LLAPRFile::read(void *buf, S32 nbytes)
|
S32 LLAPRFile::read(void *buf, S32 nbytes)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -150,10 +150,11 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
LLAPRFile() ;
|
LLAPRFile() ;
|
||||||
LLAPRFile(const std::string& filename, apr_int32_t flags, access_t access_type);
|
LLAPRFile(const std::string& filename, apr_int32_t flags, access_t access_type = LLAPRFile::global);
|
||||||
~LLAPRFile() ;
|
~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 = LLAPRFile::global, 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() ;
|
apr_status_t close() ;
|
||||||
|
|
||||||
// Returns actual offset, -1 if seek fails
|
// Returns actual offset, -1 if seek fails
|
||||||
|
|||||||
@@ -35,6 +35,7 @@
|
|||||||
#include "llassettype.h"
|
#include "llassettype.h"
|
||||||
#include "lldictionary.h"
|
#include "lldictionary.h"
|
||||||
#include "llmemory.h"
|
#include "llmemory.h"
|
||||||
|
#include "llsingleton.h"
|
||||||
|
|
||||||
///----------------------------------------------------------------------------
|
///----------------------------------------------------------------------------
|
||||||
/// Class LLAssetType
|
/// Class LLAssetType
|
||||||
@@ -105,6 +106,9 @@ LLAssetDictionary::LLAssetDictionary()
|
|||||||
//addEntry(LLAssetType::AT_CURRENT_OUTFIT, new AssetEntry("FOLDER_LINK", "current", "current outfit", false, false, false));
|
//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_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_MY_OUTFITS, new AssetEntry("MY_OUTFITS", "my_otfts", "my outfits", false, false, false));
|
||||||
|
#if MESH_ENABLED
|
||||||
|
addEntry(LLAssetType::AT_MESH, new AssetEntry("MESH", "mesh", "mesh", false, false, false));
|
||||||
|
#endif //MESH_ENABLED
|
||||||
addEntry(LLAssetType::AT_NONE, new AssetEntry("NONE", "-1", NULL, false, false, false));
|
addEntry(LLAssetType::AT_NONE, new AssetEntry("NONE", "-1", NULL, false, false, false));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -138,13 +138,19 @@ public:
|
|||||||
|
|
||||||
// Inventory folder link
|
// Inventory folder link
|
||||||
AT_LINK_FOLDER = 25,
|
AT_LINK_FOLDER = 25,
|
||||||
|
|
||||||
//AT_CURRENT_OUTFIT = 46,
|
//AT_CURRENT_OUTFIT = 46,
|
||||||
|
|
||||||
//AT_OUTFIT = 47,
|
//AT_OUTFIT = 47,
|
||||||
|
|
||||||
//AT_MY_OUTFITS = 48,
|
//AT_MY_OUTFITS = 48,
|
||||||
|
|
||||||
|
#if MESH_ENABLED
|
||||||
|
AT_MESH = 49,
|
||||||
|
// Mesh data in our proprietary SLM format
|
||||||
|
|
||||||
|
AT_COUNT = 50,
|
||||||
|
#endif //MESH_ENABLED
|
||||||
// +*********************************************+
|
// +*********************************************+
|
||||||
// | TO ADD AN ELEMENT TO THIS ENUM: |
|
// | TO ADD AN ELEMENT TO THIS ENUM: |
|
||||||
// +*********************************************+
|
// +*********************************************+
|
||||||
@@ -155,8 +161,9 @@ public:
|
|||||||
// +*********************************************+
|
// +*********************************************+
|
||||||
|
|
||||||
//AT_COUNT = 49,
|
//AT_COUNT = 49,
|
||||||
|
#if !MESH_ENABLED
|
||||||
AT_COUNT = 26,
|
AT_COUNT = 26,
|
||||||
|
#endif //!MESH_ENABLED
|
||||||
AT_NONE = -1
|
AT_NONE = -1
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -38,6 +38,8 @@
|
|||||||
#include <iosfwd>
|
#include <iosfwd>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
#include "llpreprocessor.h"
|
||||||
|
|
||||||
#include "stdtypes.h"
|
#include "stdtypes.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -44,63 +44,40 @@
|
|||||||
//
|
//
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
//std::list<LLEventTimer*> LLEventTimer::sActiveList;
|
|
||||||
|
|
||||||
LLEventTimer::LLEventTimer(F32 period)
|
LLEventTimer::LLEventTimer(F32 period)
|
||||||
: mEventTimer()
|
: mEventTimer()
|
||||||
{
|
{
|
||||||
mPeriod = period;
|
mPeriod = period;
|
||||||
//sActiveList.push_back(this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
LLEventTimer::LLEventTimer(const LLDate& time)
|
LLEventTimer::LLEventTimer(const LLDate& time)
|
||||||
: mEventTimer()
|
: mEventTimer()
|
||||||
{
|
{
|
||||||
mPeriod = (F32)(time.secondsSinceEpoch() - LLDate::now().secondsSinceEpoch());
|
mPeriod = (F32)(time.secondsSinceEpoch() - LLDate::now().secondsSinceEpoch());
|
||||||
//sActiveList.push_back(this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
LLEventTimer::~LLEventTimer()
|
LLEventTimer::~LLEventTimer()
|
||||||
{
|
{
|
||||||
//sActiveList.remove(this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//static
|
//static
|
||||||
void LLEventTimer::updateClass()
|
void LLEventTimer::updateClass()
|
||||||
{
|
{
|
||||||
std::list<LLEventTimer*> completed_timers;
|
std::list<LLEventTimer*> completed_timers;
|
||||||
|
for (instance_iter iter = beginInstances(); iter != endInstances(); )
|
||||||
/*{
|
|
||||||
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 );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}*/
|
|
||||||
{
|
{
|
||||||
LLInstanceTrackerScopedGuard guard;
|
LLEventTimer& timer = *iter++;
|
||||||
for (instance_iter iter = guard.beginInstances(); iter != guard.endInstances(); )
|
F32 et = timer.mEventTimer.getElapsedTimeF32();
|
||||||
{
|
if (timer.mEventTimer.getStarted() && et > timer.mPeriod) {
|
||||||
LLEventTimer& timer = *iter++;
|
timer.mEventTimer.reset();
|
||||||
F32 et = timer.mEventTimer.getElapsedTimeF32();
|
if ( timer.tick() )
|
||||||
if (timer.mEventTimer.getStarted() && et > timer.mPeriod) {
|
{
|
||||||
timer.mEventTimer.reset();
|
completed_timers.push_back( &timer );
|
||||||
if ( timer.tick() )
|
|
||||||
{
|
|
||||||
completed_timers.push_back( &timer );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( completed_timers.size() > 0 )
|
if ( completed_timers.size() > 0 )
|
||||||
{
|
{
|
||||||
for (std::list<LLEventTimer*>::iterator completed_iter = completed_timers.begin();
|
for (std::list<LLEventTimer*>::iterator completed_iter = completed_timers.begin();
|
||||||
|
|||||||
@@ -56,11 +56,6 @@ public:
|
|||||||
protected:
|
protected:
|
||||||
LLTimer mEventTimer;
|
LLTimer mEventTimer;
|
||||||
F32 mPeriod;
|
F32 mPeriod;
|
||||||
|
|
||||||
//private:
|
|
||||||
//list of active timers
|
|
||||||
// static std::list<LLEventTimer*> sActiveList; // TODO should this be a vector
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
#endif //LL_EVENTTIMER_H
|
#endif //LL_EVENTTIMER_H
|
||||||
|
|||||||
@@ -29,33 +29,22 @@
|
|||||||
* COMPLETENESS OR PERFORMANCE.
|
* COMPLETENESS OR PERFORMANCE.
|
||||||
* $/LicenseInfo$
|
* $/LicenseInfo$
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "linden_common.h"
|
#include "linden_common.h"
|
||||||
|
|
||||||
#include "llfasttimer.h"
|
#include "llfasttimer.h"
|
||||||
|
|
||||||
#include "llmemory.h"
|
#include "llmemory.h"
|
||||||
#include "llprocessor.h"
|
#include "llprocessor.h"
|
||||||
|
|
||||||
|
|
||||||
#if LL_WINDOWS
|
#if LL_WINDOWS
|
||||||
#define WIN32_LEAN_AND_MEAN
|
#define WIN32_LEAN_AND_MEAN
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#include "lltimer.h"
|
|
||||||
#elif LL_LINUX || LL_SOLARIS
|
|
||||||
#include <sys/time.h>
|
|
||||||
#include <sched.h>
|
|
||||||
#include "lltimer.h"
|
|
||||||
#elif LL_DARWIN
|
|
||||||
#include <sys/time.h>
|
|
||||||
#include "lltimer.h" // get_clock_count()
|
|
||||||
#else
|
|
||||||
#error "architecture not supported"
|
|
||||||
#endif
|
#endif
|
||||||
|
#include "lltimer.h"
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
// statics
|
// statics
|
||||||
|
|
||||||
|
|
||||||
LLFastTimer::EFastTimerType LLFastTimer::sCurType = LLFastTimer::FTM_OTHER;
|
LLFastTimer::EFastTimerType LLFastTimer::sCurType = LLFastTimer::FTM_OTHER;
|
||||||
int LLFastTimer::sCurDepth = 0;
|
int LLFastTimer::sCurDepth = 0;
|
||||||
U64 LLFastTimer::sStart[LLFastTimer::FTM_MAX_DEPTH];
|
U64 LLFastTimer::sStart[LLFastTimer::FTM_MAX_DEPTH];
|
||||||
@@ -70,44 +59,12 @@ S32 LLFastTimer::sLastFrameIndex = -1;
|
|||||||
int LLFastTimer::sPauseHistory = 0;
|
int LLFastTimer::sPauseHistory = 0;
|
||||||
int LLFastTimer::sResetHistory = 0;
|
int LLFastTimer::sResetHistory = 0;
|
||||||
|
|
||||||
#define USE_RDTSC 0
|
U64 LLFastTimer::sClockResolution = calc_clock_frequency(50U); // Resolution of get_clock_count()
|
||||||
|
|
||||||
#if LL_LINUX || LL_SOLARIS
|
|
||||||
U64 LLFastTimer::sClockResolution = 1000000000; // 1e9, Nanosecond resolution
|
|
||||||
#else
|
|
||||||
U64 LLFastTimer::sClockResolution = 1000000; // 1e6, Microsecond resolution
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
//static
|
|
||||||
#if (LL_DARWIN || LL_LINUX || LL_SOLARIS) && !(defined(__i386__) || defined(__amd64__))
|
|
||||||
U64 LLFastTimer::countsPerSecond() // counts per second for the *32-bit* timer
|
U64 LLFastTimer::countsPerSecond() // counts per second for the *32-bit* timer
|
||||||
{
|
{
|
||||||
return sClockResolution >> 8;
|
return sClockResolution >> 8;
|
||||||
}
|
}
|
||||||
#else // windows or x86-mac or x86-linux or x86-solaris
|
|
||||||
U64 LLFastTimer::countsPerSecond() // counts per second for the *32-bit* timer
|
|
||||||
{
|
|
||||||
#if USE_RDTSC || !LL_WINDOWS
|
|
||||||
//getCPUFrequency returns MHz and sCPUClockFrequency wants to be in Hz
|
|
||||||
static U64 sCPUClockFrequency = U64(LLProcessorInfo().getCPUFrequency()*1000000.0);
|
|
||||||
|
|
||||||
// we drop the low-order byte in our timers, so report a lower frequency
|
|
||||||
#else
|
|
||||||
// If we're not using RDTSC, each fasttimer tick is just a performance counter tick.
|
|
||||||
// Not redefining the clock frequency itself (in llprocessor.cpp/calculate_cpu_frequency())
|
|
||||||
// since that would change displayed MHz stats for CPUs
|
|
||||||
static bool firstcall = true;
|
|
||||||
static U64 sCPUClockFrequency;
|
|
||||||
if (firstcall)
|
|
||||||
{
|
|
||||||
QueryPerformanceFrequency((LARGE_INTEGER*)&sCPUClockFrequency);
|
|
||||||
firstcall = false;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
return sCPUClockFrequency >> 8;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
void LLFastTimer::reset()
|
void LLFastTimer::reset()
|
||||||
{
|
{
|
||||||
@@ -162,139 +119,17 @@ void LLFastTimer::reset()
|
|||||||
// Important note: These implementations must be FAST!
|
// Important note: These implementations must be FAST!
|
||||||
//
|
//
|
||||||
|
|
||||||
|
|
||||||
#if LL_WINDOWS
|
|
||||||
//
|
|
||||||
// Windows implementation of CPU clock
|
|
||||||
//
|
|
||||||
|
|
||||||
//
|
|
||||||
// NOTE: put back in when we aren't using platform sdk anymore
|
|
||||||
//
|
|
||||||
// because MS has different signatures for these functions in winnt.h
|
|
||||||
// need to rename them to avoid conflicts
|
|
||||||
//#define _interlockedbittestandset _renamed_interlockedbittestandset
|
|
||||||
//#define _interlockedbittestandreset _renamed_interlockedbittestandreset
|
|
||||||
//#include <intrin.h>
|
|
||||||
//#undef _interlockedbittestandset
|
|
||||||
//#undef _interlockedbittestandreset
|
|
||||||
|
|
||||||
//inline U32 LLFastTimer::getCPUClockCount32()
|
|
||||||
//{
|
|
||||||
// U64 time_stamp = __rdtsc();
|
|
||||||
// return (U32)(time_stamp >> 8);
|
|
||||||
//}
|
|
||||||
//
|
|
||||||
//// return full timer value, *not* shifted by 8 bits
|
|
||||||
//inline U64 LLFastTimer::getCPUClockCount64()
|
|
||||||
//{
|
|
||||||
// return __rdtsc();
|
|
||||||
//}
|
|
||||||
|
|
||||||
// shift off lower 8 bits for lower resolution but longer term timing
|
// shift off lower 8 bits for lower resolution but longer term timing
|
||||||
// on 1Ghz machine, a 32-bit word will hold ~1000 seconds of timing
|
// on 1Ghz machine, a 32-bit word will hold ~1000 seconds of timing
|
||||||
#if USE_RDTSC
|
|
||||||
U32 LLFastTimer::getCPUClockCount32()
|
|
||||||
{
|
|
||||||
U32 ret_val;
|
|
||||||
__asm
|
|
||||||
{
|
|
||||||
_emit 0x0f
|
|
||||||
_emit 0x31
|
|
||||||
shr eax,8
|
|
||||||
shl edx,24
|
|
||||||
or eax, edx
|
|
||||||
mov dword ptr [ret_val], eax
|
|
||||||
}
|
|
||||||
return ret_val;
|
|
||||||
}
|
|
||||||
|
|
||||||
// return full timer value, *not* shifted by 8 bits
|
|
||||||
U64 LLFastTimer::getCPUClockCount64()
|
|
||||||
{
|
|
||||||
U64 ret_val;
|
|
||||||
__asm
|
|
||||||
{
|
|
||||||
_emit 0x0f
|
|
||||||
_emit 0x31
|
|
||||||
mov eax,eax
|
|
||||||
mov edx,edx
|
|
||||||
mov dword ptr [ret_val+4], edx
|
|
||||||
mov dword ptr [ret_val], eax
|
|
||||||
}
|
|
||||||
return ret_val;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string LLFastTimer::sClockType = "rdtsc";
|
|
||||||
|
|
||||||
#else
|
|
||||||
//LL_COMMON_API U64 get_clock_count(); // in lltimer.cpp
|
//LL_COMMON_API U64 get_clock_count(); // in lltimer.cpp
|
||||||
// These use QueryPerformanceCounter, which is arguably fine and also works on amd architectures.
|
// On windows these use QueryPerformanceCounter, which is arguably fine and also works on amd architectures.
|
||||||
U32 LLFastTimer::getCPUClockCount32()
|
U32 LLFastTimer::getCPUClockCount32()
|
||||||
{
|
{
|
||||||
return (U32)(get_clock_count()>>8);
|
return get_clock_count() >> 8;
|
||||||
}
|
}
|
||||||
|
|
||||||
U64 LLFastTimer::getCPUClockCount64()
|
U64 LLFastTimer::getCPUClockCount64()
|
||||||
{
|
{
|
||||||
return get_clock_count();
|
return get_clock_count();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string LLFastTimer::sClockType = "QueryPerformanceCounter";
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
#if (LL_LINUX || LL_SOLARIS) && !(defined(__i386__) || defined(__amd64__))
|
|
||||||
//
|
|
||||||
// Linux and Solaris implementation of CPU clock - non-x86.
|
|
||||||
// This is accurate but SLOW! Only use out of desperation.
|
|
||||||
//
|
|
||||||
// Try to use the MONOTONIC clock if available, this is a constant time counter
|
|
||||||
// with nanosecond resolution (but not necessarily accuracy) and attempts are
|
|
||||||
// made to synchronize this value between cores at kernel start. It should not
|
|
||||||
// be affected by CPU frequency. If not available use the REALTIME clock, but
|
|
||||||
// this may be affected by NTP adjustments or other user activity affecting
|
|
||||||
// the system time.
|
|
||||||
U64 LLFastTimer::getCPUClockCount64()
|
|
||||||
{
|
|
||||||
struct timespec tp;
|
|
||||||
|
|
||||||
#ifdef CLOCK_MONOTONIC // MONOTONIC supported at build-time?
|
|
||||||
if (-1 == clock_gettime(CLOCK_MONOTONIC,&tp)) // if MONOTONIC isn't supported at runtime then ouch, try REALTIME
|
|
||||||
#endif
|
|
||||||
clock_gettime(CLOCK_REALTIME,&tp);
|
|
||||||
|
|
||||||
return (tp.tv_sec*LLFastTimer::sClockResolution)+tp.tv_nsec;
|
|
||||||
}
|
|
||||||
|
|
||||||
U32 LLFastTimer::getCPUClockCount32()
|
|
||||||
{
|
|
||||||
return (U32)(LLFastTimer::getCPUClockCount64() >> 8);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string LLFastTimer::sClockType = "clock_gettime";
|
|
||||||
|
|
||||||
#endif // (LL_LINUX || LL_SOLARIS) && !(defined(__i386__) || defined(__amd64__))
|
|
||||||
|
|
||||||
|
|
||||||
#if (LL_LINUX || LL_SOLARIS || LL_DARWIN) && (defined(__i386__) || defined(__amd64__))
|
|
||||||
//
|
|
||||||
// Mac+Linux+Solaris FAST x86 implementation of CPU clock
|
|
||||||
U32 LLFastTimer::getCPUClockCount32()
|
|
||||||
{
|
|
||||||
U64 x;
|
|
||||||
__asm__ volatile (".byte 0x0f, 0x31": "=A"(x));
|
|
||||||
return (U32)(x >> 8);
|
|
||||||
}
|
|
||||||
|
|
||||||
U64 LLFastTimer::getCPUClockCount64()
|
|
||||||
{
|
|
||||||
U64 x;
|
|
||||||
__asm__ volatile (".byte 0x0f, 0x31": "=A"(x));
|
|
||||||
return x;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string LLFastTimer::sClockType = "rdtsc";
|
|
||||||
#endif
|
|
||||||
@@ -72,7 +72,12 @@ public:
|
|||||||
FTM_UPDATE_GRASS,
|
FTM_UPDATE_GRASS,
|
||||||
FTM_UPDATE_TREE,
|
FTM_UPDATE_TREE,
|
||||||
FTM_UPDATE_AVATAR,
|
FTM_UPDATE_AVATAR,
|
||||||
|
#if MESH_ENABLED
|
||||||
|
FTM_UPDATE_RIGGED_VOLUME,
|
||||||
|
FTM_SKIN_RIGGED,
|
||||||
|
FTM_RIGGED_OCTREE,
|
||||||
|
#endif //MESH_ENABLED
|
||||||
|
|
||||||
// common render components
|
// common render components
|
||||||
FTM_SHADOW_GEOMETRY,
|
FTM_SHADOW_GEOMETRY,
|
||||||
FTM_SHADOW_RENDER,
|
FTM_SHADOW_RENDER,
|
||||||
@@ -131,6 +136,12 @@ public:
|
|||||||
FTM_STATESORT,
|
FTM_STATESORT,
|
||||||
FTM_STATESORT_DRAWABLE,
|
FTM_STATESORT_DRAWABLE,
|
||||||
FTM_STATESORT_POSTSORT,
|
FTM_STATESORT_POSTSORT,
|
||||||
|
#if MESH_ENABLED
|
||||||
|
FTM_MESH_UPDATE,
|
||||||
|
FTM_MESH_LOCK1,
|
||||||
|
FTM_MESH_LOCK2,
|
||||||
|
FTM_LOAD_MESH_LOD,
|
||||||
|
#endif //MESH_ENABLED
|
||||||
FTM_REBUILD_VBO,
|
FTM_REBUILD_VBO,
|
||||||
FTM_REBUILD_VOLUME_VB,
|
FTM_REBUILD_VOLUME_VB,
|
||||||
FTM_REBUILD_BRIDGE_VB,
|
FTM_REBUILD_BRIDGE_VB,
|
||||||
@@ -256,7 +267,6 @@ public:
|
|||||||
static void reset();
|
static void reset();
|
||||||
static U64 countsPerSecond();
|
static U64 countsPerSecond();
|
||||||
|
|
||||||
static std::string sClockType;
|
|
||||||
public:
|
public:
|
||||||
static int sCurDepth;
|
static int sCurDepth;
|
||||||
static U64 sStart[FTM_MAX_DEPTH];
|
static U64 sStart[FTM_MAX_DEPTH];
|
||||||
|
|||||||
@@ -36,6 +36,7 @@
|
|||||||
#include "llfoldertype.h"
|
#include "llfoldertype.h"
|
||||||
#include "lldictionary.h"
|
#include "lldictionary.h"
|
||||||
#include "llmemory.h"
|
#include "llmemory.h"
|
||||||
|
#include "llsingleton.h"
|
||||||
|
|
||||||
///----------------------------------------------------------------------------
|
///----------------------------------------------------------------------------
|
||||||
/// Class LLFolderType
|
/// Class LLFolderType
|
||||||
@@ -95,7 +96,12 @@ LLFolderDictionary::LLFolderDictionary()
|
|||||||
addEntry(LLFolderType::FT_CURRENT_OUTFIT, new FolderEntry("current", TRUE));
|
addEntry(LLFolderType::FT_CURRENT_OUTFIT, new FolderEntry("current", TRUE));
|
||||||
addEntry(LLFolderType::FT_OUTFIT, new FolderEntry("outfit", FALSE));
|
addEntry(LLFolderType::FT_OUTFIT, new FolderEntry("outfit", FALSE));
|
||||||
addEntry(LLFolderType::FT_MY_OUTFITS, new FolderEntry("my_otfts", TRUE));
|
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_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));
|
addEntry(LLFolderType::FT_NONE, new FolderEntry("-1", FALSE));
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -87,9 +87,14 @@ public:
|
|||||||
FT_OUTFIT = 47,
|
FT_OUTFIT = 47,
|
||||||
FT_MY_OUTFITS = 48,
|
FT_MY_OUTFITS = 48,
|
||||||
|
|
||||||
FT_INBOX = 49,
|
FT_MESH = 49,
|
||||||
|
|
||||||
FT_COUNT = 50,
|
FT_INBOX = 50,
|
||||||
|
FT_OUTBOX = 51,
|
||||||
|
|
||||||
|
FT_BASIC_ROOT = 52,
|
||||||
|
|
||||||
|
FT_COUNT,
|
||||||
|
|
||||||
FT_NONE = -1
|
FT_NONE = -1
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
* $LicenseInfo:firstyear=2002&license=viewergpl$
|
* $LicenseInfo:firstyear=2002&license=viewergpl$
|
||||||
*
|
*
|
||||||
* Copyright (c) 2002-2009, Linden Research, Inc.
|
* Copyright (c) 2002-2009, Linden Research, Inc.
|
||||||
|
* Copyright (c) 2011, Aleric Inglewood.
|
||||||
*
|
*
|
||||||
* Second Life Viewer Source Code
|
* Second Life Viewer Source Code
|
||||||
* The source code in this file ("Source Code") is provided by Linden Lab
|
* The source code in this file ("Source Code") is provided by Linden Lab
|
||||||
@@ -35,48 +36,55 @@
|
|||||||
|
|
||||||
#include "llframetimer.h"
|
#include "llframetimer.h"
|
||||||
|
|
||||||
|
// Local constants.
|
||||||
|
static F64 const USEC_PER_SECOND = 1000000.0;
|
||||||
|
static F64 const USEC_TO_SEC_F64 = 0.000001;
|
||||||
|
|
||||||
// Static members
|
// Static members
|
||||||
//LLTimer LLFrameTimer::sInternalTimer;
|
U64 const LLFrameTimer::sStartTotalTime = totalTime(); // Application start in microseconds since epoch.
|
||||||
U64 LLFrameTimer::sStartTotalTime = totalTime();
|
U64 LLFrameTimer::sTotalTime = LLFrameTimer::sStartTotalTime; // Current time in microseconds since epoch, updated at least once per frame.
|
||||||
F64 LLFrameTimer::sFrameTime = 0.0;
|
F64 LLFrameTimer::sTotalSeconds = // Current time in seconds since epoch, updated together with LLFrameTimer::sTotalTime.
|
||||||
U64 LLFrameTimer::sTotalTime = 0;
|
U64_to_F64(LLFrameTimer::sTotalTime) * USEC_TO_SEC_F64;
|
||||||
F64 LLFrameTimer::sTotalSeconds = 0.0;
|
F64 LLFrameTimer::sFrameTime = 0.0; // Current time in seconds since application start, updated together with LLFrameTimer::sTotalTime.
|
||||||
S32 LLFrameTimer::sFrameCount = 0;
|
// Updated exactly once per frame:
|
||||||
U64 LLFrameTimer::sFrameDeltaTime = 0;
|
S32 LLFrameTimer::sFrameCount = 0; // Current frame number (number of frames since application start).
|
||||||
const F64 USEC_PER_SECOND = 1000000.0;
|
U64 LLFrameTimer::sPrevTotalTime = LLFrameTimer::sStartTotalTime; // Previous (frame) time in microseconds since epoch, updated once per frame.
|
||||||
const F64 USEC_TO_SEC_F64 = 0.000001;
|
U64 LLFrameTimer::sFrameDeltaTime = 0; // Microseconds between last two calls to LLFrameTimer::updateFrameTimeAndCount.
|
||||||
|
|
||||||
// static
|
// static
|
||||||
void LLFrameTimer::updateFrameTime()
|
void LLFrameTimer::updateFrameTime()
|
||||||
{
|
{
|
||||||
U64 total_time = totalTime();
|
sTotalTime = totalTime();
|
||||||
sFrameDeltaTime = total_time - sTotalTime;
|
|
||||||
sTotalTime = total_time;
|
|
||||||
sTotalSeconds = U64_to_F64(sTotalTime) * USEC_TO_SEC_F64;
|
sTotalSeconds = U64_to_F64(sTotalTime) * USEC_TO_SEC_F64;
|
||||||
sFrameTime = U64_to_F64(sTotalTime - sStartTotalTime) * USEC_TO_SEC_F64;
|
sFrameTime = U64_to_F64(sTotalTime - sStartTotalTime) * USEC_TO_SEC_F64;
|
||||||
}
|
}
|
||||||
|
|
||||||
void LLFrameTimer::start()
|
// static
|
||||||
|
void LLFrameTimer::updateFrameTimeAndCount()
|
||||||
{
|
{
|
||||||
reset();
|
updateFrameTime();
|
||||||
mStarted = TRUE;
|
sFrameDeltaTime = sTotalTime - sPrevTotalTime;
|
||||||
|
sPrevTotalTime = sTotalTime;
|
||||||
|
++sFrameCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
void LLFrameTimer::reset(F32 expiration)
|
||||||
|
{
|
||||||
|
llassert(!mPaused);
|
||||||
|
mStartTime = sFrameTime;
|
||||||
|
mExpiry = sFrameTime + expiration;
|
||||||
|
}
|
||||||
|
|
||||||
|
void LLFrameTimer::start(F32 expiration)
|
||||||
|
{
|
||||||
|
reset(expiration);
|
||||||
|
mRunning = true; // Start, if not already started.
|
||||||
}
|
}
|
||||||
|
|
||||||
void LLFrameTimer::stop()
|
void LLFrameTimer::stop()
|
||||||
{
|
{
|
||||||
mStarted = FALSE;
|
llassert(!mPaused);
|
||||||
}
|
mRunning = false;
|
||||||
|
|
||||||
void LLFrameTimer::reset()
|
|
||||||
{
|
|
||||||
mStartTime = sFrameTime;
|
|
||||||
mExpiry = sFrameTime;
|
|
||||||
}
|
|
||||||
|
|
||||||
void LLFrameTimer::resetWithExpiry(F32 expiration)
|
|
||||||
{
|
|
||||||
reset();
|
|
||||||
setTimerExpirySec(expiration);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Don't combine pause/unpause with start/stop
|
// Don't combine pause/unpause with start/stop
|
||||||
@@ -89,25 +97,31 @@ void LLFrameTimer::resetWithExpiry(F32 expiration)
|
|||||||
// Note: elapsed would also be valid with no unpause() call (= time run until pause() called)
|
// Note: elapsed would also be valid with no unpause() call (= time run until pause() called)
|
||||||
void LLFrameTimer::pause()
|
void LLFrameTimer::pause()
|
||||||
{
|
{
|
||||||
if (mStarted)
|
if (!mPaused)
|
||||||
mStartTime = sFrameTime - mStartTime; // save dtime
|
{
|
||||||
mStarted = FALSE;
|
mStartTime = sFrameTime - mStartTime; // Abuse mStartTime to store the elapsed time so far.
|
||||||
|
}
|
||||||
|
mPaused = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void LLFrameTimer::unpause()
|
void LLFrameTimer::unpause()
|
||||||
{
|
{
|
||||||
if (!mStarted)
|
if (mPaused)
|
||||||
mStartTime = sFrameTime - mStartTime; // restore dtime
|
{
|
||||||
mStarted = TRUE;
|
mStartTime = sFrameTime - mStartTime; // Set mStartTime consistent with the elapsed time so far.
|
||||||
|
}
|
||||||
|
mPaused = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void LLFrameTimer::setTimerExpirySec(F32 expiration)
|
void LLFrameTimer::setTimerExpirySec(F32 expiration)
|
||||||
{
|
{
|
||||||
mExpiry = expiration + mStartTime;
|
llassert(!mPaused);
|
||||||
|
mExpiry = mStartTime + expiration;
|
||||||
}
|
}
|
||||||
|
|
||||||
void LLFrameTimer::setExpiryAt(F64 seconds_since_epoch)
|
void LLFrameTimer::setExpiryAt(F64 seconds_since_epoch)
|
||||||
{
|
{
|
||||||
|
llassert(!mPaused);
|
||||||
mStartTime = sFrameTime;
|
mStartTime = sFrameTime;
|
||||||
mExpiry = seconds_since_epoch - (USEC_TO_SEC_F64 * sStartTotalTime);
|
mExpiry = seconds_since_epoch - (USEC_TO_SEC_F64 * sStartTotalTime);
|
||||||
}
|
}
|
||||||
@@ -119,20 +133,14 @@ F64 LLFrameTimer::expiresAt() const
|
|||||||
return expires_at;
|
return expires_at;
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOL LLFrameTimer::checkExpirationAndReset(F32 expiration)
|
bool LLFrameTimer::checkExpirationAndReset(F32 expiration)
|
||||||
{
|
{
|
||||||
//llinfos << "LLFrameTimer::checkExpirationAndReset()" << llendl;
|
if (hasExpired())
|
||||||
//llinfos << " mStartTime:" << mStartTime << llendl;
|
|
||||||
//llinfos << " sFrameTime:" << sFrameTime << llendl;
|
|
||||||
//llinfos << " mExpiry: " << mExpiry << llendl;
|
|
||||||
|
|
||||||
if(hasExpired())
|
|
||||||
{
|
{
|
||||||
reset();
|
reset(expiration);
|
||||||
setTimerExpirySec(expiration);
|
return true;
|
||||||
return TRUE;
|
|
||||||
}
|
}
|
||||||
return FALSE;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// static
|
// static
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
* $LicenseInfo:firstyear=2002&license=viewergpl$
|
* $LicenseInfo:firstyear=2002&license=viewergpl$
|
||||||
*
|
*
|
||||||
* Copyright (c) 2002-2009, Linden Research, Inc.
|
* Copyright (c) 2002-2009, Linden Research, Inc.
|
||||||
|
* Copyright (c) 2011, Aleric Inglewood.
|
||||||
*
|
*
|
||||||
* Second Life Viewer Source Code
|
* Second Life Viewer Source Code
|
||||||
* The source code in this file ("Source Code") is provided by Linden Lab
|
* The source code in this file ("Source Code") is provided by Linden Lab
|
||||||
@@ -37,7 +38,7 @@
|
|||||||
/**
|
/**
|
||||||
* *NOTE: Because of limitations on linux which we do not really have
|
* *NOTE: Because of limitations on linux which we do not really have
|
||||||
* time to explore, the total time is derived from the frame time
|
* time to explore, the total time is derived from the frame time
|
||||||
* and is recsynchronized on every frame.
|
* and is resynchronized on every frame.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "lltimer.h"
|
#include "lltimer.h"
|
||||||
@@ -46,61 +47,64 @@
|
|||||||
class LL_COMMON_API LLFrameTimer
|
class LL_COMMON_API LLFrameTimer
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
LLFrameTimer() : mStartTime( sFrameTime ), mExpiry(0), mStarted(TRUE) {}
|
// Create an LLFrameTimer and start it. After creation it is running and in the state expired (hasExpired will return true).
|
||||||
|
LLFrameTimer(void) : mStartTime(sFrameTime), mExpiry(0), mRunning(true), mPaused(false) { }
|
||||||
|
|
||||||
// Return the number of seconds since the start of this
|
// Return the number of seconds since the start of the application.
|
||||||
// application instance.
|
|
||||||
static F64 getElapsedSeconds()
|
static F64 getElapsedSeconds()
|
||||||
{
|
{
|
||||||
// Loses msec precision after ~4.5 hours...
|
// Loses msec precision after ~4.5 hours...
|
||||||
return sFrameTime;
|
return sFrameTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return a low precision usec since epoch
|
// Return a low precision usec since epoch.
|
||||||
static U64 getTotalTime()
|
static U64 getTotalTime()
|
||||||
{
|
{
|
||||||
return sTotalTime ? sTotalTime : totalTime();
|
llassert(sTotalTime);
|
||||||
|
return sTotalTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return a low precision seconds since epoch
|
// Return a low precision seconds since epoch.
|
||||||
static F64 getTotalSeconds()
|
static F64 getTotalSeconds()
|
||||||
{
|
{
|
||||||
return sTotalSeconds;
|
return sTotalSeconds;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Call this method once per frame to update the current frame time. This is actually called
|
// Call this method once per frame to update the current frame time.
|
||||||
// at some other times as well
|
// This is actually called at some other times as well.
|
||||||
static void updateFrameTime();
|
static void updateFrameTime();
|
||||||
|
|
||||||
// Call this method once, and only once, per frame to update the current frame count.
|
// Call this method once, and only once, per frame to update the current frame count and sFrameDeltaTime.
|
||||||
static void updateFrameCount() { sFrameCount++; }
|
static void updateFrameTimeAndCount();
|
||||||
|
|
||||||
static U32 getFrameCount() { return sFrameCount; }
|
// Return current frame number (the number of frames since application start).
|
||||||
|
static U32 getFrameCount() { return sFrameCount; }
|
||||||
|
|
||||||
static F32 getFrameDeltaTimeF32();
|
// Return duration of last frame in seconds.
|
||||||
|
static F32 getFrameDeltaTimeF32();
|
||||||
|
|
||||||
// Return seconds since the current frame started
|
// Return seconds since the current frame started
|
||||||
static F32 getCurrentFrameTime();
|
static F32 getCurrentFrameTime();
|
||||||
|
|
||||||
// MANIPULATORS
|
// MANIPULATORS
|
||||||
void start();
|
|
||||||
void stop();
|
void reset(F32 expiration = 0.f); // Same as start() but leaves mRunning off when called after stop().
|
||||||
void reset();
|
void start(F32 expiration = 0.f); // Reset and (re)start with expiration.
|
||||||
void resetWithExpiry(F32 expiration);
|
void stop(); // Stop running.
|
||||||
void pause();
|
|
||||||
void unpause();
|
void pause(); // Mark elapsed time so far.
|
||||||
|
void unpause(); // Move 'start' time in order to decrement time between pause and unpause from ElapsedTime.
|
||||||
|
|
||||||
void setTimerExpirySec(F32 expiration);
|
void setTimerExpirySec(F32 expiration);
|
||||||
void setExpiryAt(F64 seconds_since_epoch);
|
void setExpiryAt(F64 seconds_since_epoch);
|
||||||
BOOL checkExpirationAndReset(F32 expiration);
|
bool checkExpirationAndReset(F32 expiration); // Returns true when expired. Only resets if expired.
|
||||||
F32 getElapsedTimeAndResetF32() { F32 t = F32(sFrameTime - mStartTime); reset(); return t; }
|
F32 getElapsedTimeAndResetF32() { F32 t = getElapsedTimeF32(); reset(); return t; }
|
||||||
|
void setAge(const F64 age) { llassert(!mPaused); mStartTime = sFrameTime - age; }
|
||||||
void setAge(const F64 age) { mStartTime = sFrameTime - age; }
|
|
||||||
|
|
||||||
// ACCESSORS
|
// ACCESSORS
|
||||||
BOOL hasExpired() const { return (sFrameTime >= mExpiry); }
|
bool hasExpired() const { return sFrameTime >= mExpiry; }
|
||||||
F32 getTimeToExpireF32() const { return (F32)(mExpiry - sFrameTime); }
|
F32 getElapsedTimeF32() const { llassert(mRunning); return mPaused ? (F32)mStartTime : (F32)(sFrameTime - mStartTime); }
|
||||||
F32 getElapsedTimeF32() const { return mStarted ? (F32)(sFrameTime - mStartTime) : (F32)mStartTime; }
|
bool getStarted() const { return mRunning; }
|
||||||
BOOL getStarted() const { return mStarted; }
|
|
||||||
|
|
||||||
// return the seconds since epoch when this timer will expire.
|
// return the seconds since epoch when this timer will expire.
|
||||||
F64 expiresAt() const;
|
F64 expiresAt() const;
|
||||||
@@ -114,45 +118,52 @@ protected:
|
|||||||
// Aplication constants
|
// Aplication constants
|
||||||
//
|
//
|
||||||
|
|
||||||
// Start time of opp in usec since epoch
|
// Application start in microseconds since epoch.
|
||||||
static U64 sStartTotalTime;
|
static U64 const sStartTotalTime;
|
||||||
|
|
||||||
//
|
//
|
||||||
// Data updated per frame
|
// Data updated per frame
|
||||||
//
|
//
|
||||||
|
|
||||||
// Seconds since application start
|
// Current time in seconds since application start, updated together with sTotalTime.
|
||||||
static F64 sFrameTime;
|
static F64 sFrameTime;
|
||||||
|
|
||||||
// Time that has elapsed since last call to updateFrameTime()
|
// Microseconds between last two calls to updateFrameTimeAndCount (time between last two frames).
|
||||||
static U64 sFrameDeltaTime;
|
static U64 sFrameDeltaTime;
|
||||||
|
|
||||||
// Total microseconds since epoch.
|
// Current time in microseconds since epoch, updated at least once per frame.
|
||||||
static U64 sTotalTime;
|
static U64 sTotalTime;
|
||||||
|
|
||||||
// Seconds since epoch.
|
// Previous (frame) time in microseconds since epoch, updated once per frame.
|
||||||
|
static U64 sPrevTotalTime;
|
||||||
|
|
||||||
|
// Current time in seconds since epoch, updated together with sTotalTime.
|
||||||
static F64 sTotalSeconds;
|
static F64 sTotalSeconds;
|
||||||
|
|
||||||
// Total number of frames elapsed in application
|
// Current frame number (number of frames since application start).
|
||||||
static S32 sFrameCount;
|
static S32 sFrameCount;
|
||||||
|
|
||||||
//
|
//
|
||||||
// Member data
|
// Member data
|
||||||
//
|
//
|
||||||
|
|
||||||
// Number of seconds after application start when this timer was
|
// When not paused (mPaused is false): number of seconds since application start,
|
||||||
// started. Set equal to sFrameTime when reset.
|
// otherwise this value is equal to the accumulated run time (ElapsedTime).
|
||||||
|
// Set equal to sFrameTime when reset.
|
||||||
F64 mStartTime;
|
F64 mStartTime;
|
||||||
|
|
||||||
// Timer expires this many seconds after application start time.
|
// Timer expires when sFrameTime reaches this value (in seconds since application start).
|
||||||
F64 mExpiry;
|
F64 mExpiry;
|
||||||
|
|
||||||
// Useful bit of state usually associated with timers, but does
|
// True when running, merely a boolean return by getStarted(). The timer always runs.
|
||||||
// not affect actual functionality
|
bool mRunning;
|
||||||
BOOL mStarted;
|
|
||||||
|
// True when accumulating ElapsedTime. If false mStartTime has a different meaning
|
||||||
|
// and really unpause() should be called before anything else.
|
||||||
|
bool mPaused;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Glue code for Havok (or anything else that doesn't want the full .h files)
|
// Glue code for Havok (or anything else that doesn't want the full .h files)
|
||||||
extern F32 getCurrentFrameTime();
|
extern F32 getCurrentFrameTime();
|
||||||
|
|
||||||
#endif // LL_LLFRAMETIMER_H
|
#endif // LL_LLFRAMETIMER_H
|
||||||
|
|||||||
@@ -49,6 +49,7 @@ class LL_COMMON_API LLInstanceTrackerBase : public boost::noncopyable
|
|||||||
protected:
|
protected:
|
||||||
static void * & getInstances(std::type_info const & info);
|
static void * & getInstances(std::type_info const & info);
|
||||||
};
|
};
|
||||||
|
|
||||||
/// This mix-in class adds support for tracking all instances of the specified class parameter T
|
/// 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
|
/// 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
|
/// If KEY is not provided, then instances are stored in a simple set
|
||||||
@@ -58,13 +59,80 @@ class LLInstanceTracker : public LLInstanceTrackerBase
|
|||||||
{
|
{
|
||||||
typedef typename std::map<KEY, T*> InstanceMap;
|
typedef typename std::map<KEY, T*> InstanceMap;
|
||||||
typedef LLInstanceTracker<T, KEY> MyT;
|
typedef LLInstanceTracker<T, KEY> MyT;
|
||||||
typedef boost::function<const KEY&(typename InstanceMap::value_type&)> KeyGetter;
|
|
||||||
typedef boost::function<T*(typename InstanceMap::value_type&)> InstancePtrGetter;
|
|
||||||
public:
|
public:
|
||||||
/// Dereferencing key_iter gives you a const KEY&
|
class instance_iter : public boost::iterator_facade<instance_iter, T, boost::forward_traversal_tag>
|
||||||
typedef boost::transform_iterator<KeyGetter, typename InstanceMap::iterator> key_iter;
|
{
|
||||||
/// Dereferencing instance_iter gives you a T&
|
public:
|
||||||
typedef boost::indirect_iterator< boost::transform_iterator<InstancePtrGetter, typename InstanceMap::iterator> > instance_iter;
|
typedef boost::iterator_facade<instance_iter, T, boost::forward_traversal_tag> super_t;
|
||||||
|
|
||||||
|
instance_iter(const typename InstanceMap::iterator& it)
|
||||||
|
: mIterator(it)
|
||||||
|
{
|
||||||
|
++sIterationNestDepth;
|
||||||
|
}
|
||||||
|
|
||||||
|
~instance_iter()
|
||||||
|
{
|
||||||
|
--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)
|
||||||
|
{
|
||||||
|
++sIterationNestDepth;
|
||||||
|
}
|
||||||
|
|
||||||
|
key_iter(const key_iter& other)
|
||||||
|
: mIterator(other.mIterator)
|
||||||
|
{
|
||||||
|
++sIterationNestDepth;
|
||||||
|
}
|
||||||
|
|
||||||
|
~key_iter()
|
||||||
|
{
|
||||||
|
--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)
|
static T* getInstance(const KEY& k)
|
||||||
{
|
{
|
||||||
@@ -72,42 +140,47 @@ public:
|
|||||||
return (found == getMap_().end()) ? NULL : found->second;
|
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()
|
static key_iter beginKeys()
|
||||||
{
|
{
|
||||||
return boost::make_transform_iterator(getMap_().begin(),
|
return key_iter(getMap_().begin());
|
||||||
boost::bind(&InstanceMap::value_type::first, _1));
|
|
||||||
}
|
}
|
||||||
static key_iter endKeys()
|
static key_iter endKeys()
|
||||||
{
|
{
|
||||||
return boost::make_transform_iterator(getMap_().end(),
|
return key_iter(getMap_().end());
|
||||||
boost::bind(&InstanceMap::value_type::first, _1));
|
|
||||||
}
|
}
|
||||||
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:
|
protected:
|
||||||
LLInstanceTracker(KEY key) { add_(key); }
|
LLInstanceTracker(KEY key) { add_(key); }
|
||||||
virtual ~LLInstanceTracker() { remove_(); }
|
virtual ~LLInstanceTracker()
|
||||||
|
{
|
||||||
|
// it's unsafe to delete instances of this type while all instances are being iterated over.
|
||||||
|
llassert(sIterationNestDepth == 0);
|
||||||
|
remove_();
|
||||||
|
}
|
||||||
virtual void setKey(KEY key) { remove_(); add_(key); }
|
virtual void setKey(KEY key) { remove_(); add_(key); }
|
||||||
virtual const KEY& getKey() const { return mKey; }
|
virtual const KEY& getKey() const { return mInstanceKey; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void add_(KEY key)
|
void add_(KEY key)
|
||||||
{
|
{
|
||||||
mKey = key;
|
mInstanceKey = key;
|
||||||
getMap_()[key] = static_cast<T*>(this);
|
getMap_()[key] = static_cast<T*>(this);
|
||||||
}
|
}
|
||||||
void remove_()
|
void remove_()
|
||||||
{
|
{
|
||||||
getMap_().erase(mKey);
|
getMap_().erase(mInstanceKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
static InstanceMap& getMap_()
|
static InstanceMap& getMap_()
|
||||||
@@ -122,9 +195,12 @@ private:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
KEY mKey;
|
KEY mInstanceKey;
|
||||||
|
static S32 sIterationNestDepth;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <typename T, typename KEY> S32 LLInstanceTracker<T, KEY>::sIterationNestDepth = 0;
|
||||||
|
|
||||||
/// explicit specialization for default case where KEY is T*
|
/// explicit specialization for default case where KEY is T*
|
||||||
/// use a simple std::set<T*>
|
/// use a simple std::set<T*>
|
||||||
template<typename T>
|
template<typename T>
|
||||||
@@ -133,42 +209,55 @@ class LLInstanceTracker<T, T*> : public LLInstanceTrackerBase
|
|||||||
typedef typename std::set<T*> InstanceSet;
|
typedef typename std::set<T*> InstanceSet;
|
||||||
typedef LLInstanceTracker<T, T*> MyT;
|
typedef LLInstanceTracker<T, T*> MyT;
|
||||||
public:
|
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
|
/// for completeness of analogy with the generic implementation
|
||||||
static T* getInstance(T* k) { return k; }
|
static T* getInstance(T* k) { return k; }
|
||||||
static S32 instanceCount() { return getSet_().size(); }
|
static S32 instanceCount() { return getSet_().size(); }
|
||||||
|
|
||||||
// Instantiate this to get access to iterators for this type. It's a 'guard' in the sense
|
class instance_iter : public boost::iterator_facade<instance_iter, T, boost::forward_traversal_tag>
|
||||||
// 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
|
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
LLInstanceTrackerScopedGuard()
|
instance_iter(const typename InstanceSet::iterator& it)
|
||||||
|
: mIterator(it)
|
||||||
{
|
{
|
||||||
++sIterationNestDepth;
|
++sIterationNestDepth;
|
||||||
}
|
}
|
||||||
|
|
||||||
~LLInstanceTrackerScopedGuard()
|
instance_iter(const instance_iter& other)
|
||||||
|
: mIterator(other.mIterator)
|
||||||
|
{
|
||||||
|
++sIterationNestDepth;
|
||||||
|
}
|
||||||
|
|
||||||
|
~instance_iter()
|
||||||
{
|
{
|
||||||
--sIterationNestDepth;
|
--sIterationNestDepth;
|
||||||
}
|
}
|
||||||
|
|
||||||
static instance_iter beginInstances() { return instance_iter(getSet_().begin()); }
|
private:
|
||||||
static instance_iter endInstances() { return instance_iter(getSet_().end()); }
|
friend class boost::iterator_core_access;
|
||||||
static key_iter beginKeys() { return getSet_().begin(); }
|
|
||||||
static key_iter endKeys() { return getSet_().end(); }
|
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:
|
protected:
|
||||||
LLInstanceTracker()
|
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.
|
// 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);
|
|
||||||
getSet_().insert(static_cast<T*>(this));
|
getSet_().insert(static_cast<T*>(this));
|
||||||
}
|
}
|
||||||
virtual ~LLInstanceTracker()
|
virtual ~LLInstanceTracker()
|
||||||
@@ -180,7 +269,6 @@ protected:
|
|||||||
|
|
||||||
LLInstanceTracker(const LLInstanceTracker& other)
|
LLInstanceTracker(const LLInstanceTracker& other)
|
||||||
{
|
{
|
||||||
//llassert(sIterationNestDepth == 0);
|
|
||||||
getSet_().insert(static_cast<T*>(this));
|
getSet_().insert(static_cast<T*>(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -118,6 +118,62 @@ public:
|
|||||||
THROTTLE_BLOCKED, // rate exceed, block key
|
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
|
// call each time the key wants use
|
||||||
State noteAction(const T& id, S32 weight = 1)
|
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_CROUCHING = 0x0400;
|
||||||
const U32 AGENT_BUSY = 0x0800;
|
const U32 AGENT_BUSY = 0x0800;
|
||||||
const U32 AGENT_ALWAYS_RUN = 0x1000;
|
const U32 AGENT_ALWAYS_RUN = 0x1000;
|
||||||
|
const U32 AGENT_AUTOPILOT = 0x2000;
|
||||||
|
|
||||||
const S32 LSL_REMOTE_DATA_CHANNEL = 1;
|
const S32 LSL_REMOTE_DATA_CHANNEL = 1;
|
||||||
const S32 LSL_REMOTE_DATA_REQUEST = 2;
|
const S32 LSL_REMOTE_DATA_REQUEST = 2;
|
||||||
@@ -184,6 +185,10 @@ const S32 OBJECT_VELOCITY = 5;
|
|||||||
const S32 OBJECT_OWNER = 6;
|
const S32 OBJECT_OWNER = 6;
|
||||||
const S32 OBJECT_GROUP = 7;
|
const S32 OBJECT_GROUP = 7;
|
||||||
const S32 OBJECT_CREATOR = 8;
|
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
|
// changed() event flags
|
||||||
const U32 CHANGED_NONE = 0x0;
|
const U32 CHANGED_NONE = 0x0;
|
||||||
@@ -198,5 +203,17 @@ const U32 CHANGED_OWNER = 0x80;
|
|||||||
const U32 CHANGED_REGION = 0x100;
|
const U32 CHANGED_REGION = 0x100;
|
||||||
const U32 CHANGED_TELEPORT = 0x200;
|
const U32 CHANGED_TELEPORT = 0x200;
|
||||||
const U32 CHANGED_REGION_START = 0x400;
|
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
|
#endif
|
||||||
|
|||||||
@@ -276,37 +276,12 @@ void operator delete[] (void *p)
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
LLRefCount::LLRefCount() :
|
|
||||||
mRef(0)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
LLRefCount::LLRefCount(const LLRefCount& other)
|
|
||||||
: mRef(0)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
LLRefCount::~LLRefCount()
|
|
||||||
{
|
|
||||||
if (mRef != 0)
|
|
||||||
{
|
|
||||||
llerrs << "deleting non-zero reference" << llendl;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
LLRefCount& LLRefCount::operator=(const LLRefCount&)
|
|
||||||
{
|
|
||||||
// do nothing, since ref count is specific to *this* reference
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
|
|
||||||
#if defined(LL_WINDOWS)
|
#if defined(LL_WINDOWS)
|
||||||
|
|
||||||
U64 getCurrentRSS()
|
U64 LLMemory::getCurrentRSS()
|
||||||
{
|
{
|
||||||
HANDLE self = GetCurrentProcess();
|
HANDLE self = GetCurrentProcess();
|
||||||
PROCESS_MEMORY_COUNTERS counters;
|
PROCESS_MEMORY_COUNTERS counters;
|
||||||
@@ -320,6 +295,20 @@ U64 getCurrentRSS()
|
|||||||
return counters.WorkingSetSize;
|
return counters.WorkingSetSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//static
|
||||||
|
U32 LLMemory::getWorkingSetSize()
|
||||||
|
{
|
||||||
|
PROCESS_MEMORY_COUNTERS pmc ;
|
||||||
|
U32 ret = 0 ;
|
||||||
|
|
||||||
|
if (GetProcessMemoryInfo( GetCurrentProcess(), &pmc, sizeof(pmc)) )
|
||||||
|
{
|
||||||
|
ret = pmc.WorkingSetSize ;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret ;
|
||||||
|
}
|
||||||
|
|
||||||
#elif defined(LL_DARWIN)
|
#elif defined(LL_DARWIN)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -344,7 +333,7 @@ U64 getCurrentRSS()
|
|||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
|
|
||||||
U64 getCurrentRSS()
|
U64 LLMemory::getCurrentRSS()
|
||||||
{
|
{
|
||||||
U64 residentSize = 0;
|
U64 residentSize = 0;
|
||||||
task_basic_info_data_t basicInfo;
|
task_basic_info_data_t basicInfo;
|
||||||
@@ -366,9 +355,14 @@ U64 getCurrentRSS()
|
|||||||
return residentSize;
|
return residentSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
U32 LLMemory::getWorkingSetSize()
|
||||||
|
{
|
||||||
|
return 0 ;
|
||||||
|
}
|
||||||
|
|
||||||
#elif defined(LL_LINUX)
|
#elif defined(LL_LINUX)
|
||||||
|
|
||||||
U64 getCurrentRSS()
|
U64 LLMemory::getCurrentRSS()
|
||||||
{
|
{
|
||||||
static const char statPath[] = "/proc/self/stat";
|
static const char statPath[] = "/proc/self/stat";
|
||||||
LLFILE *fp = LLFile::fopen(statPath, "r");
|
LLFILE *fp = LLFile::fopen(statPath, "r");
|
||||||
@@ -400,6 +394,10 @@ bail:
|
|||||||
return rss;
|
return rss;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
U32 LLMemory::getWorkingSetSize()
|
||||||
|
{
|
||||||
|
return 0 ;
|
||||||
|
}
|
||||||
#elif LL_SOLARIS
|
#elif LL_SOLARIS
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
@@ -407,7 +405,7 @@ bail:
|
|||||||
#define _STRUCTURED_PROC 1
|
#define _STRUCTURED_PROC 1
|
||||||
#include <sys/procfs.h>
|
#include <sys/procfs.h>
|
||||||
|
|
||||||
U64 getCurrentRSS()
|
U64 LLMemory::getCurrentRSS()
|
||||||
{
|
{
|
||||||
char path [LL_MAX_PATH]; /* Flawfinder: ignore */
|
char path [LL_MAX_PATH]; /* Flawfinder: ignore */
|
||||||
|
|
||||||
@@ -428,11 +426,22 @@ U64 getCurrentRSS()
|
|||||||
|
|
||||||
return((U64)proc_psinfo.pr_rssize * 1024);
|
return((U64)proc_psinfo.pr_rssize * 1024);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
U32 LLMemory::getWorkingSetSize()
|
||||||
|
{
|
||||||
|
return 0 ;
|
||||||
|
}
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
U64 getCurrentRSS()
|
U64 LLMemory::getCurrentRSS()
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
U32 LLMemory::getWorkingSetSize()
|
||||||
|
{
|
||||||
|
return 0 ;
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -29,453 +29,115 @@
|
|||||||
* COMPLETENESS OR PERFORMANCE.
|
* COMPLETENESS OR PERFORMANCE.
|
||||||
* $/LicenseInfo$
|
* $/LicenseInfo$
|
||||||
*/
|
*/
|
||||||
#ifndef LL_MEMORY_H
|
#ifndef LLMEMORY_H
|
||||||
#define LL_MEMORY_H
|
#define LLMEMORY_H
|
||||||
|
|
||||||
|
|
||||||
#include <new>
|
#include <new>
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
|
#if !LL_WINDOWS
|
||||||
|
#include <stdint.h> // uintptr_t
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "llerror.h"
|
#include "llerror.h"
|
||||||
|
|
||||||
extern S32 gTotalDAlloc;
|
|
||||||
extern S32 gTotalDAUse;
|
|
||||||
extern S32 gDACount;
|
|
||||||
|
|
||||||
const U32 LLREFCOUNT_SENTINEL_VALUE = 0xAAAAAAAA;
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#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));
|
||||||
|
|
||||||
|
((void**)aligned)[-1] = mem;
|
||||||
|
return aligned;
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
class LL_COMMON_API LLMemory
|
class LL_COMMON_API LLMemory
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
static void initClass();
|
static void initClass();
|
||||||
static void cleanupClass();
|
static void cleanupClass();
|
||||||
static void freeReserve();
|
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();
|
||||||
private:
|
private:
|
||||||
static char* reserveMem;
|
static char* reserveMem;
|
||||||
};
|
};
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//EVENTUALLY REMOVE THESE:
|
||||||
// RefCount objects should generally only be accessed by way of LLPointer<>'s
|
#include "llpointer.h"
|
||||||
// NOTE: LLPointer<LLFoo> x = new LLFoo(); MAY NOT BE THREAD SAFE
|
#include "llrefcount.h"
|
||||||
// if LLFoo::LLFoo() does anything like put itself in an update queue.
|
#include "llsingleton.h"
|
||||||
// The queue may get accessed before it gets assigned to x.
|
#include "llsafehandle.h"
|
||||||
// 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
|
|
||||||
{
|
|
||||||
protected:
|
|
||||||
LLRefCount(const LLRefCount&);
|
|
||||||
private:
|
|
||||||
LLRefCount&operator=(const LLRefCount&);
|
|
||||||
|
|
||||||
protected:
|
|
||||||
virtual ~LLRefCount(); // use unref()
|
|
||||||
|
|
||||||
public:
|
|
||||||
LLRefCount();
|
|
||||||
|
|
||||||
void ref()
|
|
||||||
{
|
|
||||||
mRef++;
|
|
||||||
}
|
|
||||||
|
|
||||||
S32 unref()
|
|
||||||
{
|
|
||||||
llassert(mRef >= 1);
|
|
||||||
if (0 == --mRef)
|
|
||||||
{
|
|
||||||
delete this;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
return mRef;
|
|
||||||
}
|
|
||||||
|
|
||||||
S32 getNumRefs() const
|
|
||||||
{
|
|
||||||
return mRef;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
S32 mRef;
|
|
||||||
};
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
// 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; }
|
|
||||||
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 )
|
|
||||||
{
|
|
||||||
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;
|
|
||||||
};
|
|
||||||
|
|
||||||
//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
|
|
||||||
{
|
|
||||||
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; }
|
|
||||||
// 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;
|
|
||||||
};
|
|
||||||
|
|
||||||
// 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; }
|
|
||||||
|
|
||||||
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()
|
|
||||||
#else
|
|
||||||
static T* getInstance()
|
|
||||||
#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() {}
|
|
||||||
};
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
// Return the resident set size of the current process, in bytes.
|
|
||||||
// Return value is zero if not known.
|
|
||||||
LL_COMMON_API U64 getCurrentRSS();
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -74,9 +74,3 @@ void LLMortician::setZealous(BOOL b)
|
|||||||
{
|
{
|
||||||
sDestroyImmediate = b;
|
sDestroyImmediate = b;
|
||||||
}
|
}
|
||||||
|
|
||||||
// static
|
|
||||||
BOOL LLMortician::getZealous()
|
|
||||||
{
|
|
||||||
return sDestroyImmediate;
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -46,7 +46,6 @@ public:
|
|||||||
|
|
||||||
// sets destroy immediate true
|
// sets destroy immediate true
|
||||||
static void setZealous(BOOL b);
|
static void setZealous(BOOL b);
|
||||||
static BOOL getZealous();
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static BOOL sDestroyImmediate;
|
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
|
#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)
|
#if defined(LL_WINDOWS)
|
||||||
#define BOOST_REGEX_NO_LIB 1
|
#define BOOST_REGEX_NO_LIB 1
|
||||||
#define CURL_STATICLIB 1
|
#define CURL_STATICLIB 1
|
||||||
@@ -159,12 +169,19 @@
|
|||||||
#define LL_DLLIMPORT
|
#define LL_DLLIMPORT
|
||||||
#endif // LL_WINDOWS
|
#endif // LL_WINDOWS
|
||||||
|
|
||||||
#ifdef llcommon_EXPORTS
|
#if LL_COMMON_LINK_SHARED
|
||||||
// Compiling llcommon (shared)
|
// CMake automagically defines llcommon_EXPORTS only when building llcommon
|
||||||
#define LL_COMMON_API LL_DLLEXPORT
|
// sources, and only when llcommon is a shared library (i.e. when
|
||||||
#else // llcommon_EXPORTS
|
// LL_COMMON_LINK_SHARED). We must still test LL_COMMON_LINK_SHARED because
|
||||||
// Using llcommon (shared)
|
// otherwise we can't distinguish between (non-llcommon source) and (llcommon
|
||||||
#define LL_COMMON_API LL_DLLIMPORT
|
// not shared).
|
||||||
#endif // llcommon_EXPORTS
|
# 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
|
#endif // not LL_LINDEN_PREPROCESSOR_H
|
||||||
|
|||||||
@@ -102,7 +102,7 @@ int LLProcessLauncher::launch(void)
|
|||||||
STARTUPINFOA sinfo;
|
STARTUPINFOA sinfo;
|
||||||
memset(&sinfo, 0, sizeof(sinfo));
|
memset(&sinfo, 0, sizeof(sinfo));
|
||||||
|
|
||||||
std::string args = "\"" + mExecutable + "\"";
|
std::string args = mExecutable;
|
||||||
for(int i = 0; i < (int)mLaunchArguments.size(); i++)
|
for(int i = 0; i < (int)mLaunchArguments.size(); i++)
|
||||||
{
|
{
|
||||||
args += " ";
|
args += " ";
|
||||||
@@ -114,10 +114,30 @@ int LLProcessLauncher::launch(void)
|
|||||||
char *args2 = new char[args.size() + 1];
|
char *args2 = new char[args.size() + 1];
|
||||||
strcpy(args2, args.c_str());
|
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();
|
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)
|
if(result == 0)
|
||||||
{
|
{
|
||||||
// Make absolutely certain we return a non-zero value on failure.
|
// Make absolutely certain we return a non-zero value on failure.
|
||||||
@@ -328,7 +348,11 @@ int LLProcessLauncher::launch(void)
|
|||||||
apr_file_t* out;
|
apr_file_t* out;
|
||||||
AIAPRPool pool;
|
AIAPRPool pool;
|
||||||
pool.create();
|
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());
|
apr_status_t status = apr_file_pipe_create_ex(&in, &out, APR_FULL_BLOCK, pool());
|
||||||
|
#else
|
||||||
|
apr_status_t status = apr_file_pipe_create(&in, &out, pool());
|
||||||
|
#endif
|
||||||
assert(status == APR_SUCCESS);
|
assert(status == APR_SUCCESS);
|
||||||
bool success = (status == APR_SUCCESS);
|
bool success = (status == APR_SUCCESS);
|
||||||
if (success)
|
if (success)
|
||||||
|
|||||||
@@ -31,8 +31,9 @@
|
|||||||
|
|
||||||
#include "linden_common.h"
|
#include "linden_common.h"
|
||||||
#include "llqueuedthread.h"
|
#include "llqueuedthread.h"
|
||||||
|
|
||||||
#include "llstl.h"
|
#include "llstl.h"
|
||||||
#include "lltimer.h"
|
#include "lltimer.h" // ms_sleep()
|
||||||
|
|
||||||
//============================================================================
|
//============================================================================
|
||||||
|
|
||||||
@@ -41,7 +42,8 @@ LLQueuedThread::LLQueuedThread(const std::string& name, bool threaded) :
|
|||||||
LLThread(name),
|
LLThread(name),
|
||||||
mThreaded(threaded),
|
mThreaded(threaded),
|
||||||
mIdleThread(TRUE),
|
mIdleThread(TRUE),
|
||||||
mNextHandle(0)
|
mNextHandle(0),
|
||||||
|
mStarted(FALSE)
|
||||||
{
|
{
|
||||||
if (mThreaded)
|
if (mThreaded)
|
||||||
{
|
{
|
||||||
@@ -52,6 +54,10 @@ LLQueuedThread::LLQueuedThread(const std::string& name, bool threaded) :
|
|||||||
// MAIN THREAD
|
// MAIN THREAD
|
||||||
LLQueuedThread::~LLQueuedThread()
|
LLQueuedThread::~LLQueuedThread()
|
||||||
{
|
{
|
||||||
|
if (!mThreaded)
|
||||||
|
{
|
||||||
|
endThread();
|
||||||
|
}
|
||||||
shutdown();
|
shutdown();
|
||||||
// ~LLThread() will be called here
|
// ~LLThread() will be called here
|
||||||
}
|
}
|
||||||
@@ -90,6 +96,7 @@ void LLQueuedThread::shutdown()
|
|||||||
if (req->getStatus() == STATUS_QUEUED || req->getStatus() == STATUS_INPROGRESS)
|
if (req->getStatus() == STATUS_QUEUED || req->getStatus() == STATUS_INPROGRESS)
|
||||||
{
|
{
|
||||||
++active_count;
|
++active_count;
|
||||||
|
req->setStatus(STATUS_ABORTED); // avoid assert in deleteRequest
|
||||||
}
|
}
|
||||||
req->deleteRequest();
|
req->deleteRequest();
|
||||||
}
|
}
|
||||||
@@ -105,6 +112,14 @@ void LLQueuedThread::shutdown()
|
|||||||
// virtual
|
// virtual
|
||||||
S32 LLQueuedThread::update(U32 max_time_ms)
|
S32 LLQueuedThread::update(U32 max_time_ms)
|
||||||
{
|
{
|
||||||
|
if (!mStarted)
|
||||||
|
{
|
||||||
|
if (!mThreaded)
|
||||||
|
{
|
||||||
|
startThread();
|
||||||
|
mStarted = TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
return updateQueue(max_time_ms);
|
return updateQueue(max_time_ms);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -118,8 +133,11 @@ S32 LLQueuedThread::updateQueue(U32 max_time_ms)
|
|||||||
if (mThreaded)
|
if (mThreaded)
|
||||||
{
|
{
|
||||||
pending = getPending();
|
pending = getPending();
|
||||||
|
if(pending > 0)
|
||||||
|
{
|
||||||
unpause();
|
unpause();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
while (pending > 0)
|
while (pending > 0)
|
||||||
@@ -349,9 +367,9 @@ bool LLQueuedThread::completeRequest(handle_t handle)
|
|||||||
#if _DEBUG
|
#if _DEBUG
|
||||||
// llinfos << llformat("LLQueuedThread::Completed req [%08d]",handle) << llendl;
|
// llinfos << llformat("LLQueuedThread::Completed req [%08d]",handle) << llendl;
|
||||||
#endif
|
#endif
|
||||||
//re insert to the queue to schedule for a delete later
|
mRequestHash.erase(handle);
|
||||||
req->setStatus(STATUS_DELETE);
|
req->deleteRequest();
|
||||||
mRequestQueue.insert(req);
|
// check();
|
||||||
res = true;
|
res = true;
|
||||||
}
|
}
|
||||||
unlockData();
|
unlockData();
|
||||||
@@ -395,19 +413,11 @@ S32 LLQueuedThread::processNextRequest()
|
|||||||
}
|
}
|
||||||
req = *mRequestQueue.begin();
|
req = *mRequestQueue.begin();
|
||||||
mRequestQueue.erase(mRequestQueue.begin());
|
mRequestQueue.erase(mRequestQueue.begin());
|
||||||
|
|
||||||
if(req->getStatus() == STATUS_DELETE)
|
|
||||||
{
|
|
||||||
mRequestHash.erase(req);
|
|
||||||
req->deleteRequest();
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((req->getFlags() & FLAG_ABORT) || (mStatus == QUITTING))
|
if ((req->getFlags() & FLAG_ABORT) || (mStatus == QUITTING))
|
||||||
{
|
{
|
||||||
req->setStatus(STATUS_ABORTED);
|
req->setStatus(STATUS_ABORTED);
|
||||||
req->finishRequest(false);
|
req->finishRequest(false);
|
||||||
if ((req->getFlags() & FLAG_AUTO_COMPLETE))
|
if (req->getFlags() & FLAG_AUTO_COMPLETE)
|
||||||
{
|
{
|
||||||
mRequestHash.erase(req);
|
mRequestHash.erase(req);
|
||||||
req->deleteRequest();
|
req->deleteRequest();
|
||||||
@@ -418,9 +428,11 @@ S32 LLQueuedThread::processNextRequest()
|
|||||||
llassert_always(req->getStatus() == STATUS_QUEUED);
|
llassert_always(req->getStatus() == STATUS_QUEUED);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
U32 start_priority = 0 ;
|
||||||
if (req)
|
if (req)
|
||||||
{
|
{
|
||||||
req->setStatus(STATUS_INPROGRESS);
|
req->setStatus(STATUS_INPROGRESS);
|
||||||
|
start_priority = req->getPriority();
|
||||||
}
|
}
|
||||||
unlockData();
|
unlockData();
|
||||||
|
|
||||||
@@ -436,13 +448,12 @@ S32 LLQueuedThread::processNextRequest()
|
|||||||
{
|
{
|
||||||
lockData();
|
lockData();
|
||||||
req->setStatus(STATUS_COMPLETE);
|
req->setStatus(STATUS_COMPLETE);
|
||||||
|
|
||||||
req->finishRequest(true);
|
req->finishRequest(true);
|
||||||
|
if (req->getFlags() & FLAG_AUTO_COMPLETE)
|
||||||
if ((req->getFlags() & FLAG_AUTO_COMPLETE))
|
|
||||||
{
|
{
|
||||||
mRequestHash.erase(req);
|
mRequestHash.erase(req);
|
||||||
req->deleteRequest();
|
req->deleteRequest();
|
||||||
|
// check();
|
||||||
}
|
}
|
||||||
unlockData();
|
unlockData();
|
||||||
}
|
}
|
||||||
@@ -451,9 +462,8 @@ S32 LLQueuedThread::processNextRequest()
|
|||||||
lockData();
|
lockData();
|
||||||
req->setStatus(STATUS_QUEUED);
|
req->setStatus(STATUS_QUEUED);
|
||||||
mRequestQueue.insert(req);
|
mRequestQueue.insert(req);
|
||||||
U32 priority = req->getPriority();
|
|
||||||
unlockData();
|
unlockData();
|
||||||
if (priority < PRIORITY_NORMAL)
|
if (mThreaded && start_priority < PRIORITY_NORMAL)
|
||||||
{
|
{
|
||||||
ms_sleep(1); // sleep the thread a little
|
ms_sleep(1); // sleep the thread a little
|
||||||
}
|
}
|
||||||
@@ -481,6 +491,7 @@ void LLQueuedThread::run()
|
|||||||
// call checPause() immediately so we don't try to do anything before the class is fully constructed
|
// call checPause() immediately so we don't try to do anything before the class is fully constructed
|
||||||
checkPause();
|
checkPause();
|
||||||
startThread();
|
startThread();
|
||||||
|
mStarted = TRUE;
|
||||||
|
|
||||||
while (1)
|
while (1)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -184,7 +184,7 @@ public:
|
|||||||
void waitOnPending();
|
void waitOnPending();
|
||||||
void printQueueStats();
|
void printQueueStats();
|
||||||
|
|
||||||
S32 getPending();
|
virtual S32 getPending();
|
||||||
bool getThreaded() { return mThreaded ? true : false; }
|
bool getThreaded() { return mThreaded ? true : false; }
|
||||||
|
|
||||||
// Request accessors
|
// Request accessors
|
||||||
@@ -202,6 +202,7 @@ public:
|
|||||||
|
|
||||||
protected:
|
protected:
|
||||||
BOOL mThreaded; // if false, run on main thread and do updates during update()
|
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
|
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;
|
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
|
||||||
@@ -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)
|
LLSD& LLSD::with(const String& k, const LLSD& v)
|
||||||
{
|
{
|
||||||
makeMap(impl).insert(k, v);
|
makeMap(impl).insert(k, v);
|
||||||
#ifdef LL_MSVC7
|
return *this;
|
||||||
return *dynamic_cast<LLSD*>(this);
|
|
||||||
#else
|
|
||||||
return *this;
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
void LLSD::erase(const String& k) { makeMap(impl).erase(k); }
|
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)
|
LLSD& LLSD::with(Integer i, const LLSD& v)
|
||||||
{
|
{
|
||||||
makeArray(impl).insert(i, v);
|
makeArray(impl).insert(i, v);
|
||||||
#ifdef LL_MSVC7
|
return *this;
|
||||||
return *dynamic_cast<LLSD*>(this);
|
|
||||||
#else
|
|
||||||
return *this;
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
void LLSD::append(const LLSD& v) { makeArray(impl).append(v); }
|
void LLSD::append(const LLSD& v) { makeArray(impl).append(v); }
|
||||||
void LLSD::erase(Integer i) { makeArray(impl).erase(i); }
|
void LLSD::erase(Integer i) { makeArray(impl).erase(i); }
|
||||||
|
|||||||
@@ -34,11 +34,18 @@
|
|||||||
|
|
||||||
#include "linden_common.h"
|
#include "linden_common.h"
|
||||||
#include "llsdserialize.h"
|
#include "llsdserialize.h"
|
||||||
#include "llmemory.h"
|
#include "llpointer.h"
|
||||||
#include "llstreamtools.h" // for fullread
|
#include "llstreamtools.h" // for fullread
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include "apr_base64.h"
|
#include "apr_base64.h"
|
||||||
|
#if MESH_ENABLED
|
||||||
|
#ifdef LL_STANDALONE
|
||||||
|
# include <zlib.h>
|
||||||
|
#else
|
||||||
|
# include "zlib/zlib.h" // for davep's dirty little zip functions
|
||||||
|
#endif
|
||||||
|
#endif //MESH_ENABLED
|
||||||
|
|
||||||
#if !LL_WINDOWS
|
#if !LL_WINDOWS
|
||||||
#include <netinet/in.h> // htonl & ntohl
|
#include <netinet/in.h> // htonl & ntohl
|
||||||
@@ -1990,3 +1997,181 @@ std::ostream& operator<<(std::ostream& s, const LLSD& llsd)
|
|||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if MESH_ENABLED
|
||||||
|
|
||||||
|
//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;
|
||||||
|
}
|
||||||
|
#endif //MESH_ENABLED
|
||||||
@@ -36,8 +36,9 @@
|
|||||||
#define LL_LLSDSERIALIZE_H
|
#define LL_LLSDSERIALIZE_H
|
||||||
|
|
||||||
#include <iosfwd>
|
#include <iosfwd>
|
||||||
|
#include "llpointer.h"
|
||||||
|
#include "llrefcount.h"
|
||||||
#include "llsd.h"
|
#include "llsd.h"
|
||||||
#include "llmemory.h"
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @class LLSDParser
|
* @class LLSDParser
|
||||||
@@ -787,4 +788,9 @@ public:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#if MESH_ENABLED
|
||||||
|
//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 //MESH_ENABLED
|
||||||
#endif // LL_LLSDSERIALIZE_H
|
#endif // LL_LLSDSERIALIZE_H
|
||||||
|
|||||||
@@ -37,6 +37,7 @@
|
|||||||
#include <deque>
|
#include <deque>
|
||||||
|
|
||||||
#include "apr_base64.h"
|
#include "apr_base64.h"
|
||||||
|
#include <boost/regex.hpp>
|
||||||
|
|
||||||
extern "C"
|
extern "C"
|
||||||
{
|
{
|
||||||
@@ -734,6 +735,7 @@ void LLSDXMLParser::Impl::endElementHandler(const XML_Char* name)
|
|||||||
case ELEMENT_INTEGER:
|
case ELEMENT_INTEGER:
|
||||||
{
|
{
|
||||||
S32 i;
|
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 )
|
if ( sscanf(mCurrentContent.c_str(), "%d", &i ) == 1 )
|
||||||
{ // See if sscanf works - it's faster
|
{ // See if sscanf works - it's faster
|
||||||
value = i;
|
value = i;
|
||||||
@@ -747,15 +749,19 @@ void LLSDXMLParser::Impl::endElementHandler(const XML_Char* name)
|
|||||||
|
|
||||||
case ELEMENT_REAL:
|
case ELEMENT_REAL:
|
||||||
{
|
{
|
||||||
F64 r;
|
value = LLSD(mCurrentContent).asReal();
|
||||||
if ( sscanf(mCurrentContent.c_str(), "%lf", &r ) == 1 )
|
// removed since this breaks when locale has decimal separator that isn't '.'
|
||||||
{ // See if sscanf works - it's faster
|
// investigated changing local to something compatible each time but deemed higher
|
||||||
value = r;
|
// risk that just using LLSD.asReal() each time.
|
||||||
}
|
//F64 r;
|
||||||
else
|
//if ( sscanf(mCurrentContent.c_str(), "%lf", &r ) == 1 )
|
||||||
{
|
//{ // See if sscanf works - it's faster
|
||||||
value = LLSD(mCurrentContent).asReal();
|
// value = r;
|
||||||
}
|
//}
|
||||||
|
//else
|
||||||
|
//{
|
||||||
|
// value = LLSD(mCurrentContent).asReal();
|
||||||
|
//}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -777,10 +783,17 @@ void LLSDXMLParser::Impl::endElementHandler(const XML_Char* name)
|
|||||||
|
|
||||||
case ELEMENT_BINARY:
|
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;
|
std::vector<U8> data;
|
||||||
data.resize(len);
|
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);
|
data.resize(len);
|
||||||
value = data;
|
value = data;
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -46,6 +46,12 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "llsdserialize.h"
|
#include "llsdserialize.h"
|
||||||
|
#include "stringize.h"
|
||||||
|
#include "is_approx_equal_fraction.h"
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
#include <set>
|
||||||
|
#include <boost/range.hpp>
|
||||||
|
|
||||||
// U32
|
// U32
|
||||||
LLSD ll_sd_from_U32(const U32 val)
|
LLSD ll_sd_from_U32(const U32 val)
|
||||||
@@ -171,6 +177,15 @@ char* ll_print_sd(const LLSD& sd)
|
|||||||
return buffer;
|
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)
|
char* ll_pretty_print_sd(const LLSD& sd)
|
||||||
{
|
{
|
||||||
const U32 bufferSize = 10 * 1024;
|
const U32 bufferSize = 10 * 1024;
|
||||||
@@ -304,3 +319,363 @@ BOOL compare_llsd_with_template(
|
|||||||
|
|
||||||
return TRUE;
|
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
|
#ifndef LL_LLSDUTIL_H
|
||||||
#define LL_LLSDUTIL_H
|
#define LL_LLSDUTIL_H
|
||||||
|
|
||||||
#include "llsd.h"
|
class LLSD;
|
||||||
|
|
||||||
// U32
|
// U32
|
||||||
LL_COMMON_API LLSD ll_sd_from_U32(const 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);
|
LL_COMMON_API char* ll_print_sd(const LLSD& sd);
|
||||||
|
|
||||||
// Serializes sd to static buffer and returns pointer, using "pretty printing" mode.
|
// 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);
|
LL_COMMON_API char* ll_pretty_print_sd(const LLSD& sd);
|
||||||
|
|
||||||
//compares the structure of an LLSD to a template LLSD and stores the
|
//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,
|
const LLSD& template_llsd,
|
||||||
LLSD& resultant_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
|
// Simple function to copy data out of input & output iterators if
|
||||||
// there is no need for casting.
|
// there is no need for casting.
|
||||||
template<typename Input> LLSD llsd_copy_array(Input iter, Input end)
|
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;
|
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
|
#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;
|
||||||
|
|
||||||
207
indra/llcommon/llsingleton.h
Normal file
207
indra/llcommon/llsingleton.h
Normal file
@@ -0,0 +1,207 @@
|
|||||||
|
/**
|
||||||
|
* @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()
|
||||||
|
{
|
||||||
|
SingletonInstanceData& data = getData();
|
||||||
|
if (data.mInitState != DELETED)
|
||||||
|
{
|
||||||
|
deleteSingleton();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual ~LLSingleton()
|
||||||
|
{
|
||||||
|
SingletonInstanceData& data = getData();
|
||||||
|
data.mSingletonInstance = NULL;
|
||||||
|
data.mInitState = DELETED;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Can be used to control when the singleton is deleted. Not normally needed.
|
||||||
|
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
|
// 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
|
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"
|
std::string LLPerfBlock::sCurrentStatPath = ""; // Something like "/total_time/physics/physics step"
|
||||||
|
LLStat::stat_map_t LLStat::sStatList;
|
||||||
|
|
||||||
//------------------------------------------------------------------------
|
//------------------------------------------------------------------------
|
||||||
// Live config file to trigger stats logging
|
// Live config file to trigger stats logging
|
||||||
@@ -129,6 +130,7 @@ bool LLStatsConfigFile::loadFile()
|
|||||||
|
|
||||||
F32 duration = 0.f;
|
F32 duration = 0.f;
|
||||||
F32 interval = 0.f;
|
F32 interval = 0.f;
|
||||||
|
S32 flags = LLPerfBlock::LLSTATS_BASIC_STATS;
|
||||||
|
|
||||||
const char * w = "duration";
|
const char * w = "duration";
|
||||||
if (stats_config.has(w))
|
if (stats_config.has(w))
|
||||||
@@ -140,8 +142,18 @@ bool LLStatsConfigFile::loadFile()
|
|||||||
{
|
{
|
||||||
interval = (F32)stats_config[w].asReal();
|
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 );
|
mStatsp->setReportPerformanceInterval( interval );
|
||||||
|
|
||||||
if ( duration > 0 )
|
if ( duration > 0 )
|
||||||
@@ -253,13 +265,14 @@ void LLPerfStats::dumpIntervalPerformanceStats()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set length of performance stat recording
|
// Set length of performance stat recording.
|
||||||
void LLPerfStats::setReportPerformanceDuration( F32 seconds )
|
// If turning stats on, caller must provide flags
|
||||||
|
void LLPerfStats::setReportPerformanceDuration( F32 seconds, S32 flags /* = LLSTATS_NO_OPTIONAL_STATS */ )
|
||||||
{
|
{
|
||||||
if ( seconds <= 0.f )
|
if ( seconds <= 0.f )
|
||||||
{
|
{
|
||||||
mReportPerformanceStatEnd = 0.0;
|
mReportPerformanceStatEnd = 0.0;
|
||||||
LLPerfBlock::setStatsEnabled( FALSE );
|
LLPerfBlock::setStatsFlags(LLPerfBlock::LLSTATS_NO_OPTIONAL_STATS); // Make sure all recording is off
|
||||||
mFrameStatsFile.close();
|
mFrameStatsFile.close();
|
||||||
LLPerfBlock::clearDynamicStats();
|
LLPerfBlock::clearDynamicStats();
|
||||||
}
|
}
|
||||||
@@ -268,8 +281,8 @@ void LLPerfStats::setReportPerformanceDuration( F32 seconds )
|
|||||||
mReportPerformanceStatEnd = LLFrameTimer::getElapsedSeconds() + ((F64) seconds);
|
mReportPerformanceStatEnd = LLFrameTimer::getElapsedSeconds() + ((F64) seconds);
|
||||||
// Clear failure flag to try and create the log file once
|
// Clear failure flag to try and create the log file once
|
||||||
mFrameStatsFileFailure = FALSE;
|
mFrameStatsFileFailure = FALSE;
|
||||||
LLPerfBlock::setStatsEnabled( TRUE );
|
|
||||||
mSkipFirstFrameStats = TRUE; // Skip the first report (at the end of this frame)
|
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.
|
// Use this constructor for normal, optional LLPerfBlock time slices
|
||||||
// These are also turned on or off via the switch passed in
|
LLPerfBlock::LLPerfBlock( const char* key ) : mPredefinedStat(NULL), mDynamicStat(NULL)
|
||||||
LLPerfBlock::LLPerfBlock( const char* key1, const char* key2 ) : 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)
|
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)
|
void LLPerfBlock::initDynamicStat(const std::string& key)
|
||||||
{
|
{
|
||||||
// Early exit if dynamic stats aren't enabled.
|
// 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
|
mLastPath = sCurrentStatPath; // Save and restore current path
|
||||||
sCurrentStatPath += "/" + key; // Add key to current path
|
sCurrentStatPath += "/" + key; // Add key to current path
|
||||||
@@ -713,7 +743,7 @@ void LLPerfBlock::addStatsToLLSDandReset( LLSD & stats,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
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;
|
llwarns << "Unexpected NULL dynamic stat at '" << stats_full_path << "'" << llendl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -725,14 +755,12 @@ void LLPerfBlock::addStatsToLLSDandReset( LLSD & stats,
|
|||||||
LLTimer LLStat::sTimer;
|
LLTimer LLStat::sTimer;
|
||||||
LLFrameTimer LLStat::sFrameTimer;
|
LLFrameTimer LLStat::sFrameTimer;
|
||||||
|
|
||||||
LLStat::LLStat(const U32 num_bins, const BOOL use_frame_timer)
|
void LLStat::init()
|
||||||
{
|
{
|
||||||
llassert(num_bins > 0);
|
llassert(mNumBins > 0);
|
||||||
mUseFrameTimer = use_frame_timer;
|
|
||||||
mNumValues = 0;
|
mNumValues = 0;
|
||||||
mLastValue = 0.f;
|
mLastValue = 0.f;
|
||||||
mLastTime = 0.f;
|
mLastTime = 0.f;
|
||||||
mNumBins = num_bins;
|
|
||||||
mCurBin = (mNumBins-1);
|
mCurBin = (mNumBins-1);
|
||||||
mNextBin = 0;
|
mNextBin = 0;
|
||||||
mBins = new F32[mNumBins];
|
mBins = new F32[mNumBins];
|
||||||
@@ -746,6 +774,29 @@ LLStat::LLStat(const U32 num_bins, const BOOL use_frame_timer)
|
|||||||
mTime[i] = 0.0;
|
mTime[i] = 0.0;
|
||||||
mDT[i] = 0.f;
|
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()
|
LLStat::~LLStat()
|
||||||
@@ -754,6 +805,15 @@ LLStat::~LLStat()
|
|||||||
delete[] mBeginTime;
|
delete[] mBeginTime;
|
||||||
delete[] mTime;
|
delete[] mTime;
|
||||||
delete[] mDT;
|
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()
|
void LLStat::reset()
|
||||||
|
|||||||
@@ -192,14 +192,23 @@ public:
|
|||||||
// Use this constructor for pre-defined LLStatTime objects
|
// Use this constructor for pre-defined LLStatTime objects
|
||||||
LLPerfBlock(LLStatTime* stat);
|
LLPerfBlock(LLStatTime* stat);
|
||||||
|
|
||||||
// Use this constructor for dynamically created LLStatTime objects (not pre-defined) with a multi-part key
|
// Use this constructor for normal, optional LLPerfBlock time slices
|
||||||
LLPerfBlock( const char* key1, const char* key2 = NULL);
|
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();
|
~LLPerfBlock();
|
||||||
|
|
||||||
static void setStatsEnabled( BOOL enable ) { sStatsEnabled = enable; };
|
enum
|
||||||
static S32 getStatsEnabled() { return sStatsEnabled; };
|
{ // 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 clearDynamicStats(); // Reset maps to clear out dynamic objects
|
||||||
static void addStatsToLLSDandReset( LLSD & stats, // Get current information and clear time bin
|
static void addStatsToLLSDandReset( LLSD & stats, // Get current information and clear time bin
|
||||||
@@ -213,7 +222,7 @@ private:
|
|||||||
LLStatTime * mPredefinedStat; // LLStatTime object to get data
|
LLStatTime * mPredefinedStat; // LLStatTime object to get data
|
||||||
StatEntry * mDynamicStat; // StatEntryobject 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 stat_map_t sStatMap; // Map full path string to LLStatTime objects
|
||||||
static std::string sCurrentStatPath; // Something like "frame/physics/physics step"
|
static std::string sCurrentStatPath; // Something like "frame/physics/physics step"
|
||||||
};
|
};
|
||||||
@@ -236,7 +245,7 @@ public:
|
|||||||
BOOL frameStatsIsRunning() { return (mReportPerformanceStatEnd > 0.); };
|
BOOL frameStatsIsRunning() { return (mReportPerformanceStatEnd > 0.); };
|
||||||
F32 getReportPerformanceInterval() const { return mReportPerformanceStatInterval; };
|
F32 getReportPerformanceInterval() const { return mReportPerformanceStatInterval; };
|
||||||
void setReportPerformanceInterval( F32 interval ) { mReportPerformanceStatInterval = interval; };
|
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 setProcessName(const std::string& process_name) { mProcessName = process_name; }
|
||||||
void setProcessPID(S32 process_pid) { mProcessPID = process_pid; }
|
void setProcessPID(S32 process_pid) { mProcessPID = process_pid; }
|
||||||
|
|
||||||
@@ -258,8 +267,15 @@ private:
|
|||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
class LL_COMMON_API LLStat
|
class LL_COMMON_API LLStat
|
||||||
{
|
{
|
||||||
|
private:
|
||||||
|
typedef std::multimap<std::string, LLStat*> stat_map_t;
|
||||||
|
static stat_map_t sStatList;
|
||||||
|
|
||||||
|
void init();
|
||||||
|
|
||||||
public:
|
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();
|
~LLStat();
|
||||||
|
|
||||||
void reset();
|
void reset();
|
||||||
@@ -322,8 +338,22 @@ private:
|
|||||||
F32 *mDT;
|
F32 *mDT;
|
||||||
S32 mCurBin;
|
S32 mCurBin;
|
||||||
S32 mNextBin;
|
S32 mNextBin;
|
||||||
|
|
||||||
|
std::string mName;
|
||||||
|
|
||||||
static LLTimer sTimer;
|
static LLTimer sTimer;
|
||||||
static LLFrameTimer sFrameTimer;
|
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_
|
#endif // LL_STAT_
|
||||||
|
|||||||
@@ -45,7 +45,7 @@
|
|||||||
// skips spaces and tabs
|
// skips spaces and tabs
|
||||||
bool skip_whitespace(std::istream& input_stream)
|
bool skip_whitespace(std::istream& input_stream)
|
||||||
{
|
{
|
||||||
char c = input_stream.peek();
|
int c = input_stream.peek();
|
||||||
while (('\t' == c || ' ' == c) && input_stream.good())
|
while (('\t' == c || ' ' == c) && input_stream.good())
|
||||||
{
|
{
|
||||||
input_stream.get();
|
input_stream.get();
|
||||||
@@ -57,7 +57,7 @@ bool skip_whitespace(std::istream& input_stream)
|
|||||||
// skips whitespace, newlines, and carriage returns
|
// skips whitespace, newlines, and carriage returns
|
||||||
bool skip_emptyspace(std::istream& input_stream)
|
bool skip_emptyspace(std::istream& input_stream)
|
||||||
{
|
{
|
||||||
char c = input_stream.peek();
|
int c = input_stream.peek();
|
||||||
while ( input_stream.good()
|
while ( input_stream.good()
|
||||||
&& ('\t' == c || ' ' == c || '\n' == c || '\r' == c) )
|
&& ('\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))
|
while (skip_emptyspace(input_stream))
|
||||||
{
|
{
|
||||||
char c = input_stream.peek();
|
int c = input_stream.peek();
|
||||||
if ('#' == c )
|
if ('#' == c )
|
||||||
{
|
{
|
||||||
while ('\n' != c && input_stream.good())
|
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)
|
bool skip_line(std::istream& input_stream)
|
||||||
{
|
{
|
||||||
char c;
|
int c;
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
c = input_stream.get();
|
c = input_stream.get();
|
||||||
@@ -100,7 +100,7 @@ bool skip_line(std::istream& input_stream)
|
|||||||
|
|
||||||
bool skip_to_next_word(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()
|
while ( input_stream.good()
|
||||||
&& ( (c >= 'a' && c <= 'z')
|
&& ( (c >= 'a' && c <= 'z')
|
||||||
|| (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())
|
while (input_stream.good())
|
||||||
{
|
{
|
||||||
skip_emptyspace(input_stream);
|
skip_emptyspace(input_stream);
|
||||||
char c = input_stream.get();
|
int c = input_stream.get();
|
||||||
if (keyword[0] != c)
|
if (keyword[0] != c)
|
||||||
{
|
{
|
||||||
skip_line(input_stream);
|
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())
|
while (input_stream.good())
|
||||||
{
|
{
|
||||||
skip_emptyspace(input_stream);
|
skip_emptyspace(input_stream);
|
||||||
char c = input_stream.get();
|
int c = input_stream.get();
|
||||||
if (keyword[0] != c)
|
if (keyword[0] != c)
|
||||||
{
|
{
|
||||||
skip_line(input_stream);
|
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)
|
bool get_word(std::string& output_string, std::istream& input_stream)
|
||||||
{
|
{
|
||||||
skip_emptyspace(input_stream);
|
skip_emptyspace(input_stream);
|
||||||
char c = input_stream.peek();
|
int c = input_stream.peek();
|
||||||
while ( !isspace(c)
|
while ( !isspace(c)
|
||||||
&& '\n' != c
|
&& '\n' != c
|
||||||
&& '\r' != c
|
&& '\r' != c
|
||||||
@@ -246,7 +246,7 @@ bool get_word(std::string& output_string, std::istream& input_stream, int n)
|
|||||||
{
|
{
|
||||||
skip_emptyspace(input_stream);
|
skip_emptyspace(input_stream);
|
||||||
int char_count = 0;
|
int char_count = 0;
|
||||||
char c = input_stream.peek();
|
int c = input_stream.peek();
|
||||||
while (!isspace(c)
|
while (!isspace(c)
|
||||||
&& '\n' != c
|
&& '\n' != c
|
||||||
&& '\r' != 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)
|
bool get_line(std::string& output_string, std::istream& input_stream)
|
||||||
{
|
{
|
||||||
output_string.clear();
|
output_string.clear();
|
||||||
char c = input_stream.get();
|
int c = input_stream.get();
|
||||||
while (input_stream.good())
|
while (input_stream.good())
|
||||||
{
|
{
|
||||||
output_string += c;
|
output_string += c;
|
||||||
@@ -285,7 +285,7 @@ bool get_line(std::string& output_string, std::istream& input_stream, int n)
|
|||||||
{
|
{
|
||||||
output_string.clear();
|
output_string.clear();
|
||||||
int char_count = 0;
|
int char_count = 0;
|
||||||
char c = input_stream.get();
|
int c = input_stream.get();
|
||||||
while (input_stream.good() && char_count < n)
|
while (input_stream.good() && char_count < n)
|
||||||
{
|
{
|
||||||
char_count++;
|
char_count++;
|
||||||
|
|||||||
@@ -42,14 +42,17 @@ template <class Object> class LLStrider
|
|||||||
U8* mBytep;
|
U8* mBytep;
|
||||||
};
|
};
|
||||||
U32 mSkip;
|
U32 mSkip;
|
||||||
|
U32 mTypeSize;
|
||||||
public:
|
public:
|
||||||
|
|
||||||
LLStrider() { mObjectp = NULL; mSkip = sizeof(Object); }
|
LLStrider() { mObjectp = NULL; mTypeSize = mSkip = sizeof(Object); }
|
||||||
~LLStrider() { }
|
~LLStrider() { }
|
||||||
|
|
||||||
const LLStrider<Object>& operator = (Object *first) { mObjectp = first; return *this;}
|
const LLStrider<Object>& operator = (Object *first) { mObjectp = first; return *this;}
|
||||||
void setStride (S32 skipBytes) { mSkip = (skipBytes ? skipBytes : sizeof(Object));}
|
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;}
|
void skip(const U32 index) { mBytep += mSkip*index;}
|
||||||
U32 getSkip() const { return mSkip; }
|
U32 getSkip() const { return mSkip; }
|
||||||
Object* get() { return mObjectp; }
|
Object* get() { return mObjectp; }
|
||||||
@@ -58,6 +61,71 @@ public:
|
|||||||
Object* operator ++(int) { Object* old = mObjectp; mBytep += mSkip; return old; }
|
Object* operator ++(int) { Object* old = mObjectp; mBytep += mSkip; return old; }
|
||||||
Object* operator +=(int i) { mBytep += mSkip*i; return mObjectp; }
|
Object* operator +=(int i) { mBytep += mSkip*i; return mObjectp; }
|
||||||
Object& operator[](U32 index) { return *(Object*)(mBytep + (mSkip * index)); }
|
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
|
#endif // LL_LLSTRIDER_H
|
||||||
|
|||||||
@@ -52,7 +52,7 @@
|
|||||||
# include <sys/sysctl.h>
|
# include <sys/sysctl.h>
|
||||||
# include <sys/utsname.h>
|
# include <sys/utsname.h>
|
||||||
# include <stdint.h>
|
# include <stdint.h>
|
||||||
//# include <Carbon/Carbon.h> May be needed?
|
# include <Carbon/Carbon.h>
|
||||||
#elif LL_LINUX
|
#elif LL_LINUX
|
||||||
# include <errno.h>
|
# include <errno.h>
|
||||||
# include <sys/utsname.h>
|
# include <sys/utsname.h>
|
||||||
|
|||||||
@@ -62,6 +62,21 @@
|
|||||||
//
|
//
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#if !LL_DARWIN
|
||||||
|
U32 ll_thread_local sThreadID = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
U32 LLThread::sIDIter = 0;
|
||||||
|
|
||||||
|
LL_COMMON_API void assert_main_thread()
|
||||||
|
{
|
||||||
|
static U32 s_thread_id = LLThread::currentID();
|
||||||
|
if (LLThread::currentID() != s_thread_id)
|
||||||
|
{
|
||||||
|
llerrs << "Illegal execution outside main thread." << llendl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// Handed to the APR thread creation function
|
// Handed to the APR thread creation function
|
||||||
//
|
//
|
||||||
@@ -73,8 +88,10 @@ void *APR_THREAD_FUNC LLThread::staticRun(apr_thread_t *apr_threadp, void *datap
|
|||||||
|
|
||||||
LLThread *threadp = (LLThread *)datap;
|
LLThread *threadp = (LLThread *)datap;
|
||||||
|
|
||||||
// Set thread state to running
|
#if !LL_DARWIN
|
||||||
threadp->mStatus = RUNNING;
|
sThreadID = threadp->mID;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
// Create a thread local data.
|
// Create a thread local data.
|
||||||
AIThreadLocalData::create(threadp);
|
AIThreadLocalData::create(threadp);
|
||||||
@@ -82,11 +99,21 @@ void *APR_THREAD_FUNC LLThread::staticRun(apr_thread_t *apr_threadp, void *datap
|
|||||||
// Run the user supplied function
|
// Run the user supplied function
|
||||||
threadp->run();
|
threadp->run();
|
||||||
|
|
||||||
llinfos << "LLThread::staticRun() Exiting: " << threadp->mName << llendl;
|
// Setting mStatus to STOPPED is done non-thread-safe, so it's
|
||||||
|
// possible that the thread is deleted by another thread at
|
||||||
|
// the moment it happens... therefore make a copy here.
|
||||||
|
char const* volatile name = threadp->mName.c_str();
|
||||||
|
|
||||||
// We're done with the run function, this thread is done executing now.
|
// We're done with the run function, this thread is done executing now.
|
||||||
threadp->mStatus = STOPPED;
|
threadp->mStatus = STOPPED;
|
||||||
|
|
||||||
|
// Only now print this info [doing that before setting mStatus
|
||||||
|
// to STOPPED makes it much more likely that another thread runs
|
||||||
|
// after the LLCurl::Multi::run() function exits and we actually
|
||||||
|
// change this variable (which really SHOULD have been inside
|
||||||
|
// the critical area of the mSignal lock)].
|
||||||
|
llinfos << "LLThread::staticRun() Exiting: " << name << llendl;
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -98,6 +125,7 @@ LLThread::LLThread(std::string const& name) :
|
|||||||
mStatus(STOPPED),
|
mStatus(STOPPED),
|
||||||
mThreadLocalData(NULL)
|
mThreadLocalData(NULL)
|
||||||
{
|
{
|
||||||
|
mID = ++sIDIter;
|
||||||
mRunCondition = new LLCondition;
|
mRunCondition = new LLCondition;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -119,7 +147,7 @@ void LLThread::shutdown()
|
|||||||
// First, set the flag that indicates that we're ready to die
|
// First, set the flag that indicates that we're ready to die
|
||||||
setQuitting();
|
setQuitting();
|
||||||
|
|
||||||
llinfos << "LLThread::~LLThread() Killing thread " << mName << " Status: " << mStatus << llendl;
|
llinfos << "LLThread::shutdown() Killing thread " << mName << " Status: " << mStatus << llendl;
|
||||||
// Now wait a bit for the thread to exit
|
// Now wait a bit for the thread to exit
|
||||||
// It's unclear whether I should even bother doing this - this destructor
|
// It's unclear whether I should even bother doing this - this destructor
|
||||||
// should netver get called unless we're already stopped, really...
|
// should netver get called unless we're already stopped, really...
|
||||||
@@ -142,20 +170,38 @@ void LLThread::shutdown()
|
|||||||
{
|
{
|
||||||
// This thread just wouldn't stop, even though we gave it time
|
// This thread just wouldn't stop, even though we gave it time
|
||||||
llwarns << "LLThread::shutdown() exiting thread before clean exit!" << llendl;
|
llwarns << "LLThread::shutdown() exiting thread before clean exit!" << llendl;
|
||||||
|
// Put a stake in its heart.
|
||||||
|
apr_thread_exit(mAPRThreadp, -1);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
mAPRThreadp = NULL;
|
mAPRThreadp = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
delete mRunCondition;
|
delete mRunCondition;
|
||||||
|
mRunCondition = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void LLThread::start()
|
void LLThread::start()
|
||||||
{
|
{
|
||||||
apr_thread_create(&mAPRThreadp, NULL, staticRun, (void *)this, tldata().mRootPool());
|
llassert(isStopped());
|
||||||
|
|
||||||
|
// Set thread state to running
|
||||||
|
mStatus = RUNNING;
|
||||||
|
|
||||||
// We won't bother joining
|
apr_status_t status =
|
||||||
apr_thread_detach(mAPRThreadp);
|
apr_thread_create(&mAPRThreadp, NULL, staticRun, (void *)this, tldata().mRootPool());
|
||||||
|
|
||||||
|
if(status == APR_SUCCESS)
|
||||||
|
{
|
||||||
|
// We won't bother joining
|
||||||
|
apr_thread_detach(mAPRThreadp);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mStatus = STOPPED;
|
||||||
|
llwarns << "failed to start thread " << mName << llendl;
|
||||||
|
ll_apr_warn_status(status);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//============================================================================
|
//============================================================================
|
||||||
@@ -318,6 +364,55 @@ AIThreadLocalData& AIThreadLocalData::tldata(void)
|
|||||||
|
|
||||||
//============================================================================
|
//============================================================================
|
||||||
|
|
||||||
|
void LLMutexBase::lock()
|
||||||
|
{
|
||||||
|
#if LL_DARWIN
|
||||||
|
if (mLockingThread == LLThread::currentID())
|
||||||
|
#else
|
||||||
|
if (mLockingThread == sThreadID)
|
||||||
|
#endif
|
||||||
|
{ //redundant lock
|
||||||
|
mCount++;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
apr_thread_mutex_lock(mAPRMutexp);
|
||||||
|
|
||||||
|
#if MUTEX_DEBUG
|
||||||
|
// Have to have the lock before we can access the debug info
|
||||||
|
U32 id = LLThread::currentID();
|
||||||
|
if (mIsLocked[id] != FALSE)
|
||||||
|
llerrs << "Already locked in Thread: " << id << llendl;
|
||||||
|
mIsLocked[id] = TRUE;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if LL_DARWIN
|
||||||
|
mLockingThread = LLThread::currentID();
|
||||||
|
#else
|
||||||
|
mLockingThread = sThreadID;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void LLMutexBase::unlock()
|
||||||
|
{
|
||||||
|
if (mCount > 0)
|
||||||
|
{ //not the root unlock
|
||||||
|
mCount--;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if MUTEX_DEBUG
|
||||||
|
// Access the debug info while we have the lock
|
||||||
|
U32 id = LLThread::currentID();
|
||||||
|
if (mIsLocked[id] != TRUE)
|
||||||
|
llerrs << "Not locked in Thread: " << id << llendl;
|
||||||
|
mIsLocked[id] = FALSE;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
mLockingThread = NO_THREAD;
|
||||||
|
apr_thread_mutex_unlock(mAPRMutexp);
|
||||||
|
}
|
||||||
|
|
||||||
bool LLMutexBase::isLocked()
|
bool LLMutexBase::isLocked()
|
||||||
{
|
{
|
||||||
if (!tryLock())
|
if (!tryLock())
|
||||||
@@ -328,6 +423,11 @@ bool LLMutexBase::isLocked()
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
U32 LLMutexBase::lockingThread() const
|
||||||
|
{
|
||||||
|
return mLockingThread;
|
||||||
|
}
|
||||||
|
|
||||||
//============================================================================
|
//============================================================================
|
||||||
|
|
||||||
LLCondition::LLCondition(AIAPRPool& parent) : LLMutex(parent)
|
LLCondition::LLCondition(AIAPRPool& parent) : LLMutex(parent)
|
||||||
@@ -335,6 +435,7 @@ LLCondition::LLCondition(AIAPRPool& parent) : LLMutex(parent)
|
|||||||
apr_thread_cond_create(&mAPRCondp, mPool());
|
apr_thread_cond_create(&mAPRCondp, mPool());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
LLCondition::~LLCondition()
|
LLCondition::~LLCondition()
|
||||||
{
|
{
|
||||||
apr_thread_cond_destroy(mAPRCondp);
|
apr_thread_cond_destroy(mAPRCondp);
|
||||||
|
|||||||
@@ -48,6 +48,12 @@ class LLThread;
|
|||||||
class LLMutex;
|
class LLMutex;
|
||||||
class LLCondition;
|
class LLCondition;
|
||||||
|
|
||||||
|
#if LL_WINDOWS
|
||||||
|
#define ll_thread_local __declspec(thread)
|
||||||
|
#else
|
||||||
|
#define ll_thread_local __thread
|
||||||
|
#endif
|
||||||
|
|
||||||
class LL_COMMON_API AIThreadLocalData
|
class LL_COMMON_API AIThreadLocalData
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
@@ -66,6 +72,9 @@ public:
|
|||||||
|
|
||||||
class LL_COMMON_API LLThread
|
class LL_COMMON_API LLThread
|
||||||
{
|
{
|
||||||
|
private:
|
||||||
|
static U32 sIDIter;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
typedef enum e_thread_status
|
typedef enum e_thread_status
|
||||||
{
|
{
|
||||||
@@ -106,6 +115,8 @@ public:
|
|||||||
// Return thread-local data for the current thread.
|
// Return thread-local data for the current thread.
|
||||||
static AIThreadLocalData& tldata(void) { return AIThreadLocalData::tldata(); }
|
static AIThreadLocalData& tldata(void) { return AIThreadLocalData::tldata(); }
|
||||||
|
|
||||||
|
U32 getID() const { return mID; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
BOOL mPaused;
|
BOOL mPaused;
|
||||||
|
|
||||||
@@ -117,7 +128,8 @@ protected:
|
|||||||
LLCondition* mRunCondition;
|
LLCondition* mRunCondition;
|
||||||
|
|
||||||
apr_thread_t *mAPRThreadp;
|
apr_thread_t *mAPRThreadp;
|
||||||
EThreadStatus mStatus;
|
volatile EThreadStatus mStatus;
|
||||||
|
U32 mID;
|
||||||
|
|
||||||
friend void AIThreadLocalData::create(LLThread* threadp);
|
friend void AIThreadLocalData::create(LLThread* threadp);
|
||||||
AIThreadLocalData* mThreadLocalData;
|
AIThreadLocalData* mThreadLocalData;
|
||||||
@@ -151,16 +163,26 @@ protected:
|
|||||||
class LL_COMMON_API LLMutexBase
|
class LL_COMMON_API LLMutexBase
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
void lock() { apr_thread_mutex_lock(mAPRMutexp); }
|
typedef enum
|
||||||
void unlock() { apr_thread_mutex_unlock(mAPRMutexp); }
|
{
|
||||||
|
NO_THREAD = 0xFFFFFFFF
|
||||||
|
} e_locking_thread;
|
||||||
|
|
||||||
|
LLMutexBase() : mLockingThread(NO_THREAD), mCount(0) {}
|
||||||
|
|
||||||
|
void lock(); //blocks
|
||||||
|
void unlock();
|
||||||
// Returns true if lock was obtained successfully.
|
// Returns true if lock was obtained successfully.
|
||||||
bool tryLock() { return !APR_STATUS_IS_EBUSY(apr_thread_mutex_trylock(mAPRMutexp)); }
|
bool tryLock() { return !APR_STATUS_IS_EBUSY(apr_thread_mutex_trylock(mAPRMutexp)); }
|
||||||
|
|
||||||
bool isLocked(); // non-blocking, but does do a lock/unlock so not free
|
bool isLocked(); // non-blocking, but does do a lock/unlock so not free
|
||||||
|
U32 lockingThread() const; //get ID of locking thread
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// mAPRMutexp is initialized and uninitialized in the derived class.
|
// mAPRMutexp is initialized and uninitialized in the derived class.
|
||||||
apr_thread_mutex_t* mAPRMutexp;
|
apr_thread_mutex_t* mAPRMutexp;
|
||||||
|
mutable U32 mCount;
|
||||||
|
mutable U32 mLockingThread;
|
||||||
};
|
};
|
||||||
|
|
||||||
class LL_COMMON_API LLMutex : public LLMutexBase
|
class LL_COMMON_API LLMutex : public LLMutexBase
|
||||||
@@ -350,6 +372,7 @@ void LLThread::unlockData()
|
|||||||
mRunCondition->unlock();
|
mRunCondition->unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//============================================================================
|
//============================================================================
|
||||||
|
|
||||||
// see llmemory.h for LLPointer<> definition
|
// see llmemory.h for LLPointer<> definition
|
||||||
|
|||||||
@@ -36,6 +36,8 @@
|
|||||||
|
|
||||||
#include "u64.h"
|
#include "u64.h"
|
||||||
|
|
||||||
|
#include "lldate.h"
|
||||||
|
|
||||||
#if LL_WINDOWS
|
#if LL_WINDOWS
|
||||||
# define WIN32_LEAN_AND_MEAN
|
# define WIN32_LEAN_AND_MEAN
|
||||||
# include <winsock2.h>
|
# include <winsock2.h>
|
||||||
|
|||||||
@@ -39,8 +39,6 @@
|
|||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
|
|
||||||
#include "stdtypes.h"
|
#include "stdtypes.h"
|
||||||
#include "llpreprocessor.h"
|
|
||||||
#include "lldate.h"
|
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <list>
|
#include <list>
|
||||||
@@ -55,8 +53,6 @@ const U32 USEC_PER_HOUR = USEC_PER_MIN * MIN_PER_HOUR;
|
|||||||
const U32 SEC_PER_HOUR = SEC_PER_MIN * MIN_PER_HOUR;
|
const U32 SEC_PER_HOUR = SEC_PER_MIN * MIN_PER_HOUR;
|
||||||
const F64 SEC_PER_USEC = 1.0 / (F64) USEC_PER_SEC;
|
const F64 SEC_PER_USEC = 1.0 / (F64) USEC_PER_SEC;
|
||||||
|
|
||||||
LL_COMMON_API U64 totalTime(); // Returns current system time in microseconds
|
|
||||||
|
|
||||||
class LL_COMMON_API LLTimer
|
class LL_COMMON_API LLTimer
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@@ -175,4 +171,5 @@ LL_COMMON_API void secondsToTimecodeString(F32 current_time, std::string& tcstri
|
|||||||
LL_COMMON_API void timeToFormattedString(time_t time, std::string format, std::string ×tr);
|
LL_COMMON_API void timeToFormattedString(time_t time, std::string format, std::string ×tr);
|
||||||
LL_COMMON_API void timeStructToFormattedString(struct tm * time, std::string format, std::string ×tr);
|
LL_COMMON_API void timeStructToFormattedString(struct tm * time, std::string format, std::string ×tr);
|
||||||
|
|
||||||
|
U64 LL_COMMON_API totalTime(); // Returns current system time in microseconds
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
705
indra/llcommon/lltreeiterators.h
Normal file
705
indra/llcommon/lltreeiterators.h
Normal file
@@ -0,0 +1,705 @@
|
|||||||
|
/**
|
||||||
|
* @file lltreeiterators.h
|
||||||
|
* @author Nat Goodspeed
|
||||||
|
* @date 2008-08-19
|
||||||
|
* @brief This file defines iterators useful for traversing arbitrary node
|
||||||
|
* classes, potentially polymorphic, linked into strict tree
|
||||||
|
* structures.
|
||||||
|
*
|
||||||
|
* Dereferencing any one of these iterators actually yields a @em
|
||||||
|
* pointer to the node in question. For example, given an
|
||||||
|
* LLLinkedIter<MyNode> <tt>li</tt>, <tt>*li</tt> gets you a pointer
|
||||||
|
* to MyNode, and <tt>**li</tt> gets you the MyNode instance itself.
|
||||||
|
* More commonly, instead of writing <tt>li->member</tt>, you write
|
||||||
|
* <tt>(*li)->member</tt> -- as you would if you were traversing an
|
||||||
|
* STL container of MyNode pointers.
|
||||||
|
*
|
||||||
|
* It would certainly be possible to build these iterators so that
|
||||||
|
* <tt>*iterator</tt> would return a reference to the node itself
|
||||||
|
* rather than a pointer to the node, and for many purposes it would
|
||||||
|
* even be more convenient. However, that would be insufficiently
|
||||||
|
* flexible. If you want to use an iterator range to (e.g.) initialize
|
||||||
|
* a std::vector collecting results -- you rarely want to actually @em
|
||||||
|
* copy the nodes in question. You're much more likely to want to copy
|
||||||
|
* <i>pointers to</i> the traversed nodes. Hence these iterators
|
||||||
|
* produce pointers.
|
||||||
|
*
|
||||||
|
* Though you specify the actual NODE class as the template parameter,
|
||||||
|
* these iterators internally use LLPtrTo<> to discover whether to
|
||||||
|
* store and return an LLPointer<NODE> or a simple NODE*.
|
||||||
|
*
|
||||||
|
* By strict tree structures, we mean that each child must have
|
||||||
|
* exactly one parent. This forbids a child claiming any ancestor as a
|
||||||
|
* child of its own. Child nodes with multiple parents will be visited
|
||||||
|
* once for each parent. Cycles in the graph will result in either an
|
||||||
|
* infinite loop or an out-of-memory crash. You Have Been Warned.
|
||||||
|
*
|
||||||
|
* $LicenseInfo:firstyear=2008&license=viewerlgpl$
|
||||||
|
* Second Life Viewer Source Code
|
||||||
|
* Copyright (C) 2010, Linden Research, Inc.
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation;
|
||||||
|
* version 2.1 of the License only.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*
|
||||||
|
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||||
|
* $/LicenseInfo$
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if ! defined(LL_LLTREEITERATORS_H)
|
||||||
|
#define LL_LLTREEITERATORS_H
|
||||||
|
|
||||||
|
#include "llptrto.h"
|
||||||
|
#include <vector>
|
||||||
|
#include <deque>
|
||||||
|
#include <boost/iterator/iterator_facade.hpp>
|
||||||
|
#include <boost/function.hpp>
|
||||||
|
#include <boost/static_assert.hpp>
|
||||||
|
|
||||||
|
namespace LLTreeIter
|
||||||
|
{
|
||||||
|
/// Discriminator between LLTreeUpIter and LLTreeDownIter
|
||||||
|
enum RootIter { UP, DOWN };
|
||||||
|
/// Discriminator between LLTreeDFSIter, LLTreeDFSPostIter and LLTreeBFSIter
|
||||||
|
enum WalkIter { DFS_PRE, DFS_POST, BFS };
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* LLBaseIter defines some machinery common to all these iterators. We use
|
||||||
|
* boost::iterator_facade to define the iterator boilerplate: the conventional
|
||||||
|
* operators and methods necessary to implement a standards-conforming
|
||||||
|
* iterator. That allows us to specify the actual iterator semantics in terms
|
||||||
|
* of equal(), dereference() and increment() methods.
|
||||||
|
*/
|
||||||
|
template <class SELFTYPE, class NODE>
|
||||||
|
class LLBaseIter: public boost::iterator_facade<SELFTYPE,
|
||||||
|
// use pointer type as the
|
||||||
|
// reference type
|
||||||
|
typename LLPtrTo<NODE>::type,
|
||||||
|
boost::forward_traversal_tag>
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
/// LLPtrTo<NODE>::type is either NODE* or LLPointer<NODE>, as appropriate
|
||||||
|
typedef typename LLPtrTo<NODE>::type ptr_type;
|
||||||
|
/// function that advances from this node to next accepts a node pointer
|
||||||
|
/// and returns another
|
||||||
|
typedef boost::function<ptr_type(const ptr_type&)> func_type;
|
||||||
|
typedef SELFTYPE self_type;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Functor returning NULL, suitable for an end-iterator's 'next' functor
|
||||||
|
template <class NODE>
|
||||||
|
typename LLPtrTo<NODE>::type LLNullNextFunctor(const typename LLPtrTo<NODE>::type&)
|
||||||
|
{
|
||||||
|
return typename LLPtrTo<NODE>::type();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* LLLinkedIter is an iterator over an intrusive singly-linked list. The
|
||||||
|
* beginning of the list is represented by LLLinkedIter(list head); the end is
|
||||||
|
* represented by LLLinkedIter().
|
||||||
|
*
|
||||||
|
* The begin LLLinkedIter must be instantiated with a functor to extract the
|
||||||
|
* 'next' pointer from the current node. Supposing that the link pointer is @c
|
||||||
|
* public, something like:
|
||||||
|
*
|
||||||
|
* @code
|
||||||
|
* NODE* mNext;
|
||||||
|
* @endcode
|
||||||
|
*
|
||||||
|
* you can use (e.g.) <tt>boost::bind(&NODE::mNext, _1)</tt> for the purpose.
|
||||||
|
* Alternatively, you can bind whatever accessor method is normally used to
|
||||||
|
* advance to the next node, e.g. for:
|
||||||
|
*
|
||||||
|
* @code
|
||||||
|
* NODE* next() const;
|
||||||
|
* @endcode
|
||||||
|
*
|
||||||
|
* you can use <tt>boost::bind(&NODE::next, _1)</tt>.
|
||||||
|
*/
|
||||||
|
template <class NODE>
|
||||||
|
class LLLinkedIter: public LLBaseIter<LLLinkedIter<NODE>, NODE>
|
||||||
|
{
|
||||||
|
typedef LLBaseIter<LLLinkedIter<NODE>, NODE> super;
|
||||||
|
protected:
|
||||||
|
/// some methods need to return a reference to self
|
||||||
|
typedef typename super::self_type self_type;
|
||||||
|
typedef typename super::ptr_type ptr_type;
|
||||||
|
typedef typename super::func_type func_type;
|
||||||
|
public:
|
||||||
|
/// Instantiate an LLLinkedIter to start a range, or to end a range before
|
||||||
|
/// a particular list entry. Pass a functor to extract the 'next' pointer
|
||||||
|
/// from the current node.
|
||||||
|
LLLinkedIter(const ptr_type& entry, const func_type& nextfunc):
|
||||||
|
mCurrent(entry),
|
||||||
|
mNextFunc(nextfunc)
|
||||||
|
{}
|
||||||
|
/// Instantiate an LLLinkedIter to end a range at the end of the list
|
||||||
|
LLLinkedIter():
|
||||||
|
mCurrent(),
|
||||||
|
mNextFunc(LLNullNextFunctor<NODE>)
|
||||||
|
{}
|
||||||
|
|
||||||
|
private:
|
||||||
|
/// leverage boost::iterator_facade
|
||||||
|
friend class boost::iterator_core_access;
|
||||||
|
|
||||||
|
/// advance
|
||||||
|
void increment()
|
||||||
|
{
|
||||||
|
mCurrent = mNextFunc(mCurrent);
|
||||||
|
}
|
||||||
|
/// equality
|
||||||
|
bool equal(const self_type& that) const { return this->mCurrent == that.mCurrent; }
|
||||||
|
/// dereference
|
||||||
|
ptr_type& dereference() const { return const_cast<ptr_type&>(mCurrent); }
|
||||||
|
|
||||||
|
ptr_type mCurrent;
|
||||||
|
func_type mNextFunc;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* LLTreeUpIter walks from the node in hand to the root of the tree. The term
|
||||||
|
* "up" is applied to a tree visualized with the root at the top.
|
||||||
|
*
|
||||||
|
* LLTreeUpIter is an alias for LLLinkedIter, since any linked tree that you
|
||||||
|
* can navigate that way at all contains parent pointers.
|
||||||
|
*/
|
||||||
|
template <class NODE>
|
||||||
|
class LLTreeUpIter: public LLLinkedIter<NODE>
|
||||||
|
{
|
||||||
|
typedef LLLinkedIter<NODE> super;
|
||||||
|
public:
|
||||||
|
/// Instantiate an LLTreeUpIter to start from a particular tree node, or
|
||||||
|
/// to end a parent traversal before reaching a particular ancestor. Pass
|
||||||
|
/// a functor to extract the 'parent' pointer from the current node.
|
||||||
|
LLTreeUpIter(const typename super::ptr_type& node,
|
||||||
|
const typename super::func_type& parentfunc):
|
||||||
|
super(node, parentfunc)
|
||||||
|
{}
|
||||||
|
/// Instantiate an LLTreeUpIter to end a range at the root of the tree
|
||||||
|
LLTreeUpIter():
|
||||||
|
super()
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* LLTreeDownIter walks from the root of the tree to the node in hand. The
|
||||||
|
* term "down" is applied to a tree visualized with the root at the top.
|
||||||
|
*
|
||||||
|
* Though you instantiate the begin() LLTreeDownIter with a pointer to some
|
||||||
|
* node at an arbitrary location in the tree, the root will be the first node
|
||||||
|
* you dereference and the passed node will be the last node you dereference.
|
||||||
|
*
|
||||||
|
* On construction, LLTreeDownIter walks from the current node to the root,
|
||||||
|
* capturing the path. Then in use, it replays that walk in reverse. As with
|
||||||
|
* all traversals of interesting data structures, it is actively dangerous to
|
||||||
|
* modify the tree during an LLTreeDownIter walk.
|
||||||
|
*/
|
||||||
|
template <class NODE>
|
||||||
|
class LLTreeDownIter: public LLBaseIter<LLTreeDownIter<NODE>, NODE>
|
||||||
|
{
|
||||||
|
typedef LLBaseIter<LLTreeDownIter<NODE>, NODE> super;
|
||||||
|
typedef typename super::self_type self_type;
|
||||||
|
protected:
|
||||||
|
typedef typename super::ptr_type ptr_type;
|
||||||
|
typedef typename super::func_type func_type;
|
||||||
|
private:
|
||||||
|
typedef std::vector<ptr_type> list_type;
|
||||||
|
public:
|
||||||
|
/// Instantiate an LLTreeDownIter to end at a particular tree node. Pass a
|
||||||
|
/// functor to extract the 'parent' pointer from the current node.
|
||||||
|
LLTreeDownIter(const ptr_type& node,
|
||||||
|
const func_type& parentfunc)
|
||||||
|
{
|
||||||
|
for (ptr_type n = node; n; n = parentfunc(n))
|
||||||
|
mParents.push_back(n);
|
||||||
|
}
|
||||||
|
/// Instantiate an LLTreeDownIter representing "here", the end of the loop
|
||||||
|
LLTreeDownIter() {}
|
||||||
|
|
||||||
|
private:
|
||||||
|
/// leverage boost::iterator_facade
|
||||||
|
friend class boost::iterator_core_access;
|
||||||
|
|
||||||
|
/// advance
|
||||||
|
void increment()
|
||||||
|
{
|
||||||
|
mParents.pop_back();
|
||||||
|
}
|
||||||
|
/// equality
|
||||||
|
bool equal(const self_type& that) const { return this->mParents == that.mParents; }
|
||||||
|
/// implement dereference/indirection operators
|
||||||
|
ptr_type& dereference() const { return const_cast<ptr_type&>(mParents.back()); }
|
||||||
|
|
||||||
|
list_type mParents;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When you want to select between LLTreeUpIter and LLTreeDownIter with a
|
||||||
|
* compile-time discriminator, use LLTreeRootIter with an LLTreeIter::RootIter
|
||||||
|
* template arg.
|
||||||
|
*/
|
||||||
|
template <LLTreeIter::RootIter DISCRIM, class NODE>
|
||||||
|
class LLTreeRootIter
|
||||||
|
{
|
||||||
|
enum { use_a_valid_LLTreeIter_RootIter_value = false };
|
||||||
|
public:
|
||||||
|
/// Bogus constructors for default (unrecognized discriminator) case
|
||||||
|
template <typename TYPE1, typename TYPE2>
|
||||||
|
LLTreeRootIter(TYPE1, TYPE2)
|
||||||
|
{
|
||||||
|
BOOST_STATIC_ASSERT(use_a_valid_LLTreeIter_RootIter_value);
|
||||||
|
}
|
||||||
|
LLTreeRootIter()
|
||||||
|
{
|
||||||
|
BOOST_STATIC_ASSERT(use_a_valid_LLTreeIter_RootIter_value);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Specialize for LLTreeIter::UP
|
||||||
|
template <class NODE>
|
||||||
|
class LLTreeRootIter<LLTreeIter::UP, NODE>: public LLTreeUpIter<NODE>
|
||||||
|
{
|
||||||
|
typedef LLTreeUpIter<NODE> super;
|
||||||
|
public:
|
||||||
|
/// forward begin ctor
|
||||||
|
LLTreeRootIter(const typename super::ptr_type& node,
|
||||||
|
const typename super::func_type& parentfunc):
|
||||||
|
super(node, parentfunc)
|
||||||
|
{}
|
||||||
|
/// forward end ctor
|
||||||
|
LLTreeRootIter():
|
||||||
|
super()
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Specialize for LLTreeIter::DOWN
|
||||||
|
template <class NODE>
|
||||||
|
class LLTreeRootIter<LLTreeIter::DOWN, NODE>: public LLTreeDownIter<NODE>
|
||||||
|
{
|
||||||
|
typedef LLTreeDownIter<NODE> super;
|
||||||
|
public:
|
||||||
|
/// forward begin ctor
|
||||||
|
LLTreeRootIter(const typename super::ptr_type& node,
|
||||||
|
const typename super::func_type& parentfunc):
|
||||||
|
super(node, parentfunc)
|
||||||
|
{}
|
||||||
|
/// forward end ctor
|
||||||
|
LLTreeRootIter():
|
||||||
|
super()
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instantiated with a tree node, typically the root, LLTreeDFSIter "flattens"
|
||||||
|
* a depth-first tree walk through that node and all its descendants.
|
||||||
|
*
|
||||||
|
* The begin() LLTreeDFSIter must be instantiated with functors to obtain from
|
||||||
|
* a given node begin() and end() iterators for that node's children. For this
|
||||||
|
* reason, you must specify the type of the node's child iterator as an
|
||||||
|
* additional template parameter.
|
||||||
|
*
|
||||||
|
* Specifically, the begin functor must return an iterator whose dereferenced
|
||||||
|
* value is a @em pointer to a child tree node. For instance, if each node
|
||||||
|
* tracks its children in an STL container of node* pointers, you can simply
|
||||||
|
* return that container's begin() iterator.
|
||||||
|
*
|
||||||
|
* Alternatively, if a node tracks its children with a classic linked list,
|
||||||
|
* write a functor returning LLLinkedIter<NODE>.
|
||||||
|
*
|
||||||
|
* The end() LLTreeDFSIter must, of course, match the begin() iterator's
|
||||||
|
* template parameters, but is constructed without runtime parameters.
|
||||||
|
*/
|
||||||
|
template <class NODE, typename CHILDITER>
|
||||||
|
class LLTreeDFSIter: public LLBaseIter<LLTreeDFSIter<NODE, CHILDITER>, NODE>
|
||||||
|
{
|
||||||
|
typedef LLBaseIter<LLTreeDFSIter<NODE, CHILDITER>, NODE> super;
|
||||||
|
typedef typename super::self_type self_type;
|
||||||
|
protected:
|
||||||
|
typedef typename super::ptr_type ptr_type;
|
||||||
|
// The func_type is different for this: from a NODE pointer, we must
|
||||||
|
// obtain a CHILDITER.
|
||||||
|
typedef boost::function<CHILDITER(const ptr_type&)> func_type;
|
||||||
|
private:
|
||||||
|
typedef std::vector<ptr_type> list_type;
|
||||||
|
public:
|
||||||
|
/// Instantiate an LLTreeDFSIter to start a depth-first walk. Pass
|
||||||
|
/// functors to extract the 'child begin' and 'child end' iterators from
|
||||||
|
/// each node.
|
||||||
|
LLTreeDFSIter(const ptr_type& node, const func_type& beginfunc, const func_type& endfunc)
|
||||||
|
: mBeginFunc(beginfunc),
|
||||||
|
mEndFunc(endfunc),
|
||||||
|
mSkipChildren(false)
|
||||||
|
{
|
||||||
|
// Only push back this node if it's non-NULL!
|
||||||
|
if (node)
|
||||||
|
mPending.push_back(node);
|
||||||
|
}
|
||||||
|
/// Instantiate an LLTreeDFSIter to mark the end of the walk
|
||||||
|
LLTreeDFSIter() : mSkipChildren(false) {}
|
||||||
|
|
||||||
|
/// flags iterator logic to skip traversing children of current node on next increment
|
||||||
|
void skipDescendants(bool skip = true) { mSkipChildren = skip; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
/// leverage boost::iterator_facade
|
||||||
|
friend class boost::iterator_core_access;
|
||||||
|
|
||||||
|
/// advance
|
||||||
|
/// This implementation is due to http://en.wikipedia.org/wiki/Depth-first_search
|
||||||
|
void increment()
|
||||||
|
{
|
||||||
|
// Capture the node we were just looking at
|
||||||
|
ptr_type current = mPending.back();
|
||||||
|
// Remove it from mPending so we don't process it again later
|
||||||
|
mPending.pop_back();
|
||||||
|
if (!mSkipChildren)
|
||||||
|
{
|
||||||
|
// Add all its children to mPending
|
||||||
|
addChildren(current);
|
||||||
|
}
|
||||||
|
// reset flag after each step
|
||||||
|
mSkipChildren = false;
|
||||||
|
}
|
||||||
|
/// equality
|
||||||
|
bool equal(const self_type& that) const { return this->mPending == that.mPending; }
|
||||||
|
/// implement dereference/indirection operators
|
||||||
|
ptr_type& dereference() const { return const_cast<ptr_type&>(mPending.back()); }
|
||||||
|
|
||||||
|
/// Add the direct children of the specified node to mPending
|
||||||
|
void addChildren(const ptr_type& node)
|
||||||
|
{
|
||||||
|
// If we just use push_back() for each child in turn, we'll end up
|
||||||
|
// processing children in reverse order. We don't want to assume
|
||||||
|
// CHILDITER is reversible: some of the linked trees we'll be
|
||||||
|
// processing manage their children using singly-linked lists. So
|
||||||
|
// figure out how many children there are, grow mPending by that size
|
||||||
|
// and reverse-copy the children into the new space.
|
||||||
|
CHILDITER chi = mBeginFunc(node), chend = mEndFunc(node);
|
||||||
|
// grow mPending by the number of children
|
||||||
|
mPending.resize(mPending.size() + std::distance(chi, chend));
|
||||||
|
// reverse-copy the children into the newly-expanded space
|
||||||
|
std::copy(chi, chend, mPending.rbegin());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// list of the nodes yet to be processed
|
||||||
|
list_type mPending;
|
||||||
|
/// functor to extract begin() child iterator
|
||||||
|
func_type mBeginFunc;
|
||||||
|
/// functor to extract end() child iterator
|
||||||
|
func_type mEndFunc;
|
||||||
|
/// flag which controls traversal of children (skip children of current node if true)
|
||||||
|
bool mSkipChildren;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instantiated with a tree node, typically the root, LLTreeDFSPostIter
|
||||||
|
* "flattens" a depth-first tree walk through that node and all its
|
||||||
|
* descendants. Whereas LLTreeDFSIter visits each node before visiting any of
|
||||||
|
* its children, LLTreeDFSPostIter visits all of a node's children before
|
||||||
|
* visiting the node itself.
|
||||||
|
*
|
||||||
|
* The begin() LLTreeDFSPostIter must be instantiated with functors to obtain
|
||||||
|
* from a given node begin() and end() iterators for that node's children. For
|
||||||
|
* this reason, you must specify the type of the node's child iterator as an
|
||||||
|
* additional template parameter.
|
||||||
|
*
|
||||||
|
* Specifically, the begin functor must return an iterator whose dereferenced
|
||||||
|
* value is a @em pointer to a child tree node. For instance, if each node
|
||||||
|
* tracks its children in an STL container of node* pointers, you can simply
|
||||||
|
* return that container's begin() iterator.
|
||||||
|
*
|
||||||
|
* Alternatively, if a node tracks its children with a classic linked list,
|
||||||
|
* write a functor returning LLLinkedIter<NODE>.
|
||||||
|
*
|
||||||
|
* The end() LLTreeDFSPostIter must, of course, match the begin() iterator's
|
||||||
|
* template parameters, but is constructed without runtime parameters.
|
||||||
|
*/
|
||||||
|
template <class NODE, typename CHILDITER>
|
||||||
|
class LLTreeDFSPostIter: public LLBaseIter<LLTreeDFSPostIter<NODE, CHILDITER>, NODE>
|
||||||
|
{
|
||||||
|
typedef LLBaseIter<LLTreeDFSPostIter<NODE, CHILDITER>, NODE> super;
|
||||||
|
typedef typename super::self_type self_type;
|
||||||
|
protected:
|
||||||
|
typedef typename super::ptr_type ptr_type;
|
||||||
|
// The func_type is different for this: from a NODE pointer, we must
|
||||||
|
// obtain a CHILDITER.
|
||||||
|
typedef boost::function<CHILDITER(const ptr_type&)> func_type;
|
||||||
|
private:
|
||||||
|
// Upon reaching a given node in our pending list, we need to know whether
|
||||||
|
// we've already pushed that node's children, so we must associate a bool
|
||||||
|
// with each node pointer.
|
||||||
|
typedef std::vector< std::pair<ptr_type, bool> > list_type;
|
||||||
|
public:
|
||||||
|
/// Instantiate an LLTreeDFSPostIter to start a depth-first walk. Pass
|
||||||
|
/// functors to extract the 'child begin' and 'child end' iterators from
|
||||||
|
/// each node.
|
||||||
|
LLTreeDFSPostIter(const ptr_type& node, const func_type& beginfunc, const func_type& endfunc)
|
||||||
|
: mBeginFunc(beginfunc),
|
||||||
|
mEndFunc(endfunc),
|
||||||
|
mSkipAncestors(false)
|
||||||
|
{
|
||||||
|
if (! node)
|
||||||
|
return;
|
||||||
|
mPending.push_back(typename list_type::value_type(node, false));
|
||||||
|
makeCurrent();
|
||||||
|
}
|
||||||
|
/// Instantiate an LLTreeDFSPostIter to mark the end of the walk
|
||||||
|
LLTreeDFSPostIter() : mSkipAncestors(false) {}
|
||||||
|
|
||||||
|
/// flags iterator logic to skip traversing ancestors of current node on next increment
|
||||||
|
void skipAncestors(bool skip = true) { mSkipAncestors = skip; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
/// leverage boost::iterator_facade
|
||||||
|
friend class boost::iterator_core_access;
|
||||||
|
|
||||||
|
/// advance
|
||||||
|
/// This implementation is due to http://en.wikipedia.org/wiki/Depth-first_search
|
||||||
|
void increment()
|
||||||
|
{
|
||||||
|
// Pop the previous current node
|
||||||
|
mPending.pop_back();
|
||||||
|
makeCurrent();
|
||||||
|
}
|
||||||
|
/// equality
|
||||||
|
bool equal(const self_type& that) const { return this->mPending == that.mPending; }
|
||||||
|
/// implement dereference/indirection operators
|
||||||
|
ptr_type& dereference() const { return const_cast<ptr_type&>(mPending.back().first); }
|
||||||
|
|
||||||
|
struct isOpen
|
||||||
|
{
|
||||||
|
bool operator()(const typename list_type::value_type& item)
|
||||||
|
{
|
||||||
|
return item.second;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Call this each time we change mPending.back() -- that is, every time
|
||||||
|
/// we're about to change the value returned by dereference(). If we
|
||||||
|
/// haven't yet pushed the new node's children, do so now.
|
||||||
|
void makeCurrent()
|
||||||
|
{
|
||||||
|
if (mSkipAncestors)
|
||||||
|
{
|
||||||
|
mPending.erase(std::remove_if(mPending.begin(), mPending.end(), isOpen()), mPending.end());
|
||||||
|
mSkipAncestors = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Once we've popped the last node, this becomes a no-op.
|
||||||
|
if (mPending.empty())
|
||||||
|
return;
|
||||||
|
// Here mPending.back() holds the node pointer we're proposing to
|
||||||
|
// dereference next. Have we pushed that node's children yet?
|
||||||
|
if (mPending.back().second)
|
||||||
|
return; // if so, it's okay to visit this node now
|
||||||
|
// We haven't yet pushed this node's children. Do so now. Remember
|
||||||
|
// that we did -- while the node in question is still back().
|
||||||
|
mPending.back().second = true;
|
||||||
|
addChildren(mPending.back().first);
|
||||||
|
// Now, because we've just changed mPending.back(), make that new node
|
||||||
|
// current.
|
||||||
|
makeCurrent();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Add the direct children of the specified node to mPending
|
||||||
|
void addChildren(const ptr_type& node)
|
||||||
|
{
|
||||||
|
// If we just use push_back() for each child in turn, we'll end up
|
||||||
|
// processing children in reverse order. We don't want to assume
|
||||||
|
// CHILDITER is reversible: some of the linked trees we'll be
|
||||||
|
// processing manage their children using singly-linked lists. So
|
||||||
|
// figure out how many children there are, grow mPending by that size
|
||||||
|
// and reverse-copy the children into the new space.
|
||||||
|
CHILDITER chi = mBeginFunc(node), chend = mEndFunc(node);
|
||||||
|
// grow mPending by the number of children
|
||||||
|
mPending.resize(mPending.size() + std::distance(chi, chend));
|
||||||
|
// Reverse-copy the children into the newly-expanded space. We can't
|
||||||
|
// just use std::copy() because the source is a ptr_type, whereas the
|
||||||
|
// dest is a pair of (ptr_type, bool).
|
||||||
|
for (typename list_type::reverse_iterator pi = mPending.rbegin(); chi != chend; ++chi, ++pi)
|
||||||
|
{
|
||||||
|
pi->first = *chi; // copy the child pointer
|
||||||
|
pi->second = false; // we haven't yet pushed this child's chldren
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// list of the nodes yet to be processed
|
||||||
|
list_type mPending;
|
||||||
|
/// functor to extract begin() child iterator
|
||||||
|
func_type mBeginFunc;
|
||||||
|
/// functor to extract end() child iterator
|
||||||
|
func_type mEndFunc;
|
||||||
|
/// flags logic to skip traversal of ancestors of current node
|
||||||
|
bool mSkipAncestors;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instantiated with a tree node, typically the root, LLTreeBFSIter "flattens"
|
||||||
|
* a breadth-first tree walk through that node and all its descendants.
|
||||||
|
*
|
||||||
|
* The begin() LLTreeBFSIter must be instantiated with functors to obtain from
|
||||||
|
* a given node the begin() and end() iterators of that node's children. For
|
||||||
|
* this reason, you must specify the type of the node's child iterator as an
|
||||||
|
* additional template parameter.
|
||||||
|
*
|
||||||
|
* Specifically, the begin functor must return an iterator whose dereferenced
|
||||||
|
* value is a @em pointer to a child tree node. For instance, if each node
|
||||||
|
* tracks its children in an STL container of node* pointers, you can simply
|
||||||
|
* return that container's begin() iterator.
|
||||||
|
*
|
||||||
|
* Alternatively, if a node tracks its children with a classic linked list,
|
||||||
|
* write a functor returning LLLinkedIter<NODE>.
|
||||||
|
*
|
||||||
|
* The end() LLTreeBFSIter must, of course, match the begin() iterator's
|
||||||
|
* template parameters, but is constructed without runtime parameters.
|
||||||
|
*/
|
||||||
|
template <class NODE, typename CHILDITER>
|
||||||
|
class LLTreeBFSIter: public LLBaseIter<LLTreeBFSIter<NODE, CHILDITER>, NODE>
|
||||||
|
{
|
||||||
|
typedef LLBaseIter<LLTreeBFSIter<NODE, CHILDITER>, NODE> super;
|
||||||
|
typedef typename super::self_type self_type;
|
||||||
|
protected:
|
||||||
|
typedef typename super::ptr_type ptr_type;
|
||||||
|
// The func_type is different for this: from a NODE pointer, we must
|
||||||
|
// obtain a CHILDITER.
|
||||||
|
typedef boost::function<CHILDITER(const ptr_type&)> func_type;
|
||||||
|
private:
|
||||||
|
// We need a FIFO queue rather than a LIFO stack. Use a deque rather than
|
||||||
|
// a vector, since vector can't implement pop_front() efficiently.
|
||||||
|
typedef std::deque<ptr_type> list_type;
|
||||||
|
public:
|
||||||
|
/// Instantiate an LLTreeBFSIter to start a depth-first walk. Pass
|
||||||
|
/// functors to extract the 'child begin' and 'child end' iterators from
|
||||||
|
/// each node.
|
||||||
|
LLTreeBFSIter(const ptr_type& node, const func_type& beginfunc, const func_type& endfunc):
|
||||||
|
mBeginFunc(beginfunc),
|
||||||
|
mEndFunc(endfunc)
|
||||||
|
{
|
||||||
|
if (node)
|
||||||
|
mPending.push_back(node);
|
||||||
|
}
|
||||||
|
/// Instantiate an LLTreeBFSIter to mark the end of the walk
|
||||||
|
LLTreeBFSIter() {}
|
||||||
|
|
||||||
|
private:
|
||||||
|
/// leverage boost::iterator_facade
|
||||||
|
friend class boost::iterator_core_access;
|
||||||
|
|
||||||
|
/// advance
|
||||||
|
/// This implementation is due to http://en.wikipedia.org/wiki/Breadth-first_search
|
||||||
|
void increment()
|
||||||
|
{
|
||||||
|
// Capture the node we were just looking at
|
||||||
|
ptr_type current = mPending.front();
|
||||||
|
// Remove it from mPending so we don't process it again later
|
||||||
|
mPending.pop_front();
|
||||||
|
// Add all its children to mPending
|
||||||
|
CHILDITER chend = mEndFunc(current);
|
||||||
|
for (CHILDITER chi = mBeginFunc(current); chi != chend; ++chi)
|
||||||
|
mPending.push_back(*chi);
|
||||||
|
}
|
||||||
|
/// equality
|
||||||
|
bool equal(const self_type& that) const { return this->mPending == that.mPending; }
|
||||||
|
/// implement dereference/indirection operators
|
||||||
|
ptr_type& dereference() const { return const_cast<ptr_type&>(mPending.front()); }
|
||||||
|
|
||||||
|
/// list of the nodes yet to be processed
|
||||||
|
list_type mPending;
|
||||||
|
/// functor to extract begin() child iterator
|
||||||
|
func_type mBeginFunc;
|
||||||
|
/// functor to extract end() child iterator
|
||||||
|
func_type mEndFunc;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When you want to select between LLTreeDFSIter, LLTreeDFSPostIter and
|
||||||
|
* LLTreeBFSIter with a compile-time discriminator, use LLTreeWalkIter with an
|
||||||
|
* LLTreeIter::WalkIter template arg.
|
||||||
|
*/
|
||||||
|
template <LLTreeIter::WalkIter DISCRIM, class NODE, typename CHILDITER>
|
||||||
|
class LLTreeWalkIter
|
||||||
|
{
|
||||||
|
enum { use_a_valid_LLTreeIter_WalkIter_value = false };
|
||||||
|
public:
|
||||||
|
/// Bogus constructors for default (unrecognized discriminator) case
|
||||||
|
template <typename TYPE1, typename TYPE2>
|
||||||
|
LLTreeWalkIter(TYPE1, TYPE2)
|
||||||
|
{
|
||||||
|
BOOST_STATIC_ASSERT(use_a_valid_LLTreeIter_WalkIter_value);
|
||||||
|
}
|
||||||
|
LLTreeWalkIter()
|
||||||
|
{
|
||||||
|
BOOST_STATIC_ASSERT(use_a_valid_LLTreeIter_WalkIter_value);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Specialize for LLTreeIter::DFS_PRE
|
||||||
|
template <class NODE, typename CHILDITER>
|
||||||
|
class LLTreeWalkIter<LLTreeIter::DFS_PRE, NODE, CHILDITER>:
|
||||||
|
public LLTreeDFSIter<NODE, CHILDITER>
|
||||||
|
{
|
||||||
|
typedef LLTreeDFSIter<NODE, CHILDITER> super;
|
||||||
|
public:
|
||||||
|
/// forward begin ctor
|
||||||
|
LLTreeWalkIter(const typename super::ptr_type& node,
|
||||||
|
const typename super::func_type& beginfunc,
|
||||||
|
const typename super::func_type& endfunc):
|
||||||
|
super(node, beginfunc, endfunc)
|
||||||
|
{}
|
||||||
|
/// forward end ctor
|
||||||
|
LLTreeWalkIter():
|
||||||
|
super()
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Specialize for LLTreeIter::DFS_POST
|
||||||
|
template <class NODE, typename CHILDITER>
|
||||||
|
class LLTreeWalkIter<LLTreeIter::DFS_POST, NODE, CHILDITER>:
|
||||||
|
public LLTreeDFSPostIter<NODE, CHILDITER>
|
||||||
|
{
|
||||||
|
typedef LLTreeDFSPostIter<NODE, CHILDITER> super;
|
||||||
|
public:
|
||||||
|
/// forward begin ctor
|
||||||
|
LLTreeWalkIter(const typename super::ptr_type& node,
|
||||||
|
const typename super::func_type& beginfunc,
|
||||||
|
const typename super::func_type& endfunc):
|
||||||
|
super(node, beginfunc, endfunc)
|
||||||
|
{}
|
||||||
|
/// forward end ctor
|
||||||
|
LLTreeWalkIter():
|
||||||
|
super()
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Specialize for LLTreeIter::BFS
|
||||||
|
template <class NODE, typename CHILDITER>
|
||||||
|
class LLTreeWalkIter<LLTreeIter::BFS, NODE, CHILDITER>:
|
||||||
|
public LLTreeBFSIter<NODE, CHILDITER>
|
||||||
|
{
|
||||||
|
typedef LLTreeBFSIter<NODE, CHILDITER> super;
|
||||||
|
public:
|
||||||
|
/// forward begin ctor
|
||||||
|
LLTreeWalkIter(const typename super::ptr_type& node,
|
||||||
|
const typename super::func_type& beginfunc,
|
||||||
|
const typename super::func_type& endfunc):
|
||||||
|
super(node, beginfunc, endfunc)
|
||||||
|
{}
|
||||||
|
/// forward end ctor
|
||||||
|
LLTreeWalkIter():
|
||||||
|
super()
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* ! defined(LL_LLTREEITERATORS_H) */
|
||||||
@@ -35,7 +35,7 @@
|
|||||||
|
|
||||||
const S32 LL_VERSION_MAJOR = 1;
|
const S32 LL_VERSION_MAJOR = 1;
|
||||||
const S32 LL_VERSION_MINOR = 5;
|
const S32 LL_VERSION_MINOR = 5;
|
||||||
const S32 LL_VERSION_PATCH = 9;
|
const S32 LL_VERSION_PATCH = 10;
|
||||||
const S32 LL_VERSION_BUILD = 1;
|
const S32 LL_VERSION_BUILD = 1;
|
||||||
|
|
||||||
const char * const LL_CHANNEL = "Singularity";
|
const char * const LL_CHANNEL = "Singularity";
|
||||||
|
|||||||
@@ -245,7 +245,7 @@ U8* LLImageBase::allocateDataSize(S32 width, S32 height, S32 ncomponents, S32 si
|
|||||||
// LLImageRaw
|
// LLImageRaw
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
S32 LLImageRaw::sGlobalRawMemory = 0;
|
AITHREADSAFESIMPLE(S32, LLImageRaw::sGlobalRawMemory, );
|
||||||
S32 LLImageRaw::sRawImageCount = 0;
|
S32 LLImageRaw::sRawImageCount = 0;
|
||||||
S32 LLImageRaw::sRawImageCachedCount = 0;
|
S32 LLImageRaw::sRawImageCachedCount = 0;
|
||||||
|
|
||||||
@@ -295,23 +295,25 @@ LLImageRaw::~LLImageRaw()
|
|||||||
U8* LLImageRaw::allocateData(S32 size)
|
U8* LLImageRaw::allocateData(S32 size)
|
||||||
{
|
{
|
||||||
U8* res = LLImageBase::allocateData(size);
|
U8* res = LLImageBase::allocateData(size);
|
||||||
sGlobalRawMemory += getDataSize();
|
*AIAccess<S32>(sGlobalRawMemory) += getDataSize();
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
// virtual
|
// virtual
|
||||||
U8* LLImageRaw::reallocateData(S32 size)
|
U8* LLImageRaw::reallocateData(S32 size)
|
||||||
{
|
{
|
||||||
sGlobalRawMemory -= getDataSize();
|
S32 old_data_size = getDataSize();
|
||||||
U8* res = LLImageBase::reallocateData(size);
|
U8* res = LLImageBase::reallocateData(size);
|
||||||
sGlobalRawMemory += getDataSize();
|
*AIAccess<S32>(sGlobalRawMemory) += getDataSize() - old_data_size;
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
// virtual
|
// virtual
|
||||||
void LLImageRaw::deleteData()
|
void LLImageRaw::deleteData()
|
||||||
{
|
{
|
||||||
sGlobalRawMemory -= getDataSize();
|
{
|
||||||
|
*AIAccess<S32>(sGlobalRawMemory) -= getDataSize();
|
||||||
|
}
|
||||||
LLImageBase::deleteData();
|
LLImageBase::deleteData();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -327,7 +329,7 @@ void LLImageRaw::setDataAndSize(U8 *data, S32 width, S32 height, S8 components)
|
|||||||
LLImageBase::setSize(width, height, components) ;
|
LLImageBase::setSize(width, height, components) ;
|
||||||
LLImageBase::setDataAndSize(data, width * height * components) ;
|
LLImageBase::setDataAndSize(data, width * height * components) ;
|
||||||
|
|
||||||
sGlobalRawMemory += getDataSize();
|
*AIAccess<S32>(sGlobalRawMemory) += getDataSize();
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOL LLImageRaw::resize(U16 width, U16 height, S8 components)
|
BOOL LLImageRaw::resize(U16 width, U16 height, S8 components)
|
||||||
|
|||||||
@@ -37,6 +37,7 @@
|
|||||||
#include "llstring.h"
|
#include "llstring.h"
|
||||||
#include "llmemory.h"
|
#include "llmemory.h"
|
||||||
#include "llthread.h"
|
#include "llthread.h"
|
||||||
|
#include "aithreadsafe.h"
|
||||||
|
|
||||||
const S32 MIN_IMAGE_MIP = 2; // 4x4, only used for expand/contract power of 2
|
const S32 MIN_IMAGE_MIP = 2; // 4x4, only used for expand/contract power of 2
|
||||||
const S32 MAX_IMAGE_MIP = 11; // 2048x2048
|
const S32 MAX_IMAGE_MIP = 11; // 2048x2048
|
||||||
@@ -241,7 +242,7 @@ protected:
|
|||||||
void setDataAndSize(U8 *data, S32 width, S32 height, S8 components) ;
|
void setDataAndSize(U8 *data, S32 width, S32 height, S8 components) ;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static S32 sGlobalRawMemory;
|
static AIThreadSafeSimple<S32> sGlobalRawMemory;
|
||||||
static S32 sRawImageCount;
|
static S32 sRawImageCount;
|
||||||
|
|
||||||
static S32 sRawImageCachedCount;
|
static S32 sRawImageCachedCount;
|
||||||
|
|||||||
@@ -32,7 +32,7 @@
|
|||||||
#ifndef LL_LLECONOMY_H
|
#ifndef LL_LLECONOMY_H
|
||||||
#define LL_LLECONOMY_H
|
#define LL_LLECONOMY_H
|
||||||
|
|
||||||
#include "llmemory.h"
|
#include "llsingleton.h"
|
||||||
|
|
||||||
class LLMessageSystem;
|
class LLMessageSystem;
|
||||||
class LLVector3;
|
class LLVector3;
|
||||||
|
|||||||
@@ -36,10 +36,9 @@
|
|||||||
#include "lldarray.h"
|
#include "lldarray.h"
|
||||||
#include "llfoldertype.h"
|
#include "llfoldertype.h"
|
||||||
#include "llinventorytype.h"
|
#include "llinventorytype.h"
|
||||||
#include "llinventorydefines.h"
|
|
||||||
#include "llmemtype.h"
|
#include "llmemtype.h"
|
||||||
#include "llpermissions.h"
|
#include "llpermissions.h"
|
||||||
#include "llmemory.h"
|
#include "llrefcount.h"
|
||||||
#include "llsaleinfo.h"
|
#include "llsaleinfo.h"
|
||||||
#include "llsd.h"
|
#include "llsd.h"
|
||||||
#include "lluuid.h"
|
#include "lluuid.h"
|
||||||
@@ -304,84 +303,11 @@ protected:
|
|||||||
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
// Useful bits
|
// Convertors
|
||||||
|
//
|
||||||
|
// These functions convert between structured data and an inventory
|
||||||
|
// item, appropriate for serialization.
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
// This functor tests if an item is transferrable and returns true if
|
|
||||||
// it is. Derived from unary_function<> so that the object can be used
|
|
||||||
// in stl-compliant adaptable predicates (eg, not1<>). You might want
|
|
||||||
// to use this in std::partition() or similar logic.
|
|
||||||
struct IsItemTransferable : public std::unary_function<LLInventoryItem*, bool>
|
|
||||||
{
|
|
||||||
LLUUID mDestID;
|
|
||||||
IsItemTransferable(const LLUUID& dest_id) : mDestID(dest_id) {}
|
|
||||||
bool operator()(const LLInventoryItem* item) const
|
|
||||||
{
|
|
||||||
return (item->getPermissions().allowTransferTo(mDestID)) ? true:false;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// This functor is used to set the owner and group of inventory items,
|
|
||||||
// for example, in a simple std::for_each() loop. Note that the call
|
|
||||||
// to setOwnerAndGroup can fail if authority_id != LLUUID::null.
|
|
||||||
struct SetItemOwnerAndGroup
|
|
||||||
{
|
|
||||||
LLUUID mAuthorityID;
|
|
||||||
LLUUID mOwnerID;
|
|
||||||
LLUUID mGroupID;
|
|
||||||
SetItemOwnerAndGroup(const LLUUID& authority_id,
|
|
||||||
const LLUUID& owner_id,
|
|
||||||
const LLUUID& group_id) :
|
|
||||||
mAuthorityID(authority_id), mOwnerID(owner_id), mGroupID(group_id) {}
|
|
||||||
void operator()(LLInventoryItem* item) const
|
|
||||||
{
|
|
||||||
LLPermissions perm = item->getPermissions();
|
|
||||||
bool is_atomic = (LLAssetType::AT_OBJECT == item->getType()) ? false : true;
|
|
||||||
perm.setOwnerAndGroup(mAuthorityID, mOwnerID, mGroupID, is_atomic);
|
|
||||||
// If no owner id is set, this is equivalent to a deed action.
|
|
||||||
// Clear 'share with group'.
|
|
||||||
if (mOwnerID.isNull())
|
|
||||||
{
|
|
||||||
perm.setMaskGroup(PERM_NONE);
|
|
||||||
}
|
|
||||||
item->setPermissions(perm);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// This functor is used to unset the share with group, everyone perms, and
|
|
||||||
// for sale info for objects being sold through contents.
|
|
||||||
struct SetNotForSale
|
|
||||||
{
|
|
||||||
LLUUID mAgentID;
|
|
||||||
LLUUID mGroupID;
|
|
||||||
SetNotForSale(const LLUUID& agent_id,
|
|
||||||
const LLUUID& group_id) :
|
|
||||||
mAgentID(agent_id), mGroupID(group_id) {}
|
|
||||||
void operator()(LLInventoryItem* item) const
|
|
||||||
{
|
|
||||||
// Clear group & everyone permissions.
|
|
||||||
LLPermissions perm = item->getPermissions();
|
|
||||||
perm.setGroupBits(mAgentID, mGroupID, FALSE, PERM_MODIFY | PERM_MOVE | PERM_COPY);
|
|
||||||
perm.setEveryoneBits(mAgentID, mGroupID, FALSE, PERM_MOVE | PERM_COPY);
|
|
||||||
item->setPermissions(perm);
|
|
||||||
|
|
||||||
// Mark group & everyone permissions for overwrite on the next
|
|
||||||
// rez if it is an object.
|
|
||||||
if(LLAssetType::AT_OBJECT == item->getType())
|
|
||||||
{
|
|
||||||
U32 flags = item->getFlags();
|
|
||||||
flags |= LLInventoryItemFlags::II_FLAGS_OBJECT_PERM_OVERWRITE_GROUP;
|
|
||||||
flags |= LLInventoryItemFlags::II_FLAGS_OBJECT_PERM_OVERWRITE_EVERYONE;
|
|
||||||
item->setFlags(flags);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Clear for sale info.
|
|
||||||
item->setSaleInfo(LLSaleInfo::DEFAULT);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// These functions convert between structured data and an inventroy
|
|
||||||
// item, appropriate for serialization.
|
|
||||||
LLSD ll_create_sd_from_inventory_item(LLPointer<LLInventoryItem> item);
|
LLSD ll_create_sd_from_inventory_item(LLPointer<LLInventoryItem> item);
|
||||||
LLPointer<LLInventoryItem> ll_create_item_from_sd(const LLSD& sd_item);
|
LLPointer<LLInventoryItem> ll_create_item_from_sd(const LLSD& sd_item);
|
||||||
LLSD ll_create_sd_from_inventory_category(LLPointer<LLInventoryCategory> cat);
|
LLSD ll_create_sd_from_inventory_category(LLPointer<LLInventoryCategory> cat);
|
||||||
|
|||||||
@@ -35,6 +35,7 @@
|
|||||||
#include "llinventorytype.h"
|
#include "llinventorytype.h"
|
||||||
#include "lldictionary.h"
|
#include "lldictionary.h"
|
||||||
#include "llmemory.h"
|
#include "llmemory.h"
|
||||||
|
#include "llsingleton.h"
|
||||||
|
|
||||||
static const std::string empty_string;
|
static const std::string empty_string;
|
||||||
|
|
||||||
|
|||||||
@@ -33,7 +33,7 @@
|
|||||||
#ifndef LL_NOTECARD_H
|
#ifndef LL_NOTECARD_H
|
||||||
#define LL_NOTECARD_H
|
#define LL_NOTECARD_H
|
||||||
|
|
||||||
#include "llmemory.h"
|
#include "llpointer.h"
|
||||||
#include "llinventory.h"
|
#include "llinventory.h"
|
||||||
|
|
||||||
class LLNotecard
|
class LLNotecard
|
||||||
|
|||||||
@@ -177,7 +177,7 @@ void LLParcel::init(const LLUUID &owner_id,
|
|||||||
mSaleTimerExpires.stop();
|
mSaleTimerExpires.stop();
|
||||||
mGraceExtension = 0;
|
mGraceExtension = 0;
|
||||||
//mExpireAction = STEA_REVERT;
|
//mExpireAction = STEA_REVERT;
|
||||||
mRecordTransaction = FALSE;
|
//mRecordTransaction = FALSE;
|
||||||
|
|
||||||
mAuctionID = 0;
|
mAuctionID = 0;
|
||||||
mInEscrow = false;
|
mInEscrow = false;
|
||||||
|
|||||||
@@ -38,8 +38,8 @@
|
|||||||
#include "lluuid.h"
|
#include "lluuid.h"
|
||||||
#include "llparcelflags.h"
|
#include "llparcelflags.h"
|
||||||
#include "llpermissions.h"
|
#include "llpermissions.h"
|
||||||
#include "v3math.h"
|
|
||||||
#include "lltimer.h"
|
#include "lltimer.h"
|
||||||
|
#include "v3math.h"
|
||||||
|
|
||||||
// Grid out of which parcels taken is stepped every 4 meters.
|
// Grid out of which parcels taken is stepped every 4 meters.
|
||||||
const F32 PARCEL_GRID_STEP_METERS = 4.f;
|
const F32 PARCEL_GRID_STEP_METERS = 4.f;
|
||||||
@@ -67,6 +67,7 @@ const F32 PARCEL_PASS_HOURS_DEFAULT = 1.f;
|
|||||||
|
|
||||||
// Number of "chunks" in which parcel overlay data is sent
|
// Number of "chunks" in which parcel overlay data is sent
|
||||||
// Chunk 0 = southern rows, entire width
|
// Chunk 0 = southern rows, entire width
|
||||||
|
// NOTE: NOT USABLE FOR VAR SIZED REGIONS!
|
||||||
const S32 PARCEL_OVERLAY_CHUNKS = 4;
|
const S32 PARCEL_OVERLAY_CHUNKS = 4;
|
||||||
|
|
||||||
// Bottom three bits are a color index for the land overlay
|
// Bottom three bits are a color index for the land overlay
|
||||||
@@ -432,13 +433,10 @@ public:
|
|||||||
void completeSale(U32& type, U8& flags, LLUUID& to_id);
|
void completeSale(U32& type, U8& flags, LLUUID& to_id);
|
||||||
void clearSale();
|
void clearSale();
|
||||||
|
|
||||||
// this function returns TRUE if the parcel needs conversion to a
|
|
||||||
// lease from a non-owned-status state.
|
|
||||||
BOOL getRecordTransaction() const { return mRecordTransaction; }
|
|
||||||
void setRecordTransaction(BOOL record) { mRecordTransaction = record; }
|
|
||||||
|
|
||||||
BOOL isMediaResetTimerExpired(const U64& time);
|
BOOL isMediaResetTimerExpired(const U64& time);
|
||||||
|
|
||||||
|
|
||||||
// more accessors
|
// more accessors
|
||||||
U32 getParcelFlags() const { return mParcelFlags; }
|
U32 getParcelFlags() const { return mParcelFlags; }
|
||||||
|
|
||||||
@@ -473,7 +471,9 @@ public:
|
|||||||
{ return (mParcelFlags & PF_ALLOW_FLY) ? TRUE : FALSE; }
|
{ return (mParcelFlags & PF_ALLOW_FLY) ? TRUE : FALSE; }
|
||||||
|
|
||||||
BOOL getAllowLandmark() const
|
BOOL getAllowLandmark() const
|
||||||
{ return (mParcelFlags & PF_ALLOW_LANDMARK) ? TRUE : FALSE; }
|
{ return TRUE; }
|
||||||
|
//Perhaps revert for opensim?
|
||||||
|
//{ return (mParcelFlags & PF_ALLOW_LANDMARK) ? TRUE : FALSE; }
|
||||||
|
|
||||||
BOOL getAllowGroupScripts() const
|
BOOL getAllowGroupScripts() const
|
||||||
{ return (mParcelFlags & PF_ALLOW_GROUP_SCRIPTS) ? TRUE : FALSE; }
|
{ return (mParcelFlags & PF_ALLOW_GROUP_SCRIPTS) ? TRUE : FALSE; }
|
||||||
@@ -599,6 +599,7 @@ public:
|
|||||||
BOOL getPreviouslyGroupOwned() const { return mPreviouslyGroupOwned; }
|
BOOL getPreviouslyGroupOwned() const { return mPreviouslyGroupOwned; }
|
||||||
BOOL getSellWithObjects() const { return (mParcelFlags & PF_SELL_PARCEL_OBJECTS) ? TRUE : FALSE; }
|
BOOL getSellWithObjects() const { return (mParcelFlags & PF_SELL_PARCEL_OBJECTS) ? TRUE : FALSE; }
|
||||||
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
LLUUID mID;
|
LLUUID mID;
|
||||||
LLUUID mOwnerID;
|
LLUUID mOwnerID;
|
||||||
@@ -618,8 +619,6 @@ protected:
|
|||||||
LLTimer mMediaResetTimer;
|
LLTimer mMediaResetTimer;
|
||||||
|
|
||||||
S32 mGraceExtension;
|
S32 mGraceExtension;
|
||||||
BOOL mRecordTransaction;
|
|
||||||
|
|
||||||
|
|
||||||
// This value is non-zero if there is an auction associated with
|
// This value is non-zero if there is an auction associated with
|
||||||
// the parcel.
|
// the parcel.
|
||||||
@@ -672,7 +671,6 @@ protected:
|
|||||||
BOOL mRegionDenyAnonymousOverride;
|
BOOL mRegionDenyAnonymousOverride;
|
||||||
BOOL mRegionDenyAgeUnverifiedOverride;
|
BOOL mRegionDenyAgeUnverifiedOverride;
|
||||||
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// HACK, make private
|
// HACK, make private
|
||||||
S32 mLocalID;
|
S32 mLocalID;
|
||||||
|
|||||||
@@ -132,5 +132,7 @@ const S32 PARCEL_DETAILS_DESC = 1;
|
|||||||
const S32 PARCEL_DETAILS_OWNER = 2;
|
const S32 PARCEL_DETAILS_OWNER = 2;
|
||||||
const S32 PARCEL_DETAILS_GROUP = 3;
|
const S32 PARCEL_DETAILS_GROUP = 3;
|
||||||
const S32 PARCEL_DETAILS_AREA = 4;
|
const S32 PARCEL_DETAILS_AREA = 4;
|
||||||
|
const S32 PARCEL_DETAILS_ID = 5;
|
||||||
|
const S32 PARCEL_DETAILS_SEE_AVATARS = 6;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -30,8 +30,8 @@
|
|||||||
* $/LicenseInfo$
|
* $/LicenseInfo$
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "linden_common.h"
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include "linden_common.h"
|
||||||
|
|
||||||
#include "llsaleinfo.h"
|
#include "llsaleinfo.h"
|
||||||
|
|
||||||
|
|||||||
@@ -17,13 +17,16 @@ set(llmath_SOURCE_FILES
|
|||||||
llcamera.cpp
|
llcamera.cpp
|
||||||
llcoordframe.cpp
|
llcoordframe.cpp
|
||||||
llline.cpp
|
llline.cpp
|
||||||
|
llmatrix3a.cpp
|
||||||
llmodularmath.cpp
|
llmodularmath.cpp
|
||||||
llperlin.cpp
|
llperlin.cpp
|
||||||
llquaternion.cpp
|
llquaternion.cpp
|
||||||
llrect.cpp
|
llrect.cpp
|
||||||
llsphere.cpp
|
llsphere.cpp
|
||||||
|
llvector4a.cpp
|
||||||
llvolume.cpp
|
llvolume.cpp
|
||||||
llvolumemgr.cpp
|
llvolumemgr.cpp
|
||||||
|
llvolumeoctree.cpp
|
||||||
llsdutil_math.cpp
|
llsdutil_math.cpp
|
||||||
m3math.cpp
|
m3math.cpp
|
||||||
m4math.cpp
|
m4math.cpp
|
||||||
@@ -53,21 +56,32 @@ set(llmath_HEADER_FILES
|
|||||||
llinterp.h
|
llinterp.h
|
||||||
llline.h
|
llline.h
|
||||||
llmath.h
|
llmath.h
|
||||||
|
llmatrix3a.h
|
||||||
|
llmatrix3a.inl
|
||||||
llmodularmath.h
|
llmodularmath.h
|
||||||
lloctree.h
|
lloctree.h
|
||||||
llperlin.h
|
llperlin.h
|
||||||
llplane.h
|
llplane.h
|
||||||
llquantize.h
|
llquantize.h
|
||||||
llquaternion.h
|
llquaternion.h
|
||||||
|
llquaternion2.h
|
||||||
|
llquaternion2.inl
|
||||||
llrect.h
|
llrect.h
|
||||||
|
llsimdmath.h
|
||||||
|
llsimdtypes.h
|
||||||
|
llsimdtypes.inl
|
||||||
llsphere.h
|
llsphere.h
|
||||||
lltreenode.h
|
lltreenode.h
|
||||||
|
llvector4a.h
|
||||||
|
llvector4a.inl
|
||||||
|
llvector4logical.h
|
||||||
llv4math.h
|
llv4math.h
|
||||||
llv4matrix3.h
|
llv4matrix3.h
|
||||||
llv4matrix4.h
|
llv4matrix4.h
|
||||||
llv4vector3.h
|
llv4vector3.h
|
||||||
llvolume.h
|
llvolume.h
|
||||||
llvolumemgr.h
|
llvolumemgr.h
|
||||||
|
llvolumeoctree.h
|
||||||
llsdutil_math.h
|
llsdutil_math.h
|
||||||
m3math.h
|
m3math.h
|
||||||
m4math.h
|
m4math.h
|
||||||
|
|||||||
@@ -54,28 +54,20 @@ LLCalc* LLCalc::sInstance = NULL;
|
|||||||
|
|
||||||
LLCalc::LLCalc() : mLastErrorPos(0)
|
LLCalc::LLCalc() : mLastErrorPos(0)
|
||||||
{
|
{
|
||||||
// mUserVariables = new calc_map_t;
|
|
||||||
mVariables = new calc_map_t;
|
|
||||||
mConstants = new calc_map_t;
|
|
||||||
|
|
||||||
// Init table of constants
|
// Init table of constants
|
||||||
(*mConstants)["PI"] = F_PI;
|
mConstants["PI"] = F_PI;
|
||||||
(*mConstants)["TWO_PI"] = F_TWO_PI;
|
mConstants["TWO_PI"] = F_TWO_PI;
|
||||||
(*mConstants)["PI_BY_TWO"] = F_PI_BY_TWO;
|
mConstants["PI_BY_TWO"] = F_PI_BY_TWO;
|
||||||
(*mConstants)["SQRT2"] = F_SQRT2;
|
mConstants["SQRT_TWO_PI"] = F_SQRT_TWO_PI;
|
||||||
(*mConstants)["DEG_TO_RAD"] = DEG_TO_RAD;
|
mConstants["SQRT2"] = F_SQRT2;
|
||||||
(*mConstants)["RAD_TO_DEG"] = RAD_TO_DEG;
|
mConstants["SQRT3"] = F_SQRT3;
|
||||||
(*mConstants)["GRAVITY"] = GRAVITY;
|
mConstants["DEG_TO_RAD"] = DEG_TO_RAD;
|
||||||
(*mConstants)["ALMOST_ZERO"] = F_ALMOST_ZERO;
|
mConstants["RAD_TO_DEG"] = RAD_TO_DEG;
|
||||||
(*mConstants)["ALMOST_ONE"] = F_ALMOST_ONE;
|
mConstants["GRAVITY"] = GRAVITY;
|
||||||
(*mConstants)["THE_ANSWER"] = 42;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
LLCalc::~LLCalc()
|
LLCalc::~LLCalc()
|
||||||
{
|
{
|
||||||
delete mConstants;
|
|
||||||
delete mVariables;
|
|
||||||
// delete mUserVariables;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//static
|
//static
|
||||||
@@ -94,17 +86,17 @@ LLCalc* LLCalc::getInstance()
|
|||||||
|
|
||||||
void LLCalc::setVar(const std::string& name, const F32& value)
|
void LLCalc::setVar(const std::string& name, const F32& value)
|
||||||
{
|
{
|
||||||
(*mVariables)[name] = value;
|
mVariables[name] = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
void LLCalc::clearVar(const std::string& name)
|
void LLCalc::clearVar(const std::string& name)
|
||||||
{
|
{
|
||||||
mVariables->erase(name);
|
mVariables.erase(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
void LLCalc::clearAllVariables()
|
void LLCalc::clearAllVariables()
|
||||||
{
|
{
|
||||||
mVariables->clear();
|
mVariables.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -123,7 +115,7 @@ bool LLCalc::evalString(const std::string& expression, F32& result)
|
|||||||
std::string expr_upper = expression;
|
std::string expr_upper = expression;
|
||||||
LLStringUtil::toUpper(expr_upper);
|
LLStringUtil::toUpper(expr_upper);
|
||||||
|
|
||||||
LLCalcParser calc(result, mConstants, mVariables);
|
LLCalcParser calc(result, &mConstants, &mVariables);
|
||||||
|
|
||||||
mLastErrorPos = 0;
|
mLastErrorPos = 0;
|
||||||
std::string::iterator start = expr_upper.begin();
|
std::string::iterator start = expr_upper.begin();
|
||||||
|
|||||||
@@ -69,8 +69,8 @@ public:
|
|||||||
private:
|
private:
|
||||||
std::string::size_type mLastErrorPos;
|
std::string::size_type mLastErrorPos;
|
||||||
|
|
||||||
calc_map_t* mConstants;
|
calc_map_t mConstants;
|
||||||
calc_map_t* mVariables;
|
calc_map_t mVariables;
|
||||||
|
|
||||||
// *TODO: Add support for storing user defined variables, and stored functions.
|
// *TODO: Add support for storing user defined variables, and stored functions.
|
||||||
// Will need UI work, and a means to save them between sessions.
|
// Will need UI work, and a means to save them between sessions.
|
||||||
|
|||||||
@@ -73,7 +73,9 @@ struct LLCalcParser : grammar<LLCalcParser>
|
|||||||
(str_p("SQRT") >> '(' >> expression[unary_func.value = bind(&LLCalcParser::_sqrt)(self,arg1)]) |
|
(str_p("SQRT") >> '(' >> expression[unary_func.value = bind(&LLCalcParser::_sqrt)(self,arg1)]) |
|
||||||
(str_p("LOG") >> '(' >> expression[unary_func.value = bind(&LLCalcParser::_log)(self,arg1)]) |
|
(str_p("LOG") >> '(' >> expression[unary_func.value = bind(&LLCalcParser::_log)(self,arg1)]) |
|
||||||
(str_p("EXP") >> '(' >> expression[unary_func.value = bind(&LLCalcParser::_exp)(self,arg1)]) |
|
(str_p("EXP") >> '(' >> expression[unary_func.value = bind(&LLCalcParser::_exp)(self,arg1)]) |
|
||||||
(str_p("ABS") >> '(' >> expression[unary_func.value = bind(&LLCalcParser::_fabs)(self,arg1)])
|
(str_p("ABS") >> '(' >> expression[unary_func.value = bind(&LLCalcParser::_fabs)(self,arg1)]) |
|
||||||
|
(str_p("FLR") >> '(' >> expression[unary_func.value = bind(&LLCalcParser::_floor)(self,arg1)]) |
|
||||||
|
(str_p("CEIL") >> '(' >> expression[unary_func.value = bind(&LLCalcParser::_ceil)(self,arg1)])
|
||||||
) >> assert_syntax(ch_p(')'))
|
) >> assert_syntax(ch_p(')'))
|
||||||
;
|
;
|
||||||
|
|
||||||
@@ -118,7 +120,8 @@ struct LLCalcParser : grammar<LLCalcParser>
|
|||||||
term =
|
term =
|
||||||
power[term.value = arg1] >>
|
power[term.value = arg1] >>
|
||||||
*(('*' >> assert_syntax(power[term.value *= arg1])) |
|
*(('*' >> assert_syntax(power[term.value *= arg1])) |
|
||||||
('/' >> assert_syntax(power[term.value /= arg1]))
|
('/' >> assert_syntax(power[term.value /= arg1])) |
|
||||||
|
('%' >> assert_syntax(power[term.value = bind(&fmodf)(term.value, arg1)]))
|
||||||
)
|
)
|
||||||
;
|
;
|
||||||
|
|
||||||
@@ -153,7 +156,9 @@ private:
|
|||||||
F32 _sqrt(const F32& a) const { return sqrt(a); }
|
F32 _sqrt(const F32& a) const { return sqrt(a); }
|
||||||
F32 _log(const F32& a) const { return log(a); }
|
F32 _log(const F32& a) const { return log(a); }
|
||||||
F32 _exp(const F32& a) const { return exp(a); }
|
F32 _exp(const F32& a) const { return exp(a); }
|
||||||
F32 _fabs(const F32& a) const { return fabs(a) * RAD_TO_DEG; }
|
F32 _fabs(const F32& a) const { return fabs(a); }
|
||||||
|
F32 _floor(const F32& a) const { return llfloor(a); }
|
||||||
|
F32 _ceil(const F32& a) const { return llceil(a); }
|
||||||
|
|
||||||
F32 _atan2(const F32& a,const F32& b) const { return atan2(a,b); }
|
F32 _atan2(const F32& a,const F32& b) const { return atan2(a,b); }
|
||||||
|
|
||||||
|
|||||||
@@ -92,7 +92,7 @@ F32 LLCamera::getMaxView() const
|
|||||||
|
|
||||||
// ---------------- LLCamera::setFoo() member functions ----------------
|
// ---------------- LLCamera::setFoo() member functions ----------------
|
||||||
|
|
||||||
void LLCamera::setUserClipPlane(LLPlane const& plane)
|
void LLCamera::setUserClipPlane(const LLPlane& plane)
|
||||||
{
|
{
|
||||||
mPlaneCount = 7;
|
mPlaneCount = 7;
|
||||||
mAgentPlanes[6] = plane;
|
mAgentPlanes[6] = plane;
|
||||||
@@ -168,166 +168,91 @@ size_t LLCamera::readFrustumFromBuffer(const char *buffer)
|
|||||||
|
|
||||||
// ---------------- test methods ----------------
|
// ---------------- test methods ----------------
|
||||||
|
|
||||||
S32 LLCamera::AABBInFrustum(const LLVector3 ¢er, const LLVector3& radius)
|
S32 LLCamera::AABBInFrustum(const LLVector4a ¢er, const LLVector4a& radius)
|
||||||
{
|
{
|
||||||
static const LLVector3 scaler[] = {
|
static const LLVector4a scaler[] = {
|
||||||
LLVector3(-1,-1,-1),
|
LLVector4a(-1,-1,-1),
|
||||||
LLVector3( 1,-1,-1),
|
LLVector4a( 1,-1,-1),
|
||||||
LLVector3(-1, 1,-1),
|
LLVector4a(-1, 1,-1),
|
||||||
LLVector3( 1, 1,-1),
|
LLVector4a( 1, 1,-1),
|
||||||
LLVector3(-1,-1, 1),
|
LLVector4a(-1,-1, 1),
|
||||||
LLVector3( 1,-1, 1),
|
LLVector4a( 1,-1, 1),
|
||||||
LLVector3(-1, 1, 1),
|
LLVector4a(-1, 1, 1),
|
||||||
LLVector3( 1, 1, 1)
|
LLVector4a( 1, 1, 1)
|
||||||
};
|
};
|
||||||
|
|
||||||
U8 mask = 0;
|
U8 mask = 0;
|
||||||
S32 result = 2;
|
bool result = false;
|
||||||
|
LLVector4a rscale, maxp, minp;
|
||||||
/*if (radius.magVecSquared() > mFrustumCornerDist * mFrustumCornerDist)
|
LLSimdScalar d;
|
||||||
{ //box is larger than frustum, check frustum quads against box planes
|
for (U32 i = 0; i < mPlaneCount; i++)
|
||||||
|
|
||||||
static const LLVector3 dir[] =
|
|
||||||
{
|
|
||||||
LLVector3(1, 0, 0),
|
|
||||||
LLVector3(-1, 0, 0),
|
|
||||||
LLVector3(0, 1, 0),
|
|
||||||
LLVector3(0, -1, 0),
|
|
||||||
LLVector3(0, 0, 1),
|
|
||||||
LLVector3(0, 0, -1)
|
|
||||||
};
|
|
||||||
|
|
||||||
U32 quads[] =
|
|
||||||
{
|
|
||||||
0, 1, 2, 3,
|
|
||||||
0, 1, 5, 4,
|
|
||||||
2, 3, 7, 6,
|
|
||||||
3, 0, 7, 4,
|
|
||||||
1, 2, 6, 4,
|
|
||||||
4, 5, 6, 7
|
|
||||||
};
|
|
||||||
|
|
||||||
result = 0;
|
|
||||||
|
|
||||||
BOOL total_inside = TRUE;
|
|
||||||
for (U32 i = 0; i < 6; i++)
|
|
||||||
{
|
|
||||||
LLVector3 p = center + radius.scaledVec(dir[i]);
|
|
||||||
F32 d = -p*dir[i];
|
|
||||||
|
|
||||||
for (U32 j = 0; j < 6; j++)
|
|
||||||
{ //for each quad
|
|
||||||
F32 dist = mAgentFrustum[quads[j*4+0]]*dir[i] + d;
|
|
||||||
if (dist > 0)
|
|
||||||
{ //at least one frustum point is outside the AABB
|
|
||||||
total_inside = FALSE;
|
|
||||||
for (U32 k = 1; k < 4; k++)
|
|
||||||
{ //for each other point on quad
|
|
||||||
if ( mAgentFrustum[quads[j*4+k]]*dir[i]+d <= 0.f)
|
|
||||||
{ //quad is straddling some plane of AABB
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
for (U32 k = 1; k < 4; k++)
|
|
||||||
{
|
|
||||||
if (mAgentFrustum[quads[j*4+k]]*dir[i]+d > 0.f)
|
|
||||||
{
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (total_inside)
|
|
||||||
{
|
|
||||||
result = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else*/
|
|
||||||
{
|
{
|
||||||
for (U32 i = 0; i < mPlaneCount; i++)
|
mask = mPlaneMask[i];
|
||||||
|
if (mask != 0xff)
|
||||||
{
|
{
|
||||||
mask = mPlaneMask[i];
|
const LLPlane& p(mAgentPlanes[i]);
|
||||||
if (mask == 0xff)
|
p.getAt<3>(d);
|
||||||
{
|
rscale.setMul(radius, scaler[mask]);
|
||||||
continue;
|
minp.setSub(center, rscale);
|
||||||
}
|
d = -d;
|
||||||
LLPlane p = mAgentPlanes[i];
|
if (p.dot3(minp).getF32() > d)
|
||||||
LLVector3 n = LLVector3(p);
|
|
||||||
float d = p.mV[3];
|
|
||||||
LLVector3 rscale = radius.scaledVec(scaler[mask]);
|
|
||||||
|
|
||||||
LLVector3 minp = center - rscale;
|
|
||||||
LLVector3 maxp = center + rscale;
|
|
||||||
|
|
||||||
if (n * minp > -d)
|
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (n * maxp > -d)
|
if(!result)
|
||||||
{
|
{
|
||||||
result = 1;
|
maxp.setAdd(center, rscale);
|
||||||
|
result = (p.dot3(maxp).getF32() > d);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return result?1:2;
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
S32 LLCamera::AABBInFrustumNoFarClip(const LLVector3 ¢er, const LLVector3& radius)
|
|
||||||
|
S32 LLCamera::AABBInFrustumNoFarClip(const LLVector4a& center, const LLVector4a& radius)
|
||||||
{
|
{
|
||||||
static const LLVector3 scaler[] = {
|
static const LLVector4a scaler[] = {
|
||||||
LLVector3(-1,-1,-1),
|
LLVector4a(-1,-1,-1),
|
||||||
LLVector3( 1,-1,-1),
|
LLVector4a( 1,-1,-1),
|
||||||
LLVector3(-1, 1,-1),
|
LLVector4a(-1, 1,-1),
|
||||||
LLVector3( 1, 1,-1),
|
LLVector4a( 1, 1,-1),
|
||||||
LLVector3(-1,-1, 1),
|
LLVector4a(-1,-1, 1),
|
||||||
LLVector3( 1,-1, 1),
|
LLVector4a( 1,-1, 1),
|
||||||
LLVector3(-1, 1, 1),
|
LLVector4a(-1, 1, 1),
|
||||||
LLVector3( 1, 1, 1)
|
LLVector4a( 1, 1, 1)
|
||||||
};
|
};
|
||||||
|
|
||||||
U8 mask = 0;
|
U8 mask = 0;
|
||||||
S32 result = 2;
|
bool result = false;
|
||||||
|
LLVector4a rscale, maxp, minp;
|
||||||
|
LLSimdScalar d;
|
||||||
for (U32 i = 0; i < mPlaneCount; i++)
|
for (U32 i = 0; i < mPlaneCount; i++)
|
||||||
{
|
{
|
||||||
if (i == 5)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
mask = mPlaneMask[i];
|
mask = mPlaneMask[i];
|
||||||
if (mask == 0xff)
|
if ((i != 5) && (mask != 0xff))
|
||||||
{
|
{
|
||||||
continue;
|
const LLPlane& p(mAgentPlanes[i]);
|
||||||
}
|
p.getAt<3>(d);
|
||||||
LLPlane p = mAgentPlanes[i];
|
rscale.setMul(radius, scaler[mask]);
|
||||||
LLVector3 n = LLVector3(p);
|
minp.setSub(center, rscale);
|
||||||
float d = p.mV[3];
|
d = -d;
|
||||||
LLVector3 rscale = radius.scaledVec(scaler[mask]);
|
if (p.dot3(minp).getF32() > d)
|
||||||
|
{
|
||||||
LLVector3 minp = center - rscale;
|
return 0;
|
||||||
LLVector3 maxp = center + rscale;
|
}
|
||||||
|
|
||||||
if (n * minp > -d)
|
if(!result)
|
||||||
{
|
{
|
||||||
return 0;
|
maxp.setAdd(center, rscale);
|
||||||
}
|
result = (p.dot3(maxp).getF32() > d);
|
||||||
|
}
|
||||||
if (n * maxp > -d)
|
|
||||||
{
|
|
||||||
result = 1;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result?1:2;
|
||||||
}
|
}
|
||||||
|
|
||||||
int LLCamera::sphereInFrustumQuick(const LLVector3 &sphere_center, const F32 radius)
|
int LLCamera::sphereInFrustumQuick(const LLVector3 &sphere_center, const F32 radius)
|
||||||
@@ -715,9 +640,10 @@ void LLCamera::calculateWorldFrustumPlanes()
|
|||||||
F32 d;
|
F32 d;
|
||||||
LLVector3 center = mOrigin - mXAxis*mNearPlane;
|
LLVector3 center = mOrigin - mXAxis*mNearPlane;
|
||||||
mWorldPlanePos = center;
|
mWorldPlanePos = center;
|
||||||
|
LLVector3 pnorm;
|
||||||
for (int p=0; p<4; p++)
|
for (int p=0; p<4; p++)
|
||||||
{
|
{
|
||||||
LLVector3 pnorm = LLVector3(mLocalPlanes[p]);
|
mLocalPlanes[p].getVector3(pnorm);
|
||||||
LLVector3 norm = rotateToAbsolute(pnorm);
|
LLVector3 norm = rotateToAbsolute(pnorm);
|
||||||
norm.normVec();
|
norm.normVec();
|
||||||
d = -(center * norm);
|
d = -(center * norm);
|
||||||
@@ -727,13 +653,15 @@ void LLCamera::calculateWorldFrustumPlanes()
|
|||||||
LLVector3 zaxis(0, 0, 1.0f);
|
LLVector3 zaxis(0, 0, 1.0f);
|
||||||
F32 yaw = getYaw();
|
F32 yaw = getYaw();
|
||||||
{
|
{
|
||||||
LLVector3 tnorm = LLVector3(mLocalPlanes[PLANE_LEFT]);
|
LLVector3 tnorm;
|
||||||
|
mLocalPlanes[PLANE_LEFT].getVector3(tnorm);
|
||||||
tnorm.rotVec(yaw, zaxis);
|
tnorm.rotVec(yaw, zaxis);
|
||||||
d = -(mOrigin * tnorm);
|
d = -(mOrigin * tnorm);
|
||||||
mHorizPlanes[HORIZ_PLANE_LEFT] = LLPlane(tnorm, d);
|
mHorizPlanes[HORIZ_PLANE_LEFT] = LLPlane(tnorm, d);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
LLVector3 tnorm = LLVector3(mLocalPlanes[PLANE_RIGHT]);
|
LLVector3 tnorm;
|
||||||
|
mLocalPlanes[PLANE_RIGHT].getVector3(tnorm);
|
||||||
tnorm.rotVec(yaw, zaxis);
|
tnorm.rotVec(yaw, zaxis);
|
||||||
d = -(mOrigin * tnorm);
|
d = -(mOrigin * tnorm);
|
||||||
mHorizPlanes[HORIZ_PLANE_RIGHT] = LLPlane(tnorm, d);
|
mHorizPlanes[HORIZ_PLANE_RIGHT] = LLPlane(tnorm, d);
|
||||||
|
|||||||
@@ -37,6 +37,7 @@
|
|||||||
#include "llmath.h"
|
#include "llmath.h"
|
||||||
#include "llcoordframe.h"
|
#include "llcoordframe.h"
|
||||||
#include "llplane.h"
|
#include "llplane.h"
|
||||||
|
#include "llvector4a.h"
|
||||||
|
|
||||||
const F32 DEFAULT_FIELD_OF_VIEW = 60.f * DEG_TO_RAD;
|
const F32 DEFAULT_FIELD_OF_VIEW = 60.f * DEG_TO_RAD;
|
||||||
const F32 DEFAULT_ASPECT_RATIO = 640.f / 480.f;
|
const F32 DEFAULT_ASPECT_RATIO = 640.f / 480.f;
|
||||||
@@ -143,7 +144,7 @@ public:
|
|||||||
virtual ~LLCamera();
|
virtual ~LLCamera();
|
||||||
|
|
||||||
|
|
||||||
void setUserClipPlane(LLPlane const& plane);
|
void setUserClipPlane(const LLPlane& plane);
|
||||||
void disableUserClipPlane();
|
void disableUserClipPlane();
|
||||||
virtual void setView(F32 vertical_fov_rads);
|
virtual void setView(F32 vertical_fov_rads);
|
||||||
void setViewHeightInPixels(S32 height);
|
void setViewHeightInPixels(S32 height);
|
||||||
@@ -191,8 +192,8 @@ public:
|
|||||||
S32 sphereInFrustum(const LLVector3 ¢er, const F32 radius) const;
|
S32 sphereInFrustum(const LLVector3 ¢er, const F32 radius) const;
|
||||||
S32 pointInFrustum(const LLVector3 &point) const { return sphereInFrustum(point, 0.0f); }
|
S32 pointInFrustum(const LLVector3 &point) const { return sphereInFrustum(point, 0.0f); }
|
||||||
S32 sphereInFrustumFull(const LLVector3 ¢er, const F32 radius) const { return sphereInFrustum(center, radius); }
|
S32 sphereInFrustumFull(const LLVector3 ¢er, const F32 radius) const { return sphereInFrustum(center, radius); }
|
||||||
S32 AABBInFrustum(const LLVector3 ¢er, const LLVector3& radius);
|
S32 AABBInFrustum(const LLVector4a& center, const LLVector4a& radius);
|
||||||
S32 AABBInFrustumNoFarClip(const LLVector3 ¢er, const LLVector3& radius);
|
S32 AABBInFrustumNoFarClip(const LLVector4a& center, const LLVector4a& radius);
|
||||||
|
|
||||||
//does a quick 'n dirty sphere-sphere check
|
//does a quick 'n dirty sphere-sphere check
|
||||||
S32 sphereInFrustumQuick(const LLVector3 &sphere_center, const F32 radius);
|
S32 sphereInFrustumQuick(const LLVector3 &sphere_center, const F32 radius);
|
||||||
|
|||||||
@@ -38,6 +38,7 @@
|
|||||||
// So, let's define _USE_MATH_DEFINES before including math.h
|
// So, let's define _USE_MATH_DEFINES before including math.h
|
||||||
#define _USE_MATH_DEFINES
|
#define _USE_MATH_DEFINES
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "math.h"
|
#include "math.h"
|
||||||
|
|
||||||
// Class from which different types of interpolators can be derived
|
// Class from which different types of interpolators can be derived
|
||||||
|
|||||||
@@ -35,10 +35,10 @@
|
|||||||
|
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <complex>
|
#include <vector>
|
||||||
#include "lldefs.h"
|
#include "lldefs.h"
|
||||||
#include "llstl.h" // *TODO: Remove when LLString is gone
|
//#include "llstl.h" // *TODO: Remove when LLString is gone
|
||||||
#include "llstring.h" // *TODO: Remove when LLString is gone
|
//#include "llstring.h" // *TODO: Remove when LLString is gone
|
||||||
// lltut.h uses is_approx_equal_fraction(). This was moved to its own header
|
// lltut.h uses is_approx_equal_fraction(). This was moved to its own header
|
||||||
// file in llcommon so we can use lltut.h for llcommon tests without making
|
// file in llcommon so we can use lltut.h for llcommon tests without making
|
||||||
// llcommon depend on llmath.
|
// llcommon depend on llmath.
|
||||||
@@ -61,32 +61,11 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Single Precision Floating Point Routines
|
// Single Precision Floating Point Routines
|
||||||
#ifndef sqrtf
|
// (There used to be more defined here, but they appeared to be redundant and
|
||||||
#define sqrtf(x) ((F32)sqrt((F64)(x)))
|
// were breaking some other includes. Removed by Falcon, reviewed by Andrew, 11/25/09)
|
||||||
#endif
|
/*#ifndef tanf
|
||||||
#ifndef fsqrtf
|
|
||||||
#define fsqrtf(x) sqrtf(x)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef cosf
|
|
||||||
#define cosf(x) ((F32)cos((F64)(x)))
|
|
||||||
#endif
|
|
||||||
#ifndef sinf
|
|
||||||
#define sinf(x) ((F32)sin((F64)(x)))
|
|
||||||
#endif
|
|
||||||
#ifndef tanf
|
|
||||||
#define tanf(x) ((F32)tan((F64)(x)))
|
#define tanf(x) ((F32)tan((F64)(x)))
|
||||||
#endif
|
#endif*/
|
||||||
#ifndef acosf
|
|
||||||
#define acosf(x) ((F32)acos((F64)(x)))
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef powf
|
|
||||||
#define powf(x,y) ((F32)pow((F64)(x),(F64)(y)))
|
|
||||||
#endif
|
|
||||||
#ifndef expf
|
|
||||||
#define expf(x) ((F32)exp((F64)(x)))
|
|
||||||
#endif
|
|
||||||
|
|
||||||
const F32 GRAVITY = -9.8f;
|
const F32 GRAVITY = -9.8f;
|
||||||
|
|
||||||
@@ -206,7 +185,7 @@ inline S32 llfloor( F32 f )
|
|||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
#else
|
#else
|
||||||
return (S32)floorf(f);
|
return (S32)floor(f);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -537,6 +516,12 @@ inline void ll_remove_outliers(std::vector<VEC_TYPE>& data, F32 k)
|
|||||||
VEC_TYPE Q1 = data[data.size()/4];
|
VEC_TYPE Q1 = data[data.size()/4];
|
||||||
VEC_TYPE Q3 = data[data.size()-data.size()/4-1];
|
VEC_TYPE Q3 = data[data.size()-data.size()/4-1];
|
||||||
|
|
||||||
|
if ((F32)(Q3-Q1) < 1.f)
|
||||||
|
{
|
||||||
|
// not enough variation to detect outliers
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
VEC_TYPE min = (VEC_TYPE) ((F32) Q1-k * (F32) (Q3-Q1));
|
VEC_TYPE min = (VEC_TYPE) ((F32) Q1-k * (F32) (Q3-Q1));
|
||||||
VEC_TYPE max = (VEC_TYPE) ((F32) Q3+k * (F32) (Q3-Q1));
|
VEC_TYPE max = (VEC_TYPE) ((F32) Q3+k * (F32) (Q3-Q1));
|
||||||
|
|
||||||
@@ -562,4 +547,7 @@ inline void ll_remove_outliers(std::vector<VEC_TYPE>& data, F32 k)
|
|||||||
data.erase(data.begin(), data.begin()+i);
|
data.erase(data.begin(), data.begin()+i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Include simd math header
|
||||||
|
#include "llsimdmath.h"
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
134
indra/llmath/llmatrix3a.cpp
Normal file
134
indra/llmath/llmatrix3a.cpp
Normal file
@@ -0,0 +1,134 @@
|
|||||||
|
/**
|
||||||
|
* @file llvector4a.cpp
|
||||||
|
* @brief SIMD vector implementation
|
||||||
|
*
|
||||||
|
* $LicenseInfo:firstyear=2010&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 "llmath.h"
|
||||||
|
|
||||||
|
static LL_ALIGN_16(const F32 M_IDENT_3A[12]) =
|
||||||
|
{ 1.f, 0.f, 0.f, 0.f, // Column 1
|
||||||
|
0.f, 1.f, 0.f, 0.f, // Column 2
|
||||||
|
0.f, 0.f, 1.f, 0.f }; // Column 3
|
||||||
|
|
||||||
|
extern const LLMatrix3a LL_M3A_IDENTITY = *reinterpret_cast<const LLMatrix3a*> (M_IDENT_3A);
|
||||||
|
|
||||||
|
void LLMatrix3a::setMul( const LLMatrix3a& lhs, const LLMatrix3a& rhs )
|
||||||
|
{
|
||||||
|
const LLVector4a col0 = lhs.getColumn(0);
|
||||||
|
const LLVector4a col1 = lhs.getColumn(1);
|
||||||
|
const LLVector4a col2 = lhs.getColumn(2);
|
||||||
|
|
||||||
|
for ( int i = 0; i < 3; i++ )
|
||||||
|
{
|
||||||
|
LLVector4a xxxx = _mm_load_ss( rhs.mColumns[i].getF32ptr() );
|
||||||
|
xxxx.splat<0>( xxxx );
|
||||||
|
xxxx.mul( col0 );
|
||||||
|
|
||||||
|
{
|
||||||
|
LLVector4a yyyy = _mm_load_ss( rhs.mColumns[i].getF32ptr() + 1 );
|
||||||
|
yyyy.splat<0>( yyyy );
|
||||||
|
yyyy.mul( col1 );
|
||||||
|
xxxx.add( yyyy );
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
LLVector4a zzzz = _mm_load_ss( rhs.mColumns[i].getF32ptr() + 2 );
|
||||||
|
zzzz.splat<0>( zzzz );
|
||||||
|
zzzz.mul( col2 );
|
||||||
|
xxxx.add( zzzz );
|
||||||
|
}
|
||||||
|
|
||||||
|
xxxx.store4a( mColumns[i].getF32ptr() );
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/*static */void LLMatrix3a::batchTransform( const LLMatrix3a& xform, const LLVector4a* src, int numVectors, LLVector4a* dst )
|
||||||
|
{
|
||||||
|
const LLVector4a col0 = xform.getColumn(0);
|
||||||
|
const LLVector4a col1 = xform.getColumn(1);
|
||||||
|
const LLVector4a col2 = xform.getColumn(2);
|
||||||
|
const LLVector4a* maxAddr = src + numVectors;
|
||||||
|
|
||||||
|
if ( numVectors & 0x1 )
|
||||||
|
{
|
||||||
|
LLVector4a xxxx = _mm_load_ss( (const F32*)src );
|
||||||
|
LLVector4a yyyy = _mm_load_ss( (const F32*)src + 1 );
|
||||||
|
LLVector4a zzzz = _mm_load_ss( (const F32*)src + 2 );
|
||||||
|
xxxx.splat<0>( xxxx );
|
||||||
|
yyyy.splat<0>( yyyy );
|
||||||
|
zzzz.splat<0>( zzzz );
|
||||||
|
xxxx.mul( col0 );
|
||||||
|
yyyy.mul( col1 );
|
||||||
|
zzzz.mul( col2 );
|
||||||
|
xxxx.add( yyyy );
|
||||||
|
xxxx.add( zzzz );
|
||||||
|
xxxx.store4a( (F32*)dst );
|
||||||
|
src++;
|
||||||
|
dst++;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
numVectors >>= 1;
|
||||||
|
while ( src < maxAddr )
|
||||||
|
{
|
||||||
|
_mm_prefetch( (const char*)(src + 32 ), _MM_HINT_NTA );
|
||||||
|
_mm_prefetch( (const char*)(dst + 32), _MM_HINT_NTA );
|
||||||
|
LLVector4a xxxx = _mm_load_ss( (const F32*)src );
|
||||||
|
LLVector4a xxxx1= _mm_load_ss( (const F32*)(src + 1) );
|
||||||
|
|
||||||
|
xxxx.splat<0>( xxxx );
|
||||||
|
xxxx1.splat<0>( xxxx1 );
|
||||||
|
xxxx.mul( col0 );
|
||||||
|
xxxx1.mul( col0 );
|
||||||
|
|
||||||
|
{
|
||||||
|
LLVector4a yyyy = _mm_load_ss( (const F32*)src + 1 );
|
||||||
|
LLVector4a yyyy1 = _mm_load_ss( (const F32*)(src + 1) + 1);
|
||||||
|
yyyy.splat<0>( yyyy );
|
||||||
|
yyyy1.splat<0>( yyyy1 );
|
||||||
|
yyyy.mul( col1 );
|
||||||
|
yyyy1.mul( col1 );
|
||||||
|
xxxx.add( yyyy );
|
||||||
|
xxxx1.add( yyyy1 );
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
LLVector4a zzzz = _mm_load_ss( (const F32*)(src) + 2 );
|
||||||
|
LLVector4a zzzz1 = _mm_load_ss( (const F32*)(++src) + 2 );
|
||||||
|
zzzz.splat<0>( zzzz );
|
||||||
|
zzzz1.splat<0>( zzzz1 );
|
||||||
|
zzzz.mul( col2 );
|
||||||
|
zzzz1.mul( col2 );
|
||||||
|
xxxx.add( zzzz );
|
||||||
|
xxxx1.add( zzzz1 );
|
||||||
|
}
|
||||||
|
|
||||||
|
xxxx.store4a(dst->getF32ptr());
|
||||||
|
src++;
|
||||||
|
dst++;
|
||||||
|
|
||||||
|
xxxx1.store4a((F32*)dst++);
|
||||||
|
}
|
||||||
|
}
|
||||||
128
indra/llmath/llmatrix3a.h
Normal file
128
indra/llmath/llmatrix3a.h
Normal file
@@ -0,0 +1,128 @@
|
|||||||
|
/**
|
||||||
|
* @file llmatrix3a.h
|
||||||
|
* @brief LLMatrix3a class header file - memory aligned and vectorized 3x3 matrix
|
||||||
|
*
|
||||||
|
* $LicenseInfo:firstyear=2010&license=viewerlgpl$
|
||||||
|
* Second Life Viewer Source Code
|
||||||
|
* Copyright (C) 2010, Linden Research, Inc.
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation;
|
||||||
|
* version 2.1 of the License only.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*
|
||||||
|
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||||
|
* $/LicenseInfo$
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef LL_LLMATRIX3A_H
|
||||||
|
#define LL_LLMATRIX3A_H
|
||||||
|
|
||||||
|
/////////////////////////////
|
||||||
|
// LLMatrix3a, LLRotation
|
||||||
|
/////////////////////////////
|
||||||
|
// This class stores a 3x3 (technically 4x3) matrix in column-major order
|
||||||
|
/////////////////////////////
|
||||||
|
/////////////////////////////
|
||||||
|
// These classes are intentionally minimal right now. If you need additional
|
||||||
|
// functionality, please contact someone with SSE experience (e.g., Falcon or
|
||||||
|
// Huseby).
|
||||||
|
/////////////////////////////
|
||||||
|
|
||||||
|
// LLMatrix3a is the base class for LLRotation, which should be used instead any time you're dealing with a
|
||||||
|
// rotation matrix.
|
||||||
|
class LLMatrix3a
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
// Utility function for quickly transforming an array of LLVector4a's
|
||||||
|
// For transforming a single LLVector4a, see LLVector4a::setRotated
|
||||||
|
static void batchTransform( const LLMatrix3a& xform, const LLVector4a* src, int numVectors, LLVector4a* dst );
|
||||||
|
|
||||||
|
// Utility function to obtain the identity matrix
|
||||||
|
static inline const LLMatrix3a& getIdentity();
|
||||||
|
|
||||||
|
//////////////////////////
|
||||||
|
// Ctors
|
||||||
|
//////////////////////////
|
||||||
|
|
||||||
|
// Ctor
|
||||||
|
LLMatrix3a() {}
|
||||||
|
|
||||||
|
// Ctor for setting by columns
|
||||||
|
inline LLMatrix3a( const LLVector4a& c0, const LLVector4a& c1, const LLVector4a& c2 );
|
||||||
|
|
||||||
|
//////////////////////////
|
||||||
|
// Get/Set
|
||||||
|
//////////////////////////
|
||||||
|
|
||||||
|
// Loads from an LLMatrix3
|
||||||
|
inline void loadu(const LLMatrix3& src);
|
||||||
|
|
||||||
|
// Set rows
|
||||||
|
inline void setRows(const LLVector4a& r0, const LLVector4a& r1, const LLVector4a& r2);
|
||||||
|
|
||||||
|
// Set columns
|
||||||
|
inline void setColumns(const LLVector4a& c0, const LLVector4a& c1, const LLVector4a& c2);
|
||||||
|
|
||||||
|
// Get the read-only access to a specified column. Valid columns are 0-2, but the
|
||||||
|
// function is unchecked. You've been warned.
|
||||||
|
inline const LLVector4a& getColumn(const U32 column) const;
|
||||||
|
|
||||||
|
/////////////////////////
|
||||||
|
// Matrix modification
|
||||||
|
/////////////////////////
|
||||||
|
|
||||||
|
// Set this matrix to the product of lhs and rhs ( this = lhs * rhs )
|
||||||
|
void setMul( const LLMatrix3a& lhs, const LLMatrix3a& rhs );
|
||||||
|
|
||||||
|
// Set this matrix to the transpose of src
|
||||||
|
inline void setTranspose(const LLMatrix3a& src);
|
||||||
|
|
||||||
|
// Set this matrix to a*w + b*(1-w)
|
||||||
|
inline void setLerp(const LLMatrix3a& a, const LLMatrix3a& b, F32 w);
|
||||||
|
|
||||||
|
/////////////////////////
|
||||||
|
// Matrix inspection
|
||||||
|
/////////////////////////
|
||||||
|
|
||||||
|
// Sets all 4 elements in 'dest' to the determinant of this matrix.
|
||||||
|
// If you will be using the determinant in subsequent ops with LLVector4a, use this version
|
||||||
|
inline void getDeterminant( LLVector4a& dest ) const;
|
||||||
|
|
||||||
|
// Returns the determinant as an LLSimdScalar. Use this if you will be using the determinant
|
||||||
|
// primary for scalar operations.
|
||||||
|
inline LLSimdScalar getDeterminant() const;
|
||||||
|
|
||||||
|
// Returns nonzero if rows 0-2 and colums 0-2 contain no NaN or INF values. Row 3 is ignored
|
||||||
|
inline LLBool32 isFinite() const;
|
||||||
|
|
||||||
|
// Returns true if this matrix is equal to 'rhs' up to 'tolerance'
|
||||||
|
inline bool isApproximatelyEqual( const LLMatrix3a& rhs, F32 tolerance = F_APPROXIMATELY_ZERO ) const;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
LLVector4a mColumns[3];
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
class LLRotation : public LLMatrix3a
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
LLRotation() {}
|
||||||
|
|
||||||
|
// Returns true if this rotation is orthonormal with det ~= 1
|
||||||
|
inline bool isOkRotation() const;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
119
indra/llmath/llmatrix3a.inl
Normal file
119
indra/llmath/llmatrix3a.inl
Normal file
@@ -0,0 +1,119 @@
|
|||||||
|
/**
|
||||||
|
* @file llmatrix3a.inl
|
||||||
|
* @brief LLMatrix3a inline definitions
|
||||||
|
*
|
||||||
|
* $LicenseInfo:firstyear=2010&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 "llmatrix3a.h"
|
||||||
|
#include "m3math.h"
|
||||||
|
|
||||||
|
inline LLMatrix3a::LLMatrix3a( const LLVector4a& c0, const LLVector4a& c1, const LLVector4a& c2 )
|
||||||
|
{
|
||||||
|
setColumns( c0, c1, c2 );
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void LLMatrix3a::loadu(const LLMatrix3& src)
|
||||||
|
{
|
||||||
|
mColumns[0].load3(src.mMatrix[0]);
|
||||||
|
mColumns[1].load3(src.mMatrix[1]);
|
||||||
|
mColumns[2].load3(src.mMatrix[2]);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void LLMatrix3a::setRows(const LLVector4a& r0, const LLVector4a& r1, const LLVector4a& r2)
|
||||||
|
{
|
||||||
|
mColumns[0] = r0;
|
||||||
|
mColumns[1] = r1;
|
||||||
|
mColumns[2] = r2;
|
||||||
|
setTranspose( *this );
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void LLMatrix3a::setColumns(const LLVector4a& c0, const LLVector4a& c1, const LLVector4a& c2)
|
||||||
|
{
|
||||||
|
mColumns[0] = c0;
|
||||||
|
mColumns[1] = c1;
|
||||||
|
mColumns[2] = c2;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void LLMatrix3a::setTranspose(const LLMatrix3a& src)
|
||||||
|
{
|
||||||
|
const LLQuad srcCol0 = src.mColumns[0];
|
||||||
|
const LLQuad srcCol1 = src.mColumns[1];
|
||||||
|
const LLQuad unpacklo = _mm_unpacklo_ps( srcCol0, srcCol1 );
|
||||||
|
mColumns[0] = _mm_movelh_ps( unpacklo, src.mColumns[2] );
|
||||||
|
mColumns[1] = _mm_shuffle_ps( _mm_movehl_ps( srcCol0, unpacklo ), src.mColumns[2], _MM_SHUFFLE(0, 1, 1, 0) );
|
||||||
|
mColumns[2] = _mm_shuffle_ps( _mm_unpackhi_ps( srcCol0, srcCol1 ), src.mColumns[2], _MM_SHUFFLE(0, 2, 1, 0) );
|
||||||
|
}
|
||||||
|
|
||||||
|
inline const LLVector4a& LLMatrix3a::getColumn(const U32 column) const
|
||||||
|
{
|
||||||
|
llassert( column < 3 );
|
||||||
|
return mColumns[column];
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void LLMatrix3a::setLerp(const LLMatrix3a& a, const LLMatrix3a& b, F32 w)
|
||||||
|
{
|
||||||
|
mColumns[0].setLerp( a.mColumns[0], b.mColumns[0], w );
|
||||||
|
mColumns[1].setLerp( a.mColumns[1], b.mColumns[1], w );
|
||||||
|
mColumns[2].setLerp( a.mColumns[2], b.mColumns[2], w );
|
||||||
|
}
|
||||||
|
|
||||||
|
inline LLBool32 LLMatrix3a::isFinite() const
|
||||||
|
{
|
||||||
|
return mColumns[0].isFinite3() && mColumns[1].isFinite3() && mColumns[2].isFinite3();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void LLMatrix3a::getDeterminant( LLVector4a& dest ) const
|
||||||
|
{
|
||||||
|
LLVector4a col1xcol2; col1xcol2.setCross3( mColumns[1], mColumns[2] );
|
||||||
|
dest.setAllDot3( col1xcol2, mColumns[0] );
|
||||||
|
}
|
||||||
|
|
||||||
|
inline LLSimdScalar LLMatrix3a::getDeterminant() const
|
||||||
|
{
|
||||||
|
LLVector4a col1xcol2; col1xcol2.setCross3( mColumns[1], mColumns[2] );
|
||||||
|
return col1xcol2.dot3( mColumns[0] );
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool LLMatrix3a::isApproximatelyEqual( const LLMatrix3a& rhs, F32 tolerance /*= F_APPROXIMATELY_ZERO*/ ) const
|
||||||
|
{
|
||||||
|
return rhs.getColumn(0).equals3(mColumns[0], tolerance)
|
||||||
|
&& rhs.getColumn(1).equals3(mColumns[1], tolerance)
|
||||||
|
&& rhs.getColumn(2).equals3(mColumns[2], tolerance);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline const LLMatrix3a& LLMatrix3a::getIdentity()
|
||||||
|
{
|
||||||
|
extern const LLMatrix3a LL_M3A_IDENTITY;
|
||||||
|
return LL_M3A_IDENTITY;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool LLRotation::isOkRotation() const
|
||||||
|
{
|
||||||
|
LLMatrix3a transpose; transpose.setTranspose( *this );
|
||||||
|
LLMatrix3a product; product.setMul( *this, transpose );
|
||||||
|
|
||||||
|
LLSimdScalar detMinusOne = getDeterminant() - 1.f;
|
||||||
|
|
||||||
|
return product.isApproximatelyEqual( LLMatrix3a::getIdentity() ) && (detMinusOne.getAbs() < F_APPROXIMATELY_ZERO);
|
||||||
|
}
|
||||||
|
|
||||||
143
indra/llmath/llmatrix4a.h
Normal file
143
indra/llmath/llmatrix4a.h
Normal file
@@ -0,0 +1,143 @@
|
|||||||
|
/**
|
||||||
|
* @file llmatrix4a.h
|
||||||
|
* @brief LLMatrix4a class header file - memory aligned and vectorized 4x4 matrix
|
||||||
|
*
|
||||||
|
* $LicenseInfo:firstyear=2007&license=viewerlgpl$
|
||||||
|
* Second Life Viewer Source Code
|
||||||
|
* Copyright (C) 2010, Linden Research, Inc.
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation;
|
||||||
|
* version 2.1 of the License only.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*
|
||||||
|
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||||
|
* $/LicenseInfo$
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef LL_LLMATRIX4A_H
|
||||||
|
#define LL_LLMATRIX4A_H
|
||||||
|
|
||||||
|
#include "llvector4a.h"
|
||||||
|
#include "m4math.h"
|
||||||
|
#include "m3math.h"
|
||||||
|
|
||||||
|
class LLMatrix4a
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
LLVector4a mMatrix[4];
|
||||||
|
|
||||||
|
inline void clear()
|
||||||
|
{
|
||||||
|
mMatrix[0].clear();
|
||||||
|
mMatrix[1].clear();
|
||||||
|
mMatrix[2].clear();
|
||||||
|
mMatrix[3].clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void loadu(const LLMatrix4& src)
|
||||||
|
{
|
||||||
|
mMatrix[0] = _mm_loadu_ps(src.mMatrix[0]);
|
||||||
|
mMatrix[1] = _mm_loadu_ps(src.mMatrix[1]);
|
||||||
|
mMatrix[2] = _mm_loadu_ps(src.mMatrix[2]);
|
||||||
|
mMatrix[3] = _mm_loadu_ps(src.mMatrix[3]);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void loadu(const LLMatrix3& src)
|
||||||
|
{
|
||||||
|
mMatrix[0].load3(src.mMatrix[0]);
|
||||||
|
mMatrix[1].load3(src.mMatrix[1]);
|
||||||
|
mMatrix[2].load3(src.mMatrix[2]);
|
||||||
|
mMatrix[3].set(0,0,0,1.f);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void add(const LLMatrix4a& rhs)
|
||||||
|
{
|
||||||
|
mMatrix[0].add(rhs.mMatrix[0]);
|
||||||
|
mMatrix[1].add(rhs.mMatrix[1]);
|
||||||
|
mMatrix[2].add(rhs.mMatrix[2]);
|
||||||
|
mMatrix[3].add(rhs.mMatrix[3]);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void setRows(const LLVector4a& r0, const LLVector4a& r1, const LLVector4a& r2)
|
||||||
|
{
|
||||||
|
mMatrix[0] = r0;
|
||||||
|
mMatrix[1] = r1;
|
||||||
|
mMatrix[2] = r2;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void setMul(const LLMatrix4a& m, const F32 s)
|
||||||
|
{
|
||||||
|
mMatrix[0].setMul(m.mMatrix[0], s);
|
||||||
|
mMatrix[1].setMul(m.mMatrix[1], s);
|
||||||
|
mMatrix[2].setMul(m.mMatrix[2], s);
|
||||||
|
mMatrix[3].setMul(m.mMatrix[3], s);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void setLerp(const LLMatrix4a& a, const LLMatrix4a& b, F32 w)
|
||||||
|
{
|
||||||
|
LLVector4a d0,d1,d2,d3;
|
||||||
|
d0.setSub(b.mMatrix[0], a.mMatrix[0]);
|
||||||
|
d1.setSub(b.mMatrix[1], a.mMatrix[1]);
|
||||||
|
d2.setSub(b.mMatrix[2], a.mMatrix[2]);
|
||||||
|
d3.setSub(b.mMatrix[3], a.mMatrix[3]);
|
||||||
|
|
||||||
|
// this = a + d*w
|
||||||
|
|
||||||
|
d0.mul(w);
|
||||||
|
d1.mul(w);
|
||||||
|
d2.mul(w);
|
||||||
|
d3.mul(w);
|
||||||
|
|
||||||
|
mMatrix[0].setAdd(a.mMatrix[0],d0);
|
||||||
|
mMatrix[1].setAdd(a.mMatrix[1],d1);
|
||||||
|
mMatrix[2].setAdd(a.mMatrix[2],d2);
|
||||||
|
mMatrix[3].setAdd(a.mMatrix[3],d3);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void rotate(const LLVector4a& v, LLVector4a& res)
|
||||||
|
{
|
||||||
|
res = _mm_shuffle_ps(v, v, _MM_SHUFFLE(0, 0, 0, 0));
|
||||||
|
res.mul(mMatrix[0]);
|
||||||
|
|
||||||
|
LLVector4a y;
|
||||||
|
y = _mm_shuffle_ps(v, v, _MM_SHUFFLE(1, 1, 1, 1));
|
||||||
|
y.mul(mMatrix[1]);
|
||||||
|
|
||||||
|
LLVector4a z;
|
||||||
|
z = _mm_shuffle_ps(v, v, _MM_SHUFFLE(2, 2, 2, 2));
|
||||||
|
z.mul(mMatrix[2]);
|
||||||
|
|
||||||
|
res.add(y);
|
||||||
|
res.add(z);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void affineTransform(const LLVector4a& v, LLVector4a& res)
|
||||||
|
{
|
||||||
|
LLVector4a x,y,z;
|
||||||
|
|
||||||
|
x = _mm_shuffle_ps(v, v, _MM_SHUFFLE(0, 0, 0, 0));
|
||||||
|
y = _mm_shuffle_ps(v, v, _MM_SHUFFLE(1, 1, 1, 1));
|
||||||
|
z = _mm_shuffle_ps(v, v, _MM_SHUFFLE(2, 2, 2, 2));
|
||||||
|
|
||||||
|
x.mul(mMatrix[0]);
|
||||||
|
y.mul(mMatrix[1]);
|
||||||
|
z.mul(mMatrix[2]);
|
||||||
|
|
||||||
|
x.add(y);
|
||||||
|
z.add(mMatrix[3]);
|
||||||
|
res.setAdd(x,z);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -35,6 +35,7 @@
|
|||||||
|
|
||||||
#include "lltreenode.h"
|
#include "lltreenode.h"
|
||||||
#include "v3math.h"
|
#include "v3math.h"
|
||||||
|
#include "llvector4a.h"
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <set>
|
#include <set>
|
||||||
|
|
||||||
@@ -85,6 +86,7 @@ template <class T>
|
|||||||
class LLOctreeNode : public LLTreeNode<T>
|
class LLOctreeNode : public LLTreeNode<T>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
typedef LLOctreeTraveler<T> oct_traveler;
|
typedef LLOctreeTraveler<T> oct_traveler;
|
||||||
typedef LLTreeTraveler<T> tree_traveler;
|
typedef LLTreeTraveler<T> tree_traveler;
|
||||||
typedef typename std::set<LLPointer<T> > element_list;
|
typedef typename std::set<LLPointer<T> > element_list;
|
||||||
@@ -96,23 +98,30 @@ public:
|
|||||||
typedef LLOctreeNode<T> oct_node;
|
typedef LLOctreeNode<T> oct_node;
|
||||||
typedef LLOctreeListener<T> oct_listener;
|
typedef LLOctreeListener<T> oct_listener;
|
||||||
|
|
||||||
static const U8 OCTANT_POSITIVE_X = 0x01;
|
/*void* operator new(size_t size)
|
||||||
static const U8 OCTANT_POSITIVE_Y = 0x02;
|
{
|
||||||
static const U8 OCTANT_POSITIVE_Z = 0x04;
|
return ll_aligned_malloc_16(size);
|
||||||
|
}
|
||||||
LLOctreeNode( LLVector3d center,
|
|
||||||
LLVector3d size,
|
void operator delete(void* ptr)
|
||||||
|
{
|
||||||
|
ll_aligned_free_16(ptr);
|
||||||
|
}*/
|
||||||
|
|
||||||
|
LLOctreeNode( const LLVector4a& center,
|
||||||
|
const LLVector4a& size,
|
||||||
BaseType* parent,
|
BaseType* parent,
|
||||||
U8 octant = 255)
|
U8 octant = 255)
|
||||||
: mParent((oct_node*)parent),
|
: mParent((oct_node*)parent),
|
||||||
mCenter(center),
|
|
||||||
mSize(size),
|
|
||||||
mOctant(octant)
|
mOctant(octant)
|
||||||
{
|
{
|
||||||
|
mCenter = center;
|
||||||
|
mSize = size;
|
||||||
|
|
||||||
updateMinMax();
|
updateMinMax();
|
||||||
if ((mOctant == 255) && mParent)
|
if ((mOctant == 255) && mParent)
|
||||||
{
|
{
|
||||||
mOctant = ((oct_node*) mParent)->getOctant(mCenter.mdV);
|
mOctant = ((oct_node*) mParent)->getOctant(mCenter);
|
||||||
}
|
}
|
||||||
|
|
||||||
clearChildren();
|
clearChildren();
|
||||||
@@ -129,39 +138,24 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
inline const BaseType* getParent() const { return mParent; }
|
inline const BaseType* getParent() const { return mParent; }
|
||||||
inline void setParent(BaseType* parent) { mParent = (oct_node*) parent; }
|
inline void setParent(BaseType* parent) { mParent = (oct_node*) parent; }
|
||||||
inline const LLVector3d& getCenter() const { return mCenter; }
|
inline const LLVector4a& getCenter() const { return mCenter; }
|
||||||
inline const LLVector3d& getSize() const { return mSize; }
|
inline const LLVector4a& getSize() const { return mSize; }
|
||||||
inline void setCenter(const LLVector3d center) { mCenter = center; }
|
inline void setCenter(const LLVector4a& center) { mCenter = center; }
|
||||||
inline void setSize(const LLVector3d size) { mSize = size; }
|
inline void setSize(const LLVector4a& size) { mSize = size; }
|
||||||
inline oct_node* getNodeAt(T* data) { return getNodeAt(data->getPositionGroup(), data->getBinRadius()); }
|
inline oct_node* getNodeAt(T* data) { return getNodeAt(data->getPositionGroup(), data->getBinRadius()); }
|
||||||
inline U8 getOctant() const { return mOctant; }
|
inline U8 getOctant() const { return mOctant; }
|
||||||
inline const oct_node* getOctParent() const { return (const oct_node*) getParent(); }
|
inline const oct_node* getOctParent() const { return (const oct_node*) getParent(); }
|
||||||
inline oct_node* getOctParent() { return (oct_node*) getParent(); }
|
inline oct_node* getOctParent() { return (oct_node*) getParent(); }
|
||||||
|
|
||||||
U8 getOctant(const F64 pos[]) const //get the octant pos is in
|
U8 getOctant(const LLVector4a& pos) const //get the octant pos is in
|
||||||
{
|
{
|
||||||
U8 ret = 0;
|
return (U8) (pos.greaterThan(mCenter).getGatheredBits() & 0x7);
|
||||||
|
|
||||||
if (pos[0] > mCenter.mdV[0])
|
|
||||||
{
|
|
||||||
ret |= OCTANT_POSITIVE_X;
|
|
||||||
}
|
|
||||||
if (pos[1] > mCenter.mdV[1])
|
|
||||||
{
|
|
||||||
ret |= OCTANT_POSITIVE_Y;
|
|
||||||
}
|
|
||||||
if (pos[2] > mCenter.mdV[2])
|
|
||||||
{
|
|
||||||
ret |= OCTANT_POSITIVE_Z;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool isInside(const LLVector3d& pos, const F64& rad) const
|
inline bool isInside(const LLVector4a& pos, const F32& rad) const
|
||||||
{
|
{
|
||||||
return rad <= mSize.mdV[0]*2.0 && isInside(pos);
|
return rad <= mSize[0]*2.f && isInside(pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool isInside(T* data) const
|
inline bool isInside(T* data) const
|
||||||
@@ -169,29 +163,27 @@ public:
|
|||||||
return isInside(data->getPositionGroup(), data->getBinRadius());
|
return isInside(data->getPositionGroup(), data->getBinRadius());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isInside(const LLVector3d& pos) const
|
bool isInside(const LLVector4a& pos) const
|
||||||
{
|
{
|
||||||
const F64& x = pos.mdV[0];
|
S32 gt = pos.greaterThan(mMax).getGatheredBits() & 0x7;
|
||||||
const F64& y = pos.mdV[1];
|
if (gt)
|
||||||
const F64& z = pos.mdV[2];
|
|
||||||
|
|
||||||
if (x > mMax.mdV[0] || x <= mMin.mdV[0] ||
|
|
||||||
y > mMax.mdV[1] || y <= mMin.mdV[1] ||
|
|
||||||
z > mMax.mdV[2] || z <= mMin.mdV[2])
|
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
S32 lt = pos.lessEqual(mMin).getGatheredBits() & 0x7;
|
||||||
|
if (lt)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void updateMinMax()
|
void updateMinMax()
|
||||||
{
|
{
|
||||||
for (U32 i = 0; i < 3; i++)
|
mMax.setAdd(mCenter, mSize);
|
||||||
{
|
mMin.setSub(mCenter, mSize);
|
||||||
mMax.mdV[i] = mCenter.mdV[i] + mSize.mdV[i];
|
|
||||||
mMin.mdV[i] = mCenter.mdV[i] - mSize.mdV[i];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inline oct_listener* getOctListener(U32 index)
|
inline oct_listener* getOctListener(U32 index)
|
||||||
@@ -218,20 +210,20 @@ public:
|
|||||||
(radius <= p_size && radius > size);
|
(radius <= p_size && radius > size);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void pushCenter(LLVector3d ¢er, const LLVector3d &size, const T* data)
|
static void pushCenter(LLVector4a ¢er, const LLVector4a &size, const T* data)
|
||||||
{
|
{
|
||||||
const LLVector3d& pos = data->getPositionGroup();
|
const LLVector4a& pos = data->getPositionGroup();
|
||||||
for (U32 i = 0; i < 3; i++)
|
|
||||||
{
|
LLVector4Logical gt = pos.greaterThan(center);
|
||||||
if (pos.mdV[i] > center.mdV[i])
|
|
||||||
{
|
LLVector4a up;
|
||||||
center.mdV[i] += size.mdV[i];
|
up = _mm_and_ps(size, gt);
|
||||||
}
|
|
||||||
else
|
LLVector4a down;
|
||||||
{
|
down = _mm_andnot_ps(gt, size);
|
||||||
center.mdV[i] -= size.mdV[i];
|
|
||||||
}
|
center.add(up);
|
||||||
}
|
center.sub(down);
|
||||||
}
|
}
|
||||||
|
|
||||||
void accept(oct_traveler* visitor) { visitor->visit(this); }
|
void accept(oct_traveler* visitor) { visitor->visit(this); }
|
||||||
@@ -273,14 +265,14 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
oct_node* getNodeAt(const LLVector3d& pos, const F32& rad)
|
oct_node* getNodeAt(const LLVector4a& pos, const F32& rad)
|
||||||
{
|
{
|
||||||
LLOctreeNode<T>* node = this;
|
LLOctreeNode<T>* node = this;
|
||||||
|
|
||||||
if (node->isInside(pos, rad))
|
if (node->isInside(pos, rad))
|
||||||
{
|
{
|
||||||
//do a quick search by octant
|
//do a quick search by octant
|
||||||
U8 octant = node->getOctant(pos.mdV);
|
U8 octant = node->getOctant(pos);
|
||||||
|
|
||||||
//traverse the tree until we find a node that has no node
|
//traverse the tree until we find a node that has no node
|
||||||
//at the appropriate octant or is smaller than the object.
|
//at the appropriate octant or is smaller than the object.
|
||||||
@@ -291,7 +283,7 @@ public:
|
|||||||
while (next_node != 255 && node->getSize()[0] >= rad)
|
while (next_node != 255 && node->getSize()[0] >= rad)
|
||||||
{
|
{
|
||||||
node = node->getChild(next_node);
|
node = node->getChild(next_node);
|
||||||
octant = node->getOctant(pos.mdV);
|
octant = node->getOctant(pos);
|
||||||
next_node = node->mChildMap[octant];
|
next_node = node->mChildMap[octant];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -307,7 +299,7 @@ public:
|
|||||||
{
|
{
|
||||||
if (data == NULL)
|
if (data == NULL)
|
||||||
{
|
{
|
||||||
//OCT_ERRS << "!!! INVALID ELEMENT ADDED TO OCTREE BRANCH !!!" << llendl;
|
OCT_ERRS << "!!! INVALID ELEMENT ADDED TO OCTREE BRANCH !!!" << llendl;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
LLOctreeNode<T>* parent = getOctParent();
|
LLOctreeNode<T>* parent = getOctParent();
|
||||||
@@ -347,16 +339,21 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
//it's here, but no kids are in the right place, make a new kid
|
//it's here, but no kids are in the right place, make a new kid
|
||||||
LLVector3d center(getCenter());
|
LLVector4a center = getCenter();
|
||||||
LLVector3d size(getSize()*0.5);
|
LLVector4a size = getSize();
|
||||||
|
size.mul(0.5f);
|
||||||
|
|
||||||
//push center in direction of data
|
//push center in direction of data
|
||||||
LLOctreeNode<T>::pushCenter(center, size, data);
|
LLOctreeNode<T>::pushCenter(center, size, data);
|
||||||
|
|
||||||
// handle case where floating point number gets too small
|
// handle case where floating point number gets too small
|
||||||
if( llabs(center.mdV[0] - getCenter().mdV[0]) < F_APPROXIMATELY_ZERO &&
|
LLVector4a val;
|
||||||
llabs(center.mdV[1] - getCenter().mdV[1]) < F_APPROXIMATELY_ZERO &&
|
val.setSub(center, getCenter());
|
||||||
llabs(center.mdV[2] - getCenter().mdV[2]) < F_APPROXIMATELY_ZERO)
|
val.setAbs(val);
|
||||||
|
|
||||||
|
S32 lt = val.lessThan(LLVector4a::getEpsilon()).getGatheredBits() & 0x7;
|
||||||
|
|
||||||
|
if( lt == 0x7 )
|
||||||
{
|
{
|
||||||
mData.insert(data);
|
mData.insert(data);
|
||||||
BaseType::insert(data);
|
BaseType::insert(data);
|
||||||
@@ -374,7 +371,7 @@ public:
|
|||||||
//make sure no existing node matches this position
|
//make sure no existing node matches this position
|
||||||
for (U32 i = 0; i < getChildCount(); i++)
|
for (U32 i = 0; i < getChildCount(); i++)
|
||||||
{
|
{
|
||||||
if (mChild[i]->getCenter() == center)
|
if (mChild[i]->getCenter().equals3(center))
|
||||||
{
|
{
|
||||||
OCT_ERRS << "Octree detected duplicate child center and gave up." << llendl;
|
OCT_ERRS << "Octree detected duplicate child center and gave up." << llendl;
|
||||||
return false;
|
return false;
|
||||||
@@ -392,7 +389,7 @@ public:
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
//it's not in here, give it to the root
|
//it's not in here, give it to the root
|
||||||
//OCT_ERRS << "Octree insertion failed, starting over from root!" << llendl;
|
OCT_ERRS << "Octree insertion failed, starting over from root!" << llendl;
|
||||||
|
|
||||||
oct_node* node = this;
|
oct_node* node = this;
|
||||||
|
|
||||||
@@ -503,18 +500,18 @@ public:
|
|||||||
{
|
{
|
||||||
#if LL_OCTREE_PARANOIA_CHECK
|
#if LL_OCTREE_PARANOIA_CHECK
|
||||||
|
|
||||||
if (child->getSize() == getSize())
|
if (child->getSize().equals3(getSize()))
|
||||||
{
|
{
|
||||||
OCT_ERRS << "Child size is same as parent size!" << llendl;
|
OCT_ERRS << "Child size is same as parent size!" << llendl;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (U32 i = 0; i < getChildCount(); i++)
|
for (U32 i = 0; i < getChildCount(); i++)
|
||||||
{
|
{
|
||||||
if(mChild[i]->getSize() != child->getSize())
|
if(!mChild[i]->getSize().equals3(child->getSize()))
|
||||||
{
|
{
|
||||||
OCT_ERRS <<"Invalid octree child size." << llendl;
|
OCT_ERRS <<"Invalid octree child size." << llendl;
|
||||||
}
|
}
|
||||||
if (mChild[i]->getCenter() == child->getCenter())
|
if (mChild[i]->getCenter().equals3(child->getCenter()))
|
||||||
{
|
{
|
||||||
OCT_ERRS <<"Duplicate octree child position." << llendl;
|
OCT_ERRS <<"Duplicate octree child position." << llendl;
|
||||||
}
|
}
|
||||||
@@ -593,7 +590,7 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//OCT_ERRS << "Octree failed to delete requested child." << llendl;
|
OCT_ERRS << "Octree failed to delete requested child." << llendl;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
@@ -605,11 +602,11 @@ protected:
|
|||||||
MIN = 3
|
MIN = 3
|
||||||
} eDName;
|
} eDName;
|
||||||
|
|
||||||
LLVector3d mCenter;
|
LLVector4a mCenter;
|
||||||
LLVector3d mSize;
|
LLVector4a mSize;
|
||||||
LLVector3d mMax;
|
LLVector4a mMax;
|
||||||
LLVector3d mMin;
|
LLVector4a mMin;
|
||||||
|
|
||||||
oct_node* mParent;
|
oct_node* mParent;
|
||||||
U8 mOctant;
|
U8 mOctant;
|
||||||
|
|
||||||
@@ -628,9 +625,9 @@ public:
|
|||||||
typedef LLOctreeNode<T> BaseType;
|
typedef LLOctreeNode<T> BaseType;
|
||||||
typedef LLOctreeNode<T> oct_node;
|
typedef LLOctreeNode<T> oct_node;
|
||||||
|
|
||||||
LLOctreeRoot( const LLVector3d ¢er,
|
LLOctreeRoot(const LLVector4a& center,
|
||||||
const LLVector3d &size,
|
const LLVector4a& size,
|
||||||
BaseType* parent)
|
BaseType* parent)
|
||||||
: BaseType(center, size, parent)
|
: BaseType(center, size, parent)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@@ -673,28 +670,33 @@ public:
|
|||||||
{
|
{
|
||||||
if (data == NULL)
|
if (data == NULL)
|
||||||
{
|
{
|
||||||
//OCT_ERRS << "!!! INVALID ELEMENT ADDED TO OCTREE ROOT !!!" << llendl;
|
OCT_ERRS << "!!! INVALID ELEMENT ADDED TO OCTREE ROOT !!!" << llendl;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (data->getBinRadius() > 4096.0)
|
if (data->getBinRadius() > 4096.0)
|
||||||
{
|
{
|
||||||
//OCT_ERRS << "!!! ELEMENT EXCEEDS MAXIMUM SIZE IN OCTREE ROOT !!!" << llendl;
|
OCT_ERRS << "!!! ELEMENT EXCEEDS MAXIMUM SIZE IN OCTREE ROOT !!!" << llendl;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const F64 MAX_MAG = 1024.0*1024.0;
|
LLVector4a MAX_MAG;
|
||||||
|
MAX_MAG.splat(1024.f*1024.f);
|
||||||
|
|
||||||
const LLVector3d& v = data->getPositionGroup();
|
const LLVector4a& v = data->getPositionGroup();
|
||||||
if (!(fabs(v.mdV[0]-this->mCenter.mdV[0]) < MAX_MAG &&
|
|
||||||
fabs(v.mdV[1]-this->mCenter.mdV[1]) < MAX_MAG &&
|
LLVector4a val;
|
||||||
fabs(v.mdV[2]-this->mCenter.mdV[2]) < MAX_MAG))
|
val.setSub(v, BaseType::mCenter);
|
||||||
|
val.setAbs(val);
|
||||||
|
S32 lt = val.lessThan(MAX_MAG).getGatheredBits() & 0x7;
|
||||||
|
|
||||||
|
if (lt != 0x7)
|
||||||
{
|
{
|
||||||
//OCT_ERRS << "!!! ELEMENT EXCEEDS RANGE OF SPATIAL PARTITION !!!" << llendl;
|
OCT_ERRS << "!!! ELEMENT EXCEEDS RANGE OF SPATIAL PARTITION !!!" << llendl;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this->getSize().mdV[0] > data->getBinRadius() && isInside(data->getPositionGroup()))
|
if (this->getSize()[0] > data->getBinRadius() && isInside(data->getPositionGroup()))
|
||||||
{
|
{
|
||||||
//we got it, just act like a branch
|
//we got it, just act like a branch
|
||||||
oct_node* node = getNodeAt(data);
|
oct_node* node = getNodeAt(data);
|
||||||
@@ -710,31 +712,34 @@ public:
|
|||||||
else if (this->getChildCount() == 0)
|
else if (this->getChildCount() == 0)
|
||||||
{
|
{
|
||||||
//first object being added, just wrap it up
|
//first object being added, just wrap it up
|
||||||
while (!(this->getSize().mdV[0] > data->getBinRadius() && isInside(data->getPositionGroup())))
|
while (!(this->getSize()[0] > data->getBinRadius() && isInside(data->getPositionGroup())))
|
||||||
{
|
{
|
||||||
LLVector3d center, size;
|
LLVector4a center, size;
|
||||||
center = this->getCenter();
|
center = this->getCenter();
|
||||||
size = this->getSize();
|
size = this->getSize();
|
||||||
LLOctreeNode<T>::pushCenter(center, size, data);
|
LLOctreeNode<T>::pushCenter(center, size, data);
|
||||||
this->setCenter(center);
|
this->setCenter(center);
|
||||||
this->setSize(size*2);
|
size.mul(2.f);
|
||||||
|
this->setSize(size);
|
||||||
this->updateMinMax();
|
this->updateMinMax();
|
||||||
}
|
}
|
||||||
LLOctreeNode<T>::insert(data);
|
LLOctreeNode<T>::insert(data);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
while (!(this->getSize().mdV[0] > data->getBinRadius() && isInside(data->getPositionGroup())))
|
while (!(this->getSize()[0] > data->getBinRadius() && isInside(data->getPositionGroup())))
|
||||||
{
|
{
|
||||||
//the data is outside the root node, we need to grow
|
//the data is outside the root node, we need to grow
|
||||||
LLVector3d center(this->getCenter());
|
LLVector4a center(this->getCenter());
|
||||||
LLVector3d size(this->getSize());
|
LLVector4a size(this->getSize());
|
||||||
|
|
||||||
//expand this node
|
//expand this node
|
||||||
LLVector3d newcenter(center);
|
LLVector4a newcenter(center);
|
||||||
LLOctreeNode<T>::pushCenter(newcenter, size, data);
|
LLOctreeNode<T>::pushCenter(newcenter, size, data);
|
||||||
this->setCenter(newcenter);
|
this->setCenter(newcenter);
|
||||||
this->setSize(size*2);
|
LLVector4a size2 = size;
|
||||||
|
size2.mul(2.f);
|
||||||
|
this->setSize(size2);
|
||||||
this->updateMinMax();
|
this->updateMinMax();
|
||||||
|
|
||||||
//copy our children to a new branch
|
//copy our children to a new branch
|
||||||
|
|||||||
@@ -42,13 +42,17 @@
|
|||||||
// The plane normal = [A, B, C]
|
// The plane normal = [A, B, C]
|
||||||
// The closest approach = D / sqrt(A*A + B*B + C*C)
|
// The closest approach = D / sqrt(A*A + B*B + C*C)
|
||||||
|
|
||||||
class LLPlane : public LLVector4
|
class LLPlane
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
// Constructors
|
||||||
LLPlane() {}; // no default constructor
|
LLPlane() {}; // no default constructor
|
||||||
LLPlane(const LLVector3 &p0, F32 d) { setVec(p0, d); }
|
LLPlane(const LLVector3 &p0, F32 d) { setVec(p0, d); }
|
||||||
LLPlane(const LLVector3 &p0, const LLVector3 &n) { setVec(p0, n); }
|
LLPlane(const LLVector3 &p0, const LLVector3 &n) { setVec(p0, n); }
|
||||||
inline void setVec(const LLVector3 &p0, F32 d) { LLVector4::setVec(p0[0], p0[1], p0[2], d); }
|
inline void setVec(const LLVector3 &p0, F32 d) { mV.set(p0[0], p0[1], p0[2], d); }
|
||||||
|
|
||||||
|
// Set
|
||||||
inline void setVec(const LLVector3 &p0, const LLVector3 &n)
|
inline void setVec(const LLVector3 &p0, const LLVector3 &n)
|
||||||
{
|
{
|
||||||
F32 d = -(p0 * n);
|
F32 d = -(p0 * n);
|
||||||
@@ -64,39 +68,38 @@ public:
|
|||||||
F32 d = -(w * p0);
|
F32 d = -(w * p0);
|
||||||
setVec(w, d);
|
setVec(w, d);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline LLPlane& operator=(const LLVector4& v2) { LLVector4::setVec(v2[0],v2[1],v2[2],v2[3]); return *this;}
|
inline LLPlane& operator=(const LLVector4& v2) { mV.set(v2[0],v2[1],v2[2],v2[3]); return *this;}
|
||||||
|
|
||||||
inline void set(const LLPlane& p2) { LLVector4::setVec(p2); }
|
inline LLPlane& operator=(const LLVector4a& v2) { mV.set(v2[0],v2[1],v2[2],v2[3]); return *this;}
|
||||||
|
|
||||||
|
inline void set(const LLPlane& p2) { mV = p2.mV; }
|
||||||
|
|
||||||
//
|
//
|
||||||
F32 dist(const LLVector3 &v2) const { return mV[0]*v2[0] + mV[1]*v2[1] + mV[2]*v2[2] + mV[3]; }
|
F32 dist(const LLVector3 &v2) const { return mV[0]*v2[0] + mV[1]*v2[1] + mV[2]*v2[2] + mV[3]; }
|
||||||
|
|
||||||
|
inline LLSimdScalar dot3(const LLVector4a& b) const { return mV.dot3(b); }
|
||||||
|
|
||||||
|
// Read-only access a single float in this vector. Do not use in proximity to any function call that manipulates
|
||||||
|
// the data at the whole vector level or you will incur a substantial penalty. Consider using the splat functions instead
|
||||||
|
inline F32 operator[](const S32 idx) const { return mV[idx]; }
|
||||||
|
|
||||||
|
// preferable when index is known at compile time
|
||||||
|
template <int N> LL_FORCE_INLINE void getAt(LLSimdScalar& v) const { v = mV.getScalarAt<N>(); }
|
||||||
|
|
||||||
// reset the vector to 0, 0, 0, 1
|
// reset the vector to 0, 0, 0, 1
|
||||||
inline void clear() { LLVector4::setVec(0, 0, 0, 1); }
|
inline void clear() { mV.set(0, 0, 0, 1); }
|
||||||
|
|
||||||
inline void getVector3(LLVector3& vec) const { vec.set(mV[0], mV[1], mV[2]); }
|
inline void getVector3(LLVector3& vec) const { vec.set(mV[0], mV[1], mV[2]); }
|
||||||
|
|
||||||
// Retrieve the mask indicating which of the x, y, or z axis are greater or equal to zero.
|
// Retrieve the mask indicating which of the x, y, or z axis are greater or equal to zero.
|
||||||
inline U8 calcPlaneMask() const
|
inline U8 calcPlaneMask() const
|
||||||
{
|
{
|
||||||
U8 mask = 0;
|
return mV.greaterEqual(LLVector4a::getZero()).getGatheredBits() & LLVector4Logical::MASK_XYZ;
|
||||||
|
|
||||||
if (mV[0] >= 0)
|
|
||||||
{
|
|
||||||
mask |= 1;
|
|
||||||
}
|
|
||||||
if (mV[1] >= 0)
|
|
||||||
{
|
|
||||||
mask |= 2;
|
|
||||||
}
|
|
||||||
if (mV[2] >= 0)
|
|
||||||
{
|
|
||||||
mask |= 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
return mask;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
LLVector4a mV;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -35,10 +35,16 @@
|
|||||||
#define LL_LLQUANTIZE_H
|
#define LL_LLQUANTIZE_H
|
||||||
|
|
||||||
const U16 U16MAX = 65535;
|
const U16 U16MAX = 65535;
|
||||||
|
LL_ALIGN_16( const F32 F_U16MAX_4A[4] ) = { 65535.f, 65535.f, 65535.f, 65535.f };
|
||||||
|
|
||||||
const F32 OOU16MAX = 1.f/(F32)(U16MAX);
|
const F32 OOU16MAX = 1.f/(F32)(U16MAX);
|
||||||
|
LL_ALIGN_16( const F32 F_OOU16MAX_4A[4] ) = { OOU16MAX, OOU16MAX, OOU16MAX, OOU16MAX };
|
||||||
|
|
||||||
const U8 U8MAX = 255;
|
const U8 U8MAX = 255;
|
||||||
|
LL_ALIGN_16( const F32 F_U8MAX_4A[4] ) = { 255.f, 255.f, 255.f, 255.f };
|
||||||
|
|
||||||
const F32 OOU8MAX = 1.f/(F32)(U8MAX);
|
const F32 OOU8MAX = 1.f/(F32)(U8MAX);
|
||||||
|
LL_ALIGN_16( const F32 F_OOU8MAX_4A[4] ) = { OOU8MAX, OOU8MAX, OOU8MAX, OOU8MAX };
|
||||||
|
|
||||||
const U8 FIRSTVALIDCHAR = 54;
|
const U8 FIRSTVALIDCHAR = 54;
|
||||||
const U8 MAXSTRINGVAL = U8MAX - FIRSTVALIDCHAR; //we don't allow newline or null
|
const U8 MAXSTRINGVAL = U8MAX - FIRSTVALIDCHAR; //we don't allow newline or null
|
||||||
|
|||||||
105
indra/llmath/llquaternion2.h
Normal file
105
indra/llmath/llquaternion2.h
Normal file
@@ -0,0 +1,105 @@
|
|||||||
|
/**
|
||||||
|
* @file llquaternion2.h
|
||||||
|
* @brief LLQuaternion2 class header file - SIMD-enabled quaternion class
|
||||||
|
*
|
||||||
|
* $LicenseInfo:firstyear=2010&license=viewerlgpl$
|
||||||
|
* Second Life Viewer Source Code
|
||||||
|
* Copyright (C) 2010, Linden Research, Inc.
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation;
|
||||||
|
* version 2.1 of the License only.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*
|
||||||
|
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||||
|
* $/LicenseInfo$
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef LL_QUATERNION2_H
|
||||||
|
#define LL_QUATERNION2_H
|
||||||
|
|
||||||
|
/////////////////////////////
|
||||||
|
// LLQuaternion2
|
||||||
|
/////////////////////////////
|
||||||
|
// This class stores a quaternion x*i + y*j + z*k + w in <x, y, z, w> order
|
||||||
|
// (i.e., w in high order element of vector)
|
||||||
|
/////////////////////////////
|
||||||
|
/////////////////////////////
|
||||||
|
// These classes are intentionally minimal right now. If you need additional
|
||||||
|
// functionality, please contact someone with SSE experience (e.g., Falcon or
|
||||||
|
// Huseby).
|
||||||
|
/////////////////////////////
|
||||||
|
#include "llquaternion.h"
|
||||||
|
|
||||||
|
class LLQuaternion2
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
//////////////////////////
|
||||||
|
// Ctors
|
||||||
|
//////////////////////////
|
||||||
|
|
||||||
|
// Ctor
|
||||||
|
LLQuaternion2() {}
|
||||||
|
|
||||||
|
// Ctor from LLQuaternion
|
||||||
|
explicit LLQuaternion2( const class LLQuaternion& quat );
|
||||||
|
|
||||||
|
//////////////////////////
|
||||||
|
// Get/Set
|
||||||
|
//////////////////////////
|
||||||
|
|
||||||
|
// Load from an LLQuaternion
|
||||||
|
inline void operator=( const LLQuaternion& quat )
|
||||||
|
{
|
||||||
|
mQ.loadua( quat.mQ );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return the internal LLVector4a representation of the quaternion
|
||||||
|
inline const LLVector4a& getVector4a() const;
|
||||||
|
inline LLVector4a& getVector4aRw();
|
||||||
|
|
||||||
|
/////////////////////////
|
||||||
|
// Quaternion modification
|
||||||
|
/////////////////////////
|
||||||
|
|
||||||
|
// Set this quaternion to the conjugate of src
|
||||||
|
inline void setConjugate(const LLQuaternion2& src);
|
||||||
|
|
||||||
|
// Renormalizes the quaternion. Assumes it has nonzero length.
|
||||||
|
inline void normalize();
|
||||||
|
|
||||||
|
// Quantize this quaternion to 8 bit precision
|
||||||
|
inline void quantize8();
|
||||||
|
|
||||||
|
// Quantize this quaternion to 16 bit precision
|
||||||
|
inline void quantize16();
|
||||||
|
|
||||||
|
/////////////////////////
|
||||||
|
// Quaternion inspection
|
||||||
|
/////////////////////////
|
||||||
|
|
||||||
|
// Return true if this quaternion is equal to 'rhs'.
|
||||||
|
// Note! Quaternions exhibit "double-cover", so any rotation has two equally valid
|
||||||
|
// quaternion representations and they will NOT compare equal.
|
||||||
|
inline bool equals(const LLQuaternion2& rhs, F32 tolerance = F_APPROXIMATELY_ZERO ) const;
|
||||||
|
|
||||||
|
// Return true if all components are finite and the quaternion is normalized
|
||||||
|
inline bool isOkRotation() const;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
LLVector4a mQ;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
102
indra/llmath/llquaternion2.inl
Normal file
102
indra/llmath/llquaternion2.inl
Normal file
@@ -0,0 +1,102 @@
|
|||||||
|
/**
|
||||||
|
* @file llquaternion2.inl
|
||||||
|
* @brief LLQuaternion2 inline definitions
|
||||||
|
*
|
||||||
|
* $LicenseInfo:firstyear=2010&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 "llquaternion2.h"
|
||||||
|
|
||||||
|
static const LLQuad LL_V4A_PLUS_ONE = {1.f, 1.f, 1.f, 1.f};
|
||||||
|
static const LLQuad LL_V4A_MINUS_ONE = {-1.f, -1.f, -1.f, -1.f};
|
||||||
|
|
||||||
|
// Ctor from LLQuaternion
|
||||||
|
inline LLQuaternion2::LLQuaternion2( const LLQuaternion& quat )
|
||||||
|
{
|
||||||
|
mQ.set(quat.mQ[VX], quat.mQ[VY], quat.mQ[VZ], quat.mQ[VW]);
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////////////////////
|
||||||
|
// Get/Set
|
||||||
|
//////////////////////////
|
||||||
|
|
||||||
|
// Return the internal LLVector4a representation of the quaternion
|
||||||
|
inline const LLVector4a& LLQuaternion2::getVector4a() const
|
||||||
|
{
|
||||||
|
return mQ;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline LLVector4a& LLQuaternion2::getVector4aRw()
|
||||||
|
{
|
||||||
|
return mQ;
|
||||||
|
}
|
||||||
|
|
||||||
|
/////////////////////////
|
||||||
|
// Quaternion modification
|
||||||
|
/////////////////////////
|
||||||
|
|
||||||
|
// Set this quaternion to the conjugate of src
|
||||||
|
inline void LLQuaternion2::setConjugate(const LLQuaternion2& src)
|
||||||
|
{
|
||||||
|
static LL_ALIGN_16( const U32 F_QUAT_INV_MASK_4A[4] ) = { 0x80000000, 0x80000000, 0x80000000, 0x00000000 };
|
||||||
|
mQ = _mm_xor_ps(src.mQ, *reinterpret_cast<const LLQuad*>(&F_QUAT_INV_MASK_4A));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Renormalizes the quaternion. Assumes it has nonzero length.
|
||||||
|
inline void LLQuaternion2::normalize()
|
||||||
|
{
|
||||||
|
mQ.normalize4();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Quantize this quaternion to 8 bit precision
|
||||||
|
inline void LLQuaternion2::quantize8()
|
||||||
|
{
|
||||||
|
mQ.quantize8( LL_V4A_MINUS_ONE, LL_V4A_PLUS_ONE );
|
||||||
|
normalize();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Quantize this quaternion to 16 bit precision
|
||||||
|
inline void LLQuaternion2::quantize16()
|
||||||
|
{
|
||||||
|
mQ.quantize16( LL_V4A_MINUS_ONE, LL_V4A_PLUS_ONE );
|
||||||
|
normalize();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/////////////////////////
|
||||||
|
// Quaternion inspection
|
||||||
|
/////////////////////////
|
||||||
|
|
||||||
|
// Return true if this quaternion is equal to 'rhs'.
|
||||||
|
// Note! Quaternions exhibit "double-cover", so any rotation has two equally valid
|
||||||
|
// quaternion representations and they will NOT compare equal.
|
||||||
|
inline bool LLQuaternion2::equals(const LLQuaternion2 &rhs, F32 tolerance/* = F_APPROXIMATELY_ZERO*/) const
|
||||||
|
{
|
||||||
|
return mQ.equals4(rhs.mQ, tolerance);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return true if all components are finite and the quaternion is normalized
|
||||||
|
inline bool LLQuaternion2::isOkRotation() const
|
||||||
|
{
|
||||||
|
return mQ.isFinite4() && mQ.isNormalized4();
|
||||||
|
}
|
||||||
|
|
||||||
@@ -31,4 +31,5 @@
|
|||||||
|
|
||||||
#include "linden_common.h"
|
#include "linden_common.h"
|
||||||
|
|
||||||
|
// implementation is all in the header, this include dep ensures the unit test is rerun if the implementation changes.
|
||||||
#include "llrect.h"
|
#include "llrect.h"
|
||||||
|
|||||||
93
indra/llmath/llsimdmath.h
Normal file
93
indra/llmath/llsimdmath.h
Normal file
@@ -0,0 +1,93 @@
|
|||||||
|
/**
|
||||||
|
* @file llsimdmath.h
|
||||||
|
* @brief Common header for SIMD-based math library (llvector4a, llmatrix3a, etc.)
|
||||||
|
*
|
||||||
|
* $LicenseInfo:firstyear=2010&license=viewerlgpl$
|
||||||
|
* Second Life Viewer Source Code
|
||||||
|
* Copyright (C) 2010, Linden Research, Inc.
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation;
|
||||||
|
* version 2.1 of the License only.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*
|
||||||
|
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||||
|
* $/LicenseInfo$
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef LL_SIMD_MATH_H
|
||||||
|
#define LL_SIMD_MATH_H
|
||||||
|
|
||||||
|
#ifndef LLMATH_H
|
||||||
|
#error "Please include llmath.h before this file."
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if ( ( LL_DARWIN || LL_LINUX ) && !(__SSE2__) ) || ( LL_WINDOWS && ( _M_IX86_FP < 2 ) )
|
||||||
|
#error SSE2 not enabled. LLVector4a and related class will not compile.
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !LL_WINDOWS
|
||||||
|
#include <stdint.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
template <typename T> T* LL_NEXT_ALIGNED_ADDRESS(T* address)
|
||||||
|
{
|
||||||
|
return reinterpret_cast<T*>(
|
||||||
|
(reinterpret_cast<uintptr_t>(address) + 0xF) & ~0xF);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T> T* LL_NEXT_ALIGNED_ADDRESS_64(T* address)
|
||||||
|
{
|
||||||
|
return reinterpret_cast<T*>(
|
||||||
|
(reinterpret_cast<uintptr_t>(address) + 0x3F) & ~0x3F);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if LL_LINUX || LL_DARWIN
|
||||||
|
|
||||||
|
#define LL_ALIGN_PREFIX(x)
|
||||||
|
#define LL_ALIGN_POSTFIX(x) __attribute__((aligned(x)))
|
||||||
|
|
||||||
|
#elif LL_WINDOWS
|
||||||
|
|
||||||
|
#define LL_ALIGN_PREFIX(x) __declspec(align(x))
|
||||||
|
#define LL_ALIGN_POSTFIX(x)
|
||||||
|
|
||||||
|
#else
|
||||||
|
#error "LL_ALIGN_PREFIX and LL_ALIGN_POSTFIX undefined"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define LL_ALIGN_16(var) LL_ALIGN_PREFIX(16) var LL_ALIGN_POSTFIX(16)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#include <xmmintrin.h>
|
||||||
|
#include <emmintrin.h>
|
||||||
|
|
||||||
|
#include "llsimdtypes.h"
|
||||||
|
#include "llsimdtypes.inl"
|
||||||
|
|
||||||
|
class LLMatrix3a;
|
||||||
|
class LLRotation;
|
||||||
|
class LLMatrix3;
|
||||||
|
|
||||||
|
#include "llquaternion.h"
|
||||||
|
|
||||||
|
#include "llvector4logical.h"
|
||||||
|
#include "llvector4a.h"
|
||||||
|
#include "llmatrix3a.h"
|
||||||
|
#include "llquaternion2.h"
|
||||||
|
#include "llvector4a.inl"
|
||||||
|
#include "llmatrix3a.inl"
|
||||||
|
#include "llquaternion2.inl"
|
||||||
|
|
||||||
|
|
||||||
|
#endif //LL_SIMD_MATH_H
|
||||||
124
indra/llmath/llsimdtypes.h
Normal file
124
indra/llmath/llsimdtypes.h
Normal file
@@ -0,0 +1,124 @@
|
|||||||
|
/**
|
||||||
|
* @file llsimdtypes.h
|
||||||
|
* @brief Declaration of basic SIMD math related types
|
||||||
|
*
|
||||||
|
* $LicenseInfo:firstyear=2010&license=viewerlgpl$
|
||||||
|
* Second Life Viewer Source Code
|
||||||
|
* Copyright (C) 2010, Linden Research, Inc.
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation;
|
||||||
|
* version 2.1 of the License only.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*
|
||||||
|
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||||
|
* $/LicenseInfo$
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef LL_SIMD_TYPES_H
|
||||||
|
#define LL_SIMD_TYPES_H
|
||||||
|
|
||||||
|
#ifndef LL_SIMD_MATH_H
|
||||||
|
#error "Please include llmath.h before this file."
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef __m128 LLQuad;
|
||||||
|
|
||||||
|
|
||||||
|
#if LL_WINDOWS
|
||||||
|
#pragma warning(push)
|
||||||
|
#pragma warning( disable : 4800 3 ) // Disable warning about casting int to bool for this class.
|
||||||
|
#if defined(_MSC_VER) && (_MSC_VER < 1500)
|
||||||
|
// VC++ 2005 is missing these intrinsics
|
||||||
|
// __forceinline is MSVC specific and attempts to override compiler inlining judgment. This is so
|
||||||
|
// even in debug builds this call is a NOP.
|
||||||
|
__forceinline const __m128 _mm_castsi128_ps( const __m128i a ) { return reinterpret_cast<const __m128&>(a); }
|
||||||
|
__forceinline const __m128i _mm_castps_si128( const __m128 a ) { return reinterpret_cast<const __m128i&>(a); }
|
||||||
|
#endif // _MSC_VER
|
||||||
|
|
||||||
|
#endif // LL_WINDOWS
|
||||||
|
|
||||||
|
class LLBool32
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
inline LLBool32() {}
|
||||||
|
inline LLBool32(int rhs) : m_bool(rhs) {}
|
||||||
|
inline LLBool32(unsigned int rhs) : m_bool(rhs) {}
|
||||||
|
inline LLBool32(bool rhs) { m_bool = static_cast<const int>(rhs); }
|
||||||
|
inline LLBool32& operator= (bool rhs) { m_bool = (int)rhs; return *this; }
|
||||||
|
inline bool operator== (bool rhs) const { return static_cast<const bool&>(m_bool) == rhs; }
|
||||||
|
inline bool operator!= (bool rhs) const { return !operator==(rhs); }
|
||||||
|
inline operator bool() const { return static_cast<const bool&>(m_bool); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
int m_bool;
|
||||||
|
};
|
||||||
|
|
||||||
|
#if LL_WINDOWS
|
||||||
|
#pragma warning(pop)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
class LLSimdScalar
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
inline LLSimdScalar() {}
|
||||||
|
inline LLSimdScalar(LLQuad q)
|
||||||
|
{
|
||||||
|
mQ = q;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline LLSimdScalar(F32 f)
|
||||||
|
{
|
||||||
|
mQ = _mm_set_ss(f);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline const LLSimdScalar& getZero()
|
||||||
|
{
|
||||||
|
extern const LLQuad F_ZERO_4A;
|
||||||
|
return reinterpret_cast<const LLSimdScalar&>(F_ZERO_4A);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline F32 getF32() const;
|
||||||
|
|
||||||
|
inline LLBool32 isApproximatelyEqual(const LLSimdScalar& rhs, F32 tolerance = F_APPROXIMATELY_ZERO) const;
|
||||||
|
|
||||||
|
inline LLSimdScalar getAbs() const;
|
||||||
|
|
||||||
|
inline void setMax( const LLSimdScalar& a, const LLSimdScalar& b );
|
||||||
|
|
||||||
|
inline void setMin( const LLSimdScalar& a, const LLSimdScalar& b );
|
||||||
|
|
||||||
|
inline LLSimdScalar& operator=(F32 rhs);
|
||||||
|
|
||||||
|
inline LLSimdScalar& operator+=(const LLSimdScalar& rhs);
|
||||||
|
|
||||||
|
inline LLSimdScalar& operator-=(const LLSimdScalar& rhs);
|
||||||
|
|
||||||
|
inline LLSimdScalar& operator*=(const LLSimdScalar& rhs);
|
||||||
|
|
||||||
|
inline LLSimdScalar& operator/=(const LLSimdScalar& rhs);
|
||||||
|
|
||||||
|
inline operator LLQuad() const
|
||||||
|
{
|
||||||
|
return mQ;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline const LLQuad& getQuad() const
|
||||||
|
{
|
||||||
|
return mQ;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
LLQuad mQ;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif //LL_SIMD_TYPES_H
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user