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_dependencies(viewer linux-crash-logger-strip-target)
|
||||
elseif (DARWIN)
|
||||
add_subdirectory(${VIEWER_PREFIX}mac_crash_logger)
|
||||
#add_subdirectory(${VIEWER_PREFIX}mac_crash_logger)
|
||||
#add_subdirectory(${VIEWER_PREFIX}mac_updater)
|
||||
add_dependencies(viewer mac-crash-logger)
|
||||
#add_dependencies(viewer mac-updater)
|
||||
|
||||
@@ -31,10 +31,10 @@ if (WINDOWS)
|
||||
# Don't build DLLs.
|
||||
set(BUILD_SHARED_LIBS OFF)
|
||||
|
||||
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /Od /Zi /MDd"
|
||||
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /Od /Zi /MDd /arch:SSE2"
|
||||
CACHE STRING "C++ compiler debug options" FORCE)
|
||||
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO
|
||||
"${CMAKE_CXX_FLAGS_RELWITHDEBINFO} /Od /Zi /MD /MP"
|
||||
"${CMAKE_CXX_FLAGS_RELWITHDEBINFO} /Od /Zi /MD /MP /arch:SSE2"
|
||||
CACHE STRING "C++ compiler release-with-debug options" FORCE)
|
||||
set(CMAKE_CXX_FLAGS_RELEASE
|
||||
"${CMAKE_CXX_FLAGS_RELEASE} ${LL_CXX_FLAGS} /O2 /Zi /MD /MP /arch:SSE /fp:fast"
|
||||
@@ -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_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")
|
||||
set(CMAKE_CXX_FLAGS_RELEASESSE2 "${CMAKE_CXX_FLAGS_RELEASESSE2} -march=pentium4 -mfpmath=sse -msse2 ${GCC_EXTRA_OPTIMIZATIONS}")
|
||||
set(CMAKE_C_FLAGS_RELEASESSE2 "${CMAKE_C_FLAGS_RELEASESSE2} -march=pentium4 -mfpmath=sse -msse2 "${GCC_EXTRA_OPTIMIZATIONS})
|
||||
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} -march=pentium4 -mfpmath=sse -msse2 ${GCC_EXTRA_OPTIMIZATIONS}")
|
||||
set(CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO} -march=pentium4 -mfpmath=sse -msse2 "${GCC_EXTRA_OPTIMIZATIONS})
|
||||
if (NOT STANDALONE)
|
||||
set(MARCH_FLAG " -march=pentium4")
|
||||
endif (NOT STANDALONE)
|
||||
set(CMAKE_CXX_FLAGS_RELEASESSE2 "${CMAKE_CXX_FLAGS_RELEASESSE2}${MARCH_FLAG} -mfpmath=sse -msse2 ${GCC_EXTRA_OPTIMIZATIONS}")
|
||||
set(CMAKE_C_FLAGS_RELEASESSE2 "${CMAKE_C_FLAGS_RELEASESSE2}${MARCH_FLAG} -mfpmath=sse -msse2 "${GCC_EXTRA_OPTIMIZATIONS})
|
||||
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO}${MARCH_FLAG} -mfpmath=sse -msse2 ${GCC_EXTRA_OPTIMIZATIONS}")
|
||||
set(CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO}${MARCH_FLAG} -mfpmath=sse -msse2 "${GCC_EXTRA_OPTIMIZATIONS})
|
||||
endif (${ARCH} STREQUAL "x86_64")
|
||||
endif (VIEWER)
|
||||
|
||||
set(CMAKE_CXX_FLAGS_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_C_FLAGS_RELEASE "-O3 ${CMAKE_C_FLAGS_RELEASE}")
|
||||
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")
|
||||
# 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.
|
||||
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-O0 ${CMAKE_CXX_FLAGS_RELWITHDEBINFO}")
|
||||
set(CMAKE_C_FLAGS_RELWITHDEBINFO "-O0 ${CMAKE_C_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 "${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_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}")
|
||||
@@ -278,11 +281,6 @@ endif (LINUX OR DARWIN)
|
||||
|
||||
if (STANDALONE)
|
||||
add_definitions(-DLL_STANDALONE=1)
|
||||
|
||||
if (LINUX AND ${ARCH} STREQUAL "i686")
|
||||
add_definitions(-march=pentiumpro)
|
||||
endif (LINUX AND ${ARCH} STREQUAL "i686")
|
||||
|
||||
else (STANDALONE)
|
||||
set(${ARCH}_linux_INCLUDES
|
||||
ELFIO
|
||||
@@ -297,6 +295,7 @@ endif (STANDALONE)
|
||||
|
||||
if(1 EQUAL 1)
|
||||
add_definitions(-DOPENSIM_RULES=1)
|
||||
add_definitions(-DMESH_ENABLED=1)
|
||||
endif(1 EQUAL 1)
|
||||
|
||||
if(SERVER)
|
||||
|
||||
@@ -43,6 +43,7 @@ endif (NOT FMOD_LIBRARY)
|
||||
|
||||
find_path(FMOD_INCLUDE_DIR fmod.h
|
||||
${LIBS_PREBUILT_DIR}/include
|
||||
${LIBS_PREBUILT_DIR}/${LL_ARCH_DIR}/include
|
||||
${FMOD_SDK_DIR}/api/inc
|
||||
${FMOD_SDK_DIR}/inc
|
||||
${FMOD_SDK_DIR}
|
||||
|
||||
@@ -24,11 +24,11 @@ else (STANDALONE)
|
||||
endif (LINUX)
|
||||
endif (STANDALONE)
|
||||
|
||||
if (GOOGLE_PERFTOOLS_FOUND)
|
||||
if (GOOGLE_PERFTOOLS_FOUND AND STANDALONE)
|
||||
set(USE_GOOGLE_PERFTOOLS ON CACHE BOOL "Build with Google PerfTools support.")
|
||||
else (GOOGLE_PERFTOOLS_FOUND)
|
||||
else ()
|
||||
set(USE_GOOGLE_PERFTOOLS OFF)
|
||||
endif (GOOGLE_PERFTOOLS_FOUND)
|
||||
endif ()
|
||||
|
||||
# XXX Disable temporarily, until we have compilation issues on 64-bit
|
||||
# Etch sorted.
|
||||
|
||||
@@ -5,6 +5,12 @@ include(Boost)
|
||||
include(EXPAT)
|
||||
include(ZLIB)
|
||||
|
||||
if (DARWIN)
|
||||
include(CMakeFindFrameworks)
|
||||
find_library(CORESERVICES_LIBRARY CoreServices)
|
||||
endif (DARWIN)
|
||||
|
||||
|
||||
set(LLCOMMON_INCLUDE_DIRS
|
||||
${LIBS_OPEN_DIR}/cwdebug
|
||||
${LIBS_OPEN_DIR}/llcommon
|
||||
@@ -13,3 +19,8 @@ set(LLCOMMON_INCLUDE_DIRS
|
||||
)
|
||||
|
||||
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)
|
||||
|
||||
if (NOT STANDALONE)
|
||||
use_prebuilt_binary(GL)
|
||||
use_prebuilt_binary(glext)
|
||||
# possible glh_linear should have its own .cmake file instead
|
||||
#use_prebuilt_binary(glh_linear)
|
||||
# actually... not any longer, it's now in git -SG
|
||||
set(GLEXT_INCLUDE_DIR ${LIBS_PREBUILT_DIR}/${LL_ARCH_DIR}/include)
|
||||
set(GLEXT_INCLUDE_DIR ${LIBS_PREBUILT_DIR}/include)
|
||||
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(SERVER_DIR ${CMAKE_SOURCE_DIR}/${SERVER_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(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 ;
|
||||
infile.open(in_fname,LL_APR_RB, LLAPRFile::global);
|
||||
infile.open(in_fname,LL_APR_RB);
|
||||
//********************************
|
||||
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;
|
||||
|
||||
LLAPRFile infile ;
|
||||
infile.open(in_fname,LL_APR_RB, LLAPRFile::global);
|
||||
infile.open(in_fname,LL_APR_RB);
|
||||
if (!infile.getFileHandle())
|
||||
{
|
||||
llwarns << "Couldn't open temporary ogg file for writing: " << in_fname
|
||||
@@ -249,7 +249,7 @@ S32 encode_vorbis_file(const std::string& in_fname, const std::string& out_fname
|
||||
}
|
||||
|
||||
LLAPRFile outfile ;
|
||||
outfile.open(out_fname,LL_APR_WPB, LLAPRFile::global);
|
||||
outfile.open(out_fname,LL_APR_WPB);
|
||||
if (!outfile.getFileHandle())
|
||||
{
|
||||
llwarns << "Couldn't open upload sound file for reading: " << in_fname
|
||||
|
||||
@@ -226,7 +226,7 @@ ELoadStatus LLBVHLoader::loadTranslationTable(const char *fileName)
|
||||
std::string path = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS,fileName);
|
||||
|
||||
LLAPRFile infile ;
|
||||
infile.open(path, LL_APR_R, LLAPRFile::global);
|
||||
infile.open(path, LL_APR_R);
|
||||
apr_file_t *fp = infile.getFileHandle();
|
||||
if (!fp)
|
||||
return E_ST_NO_XLT_FILE;
|
||||
|
||||
@@ -45,7 +45,7 @@
|
||||
LLStringTable LLCharacter::sVisualParamNames(1024);
|
||||
|
||||
std::vector< LLCharacter* > LLCharacter::sInstances;
|
||||
|
||||
BOOL LLCharacter::sAllowInstancesChange = TRUE ;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// LLCharacter()
|
||||
@@ -59,8 +59,10 @@ LLCharacter::LLCharacter()
|
||||
mSkeletonSerialNum( 0 ),
|
||||
mInAppearance( false )
|
||||
{
|
||||
mMotionController.setCharacter( this );
|
||||
llassert_always(sAllowInstancesChange) ;
|
||||
sInstances.push_back(this);
|
||||
|
||||
mMotionController.setCharacter( this );
|
||||
mPauseRequest = new LLPauseRequestHandle();
|
||||
}
|
||||
|
||||
@@ -77,11 +79,22 @@ LLCharacter::~LLCharacter()
|
||||
{
|
||||
delete param;
|
||||
}
|
||||
std::vector<LLCharacter*>::iterator iter = std::find(sInstances.begin(), sInstances.end(), this);
|
||||
if (iter != sInstances.end())
|
||||
|
||||
U32 i ;
|
||||
U32 size = sInstances.size() ;
|
||||
for(i = 0 ; i < size ; i++)
|
||||
{
|
||||
sInstances.erase(iter);
|
||||
if(sInstances[i] == this)
|
||||
{
|
||||
break ;
|
||||
}
|
||||
}
|
||||
|
||||
llassert_always(i < size) ;
|
||||
|
||||
llassert_always(sAllowInstancesChange) ;
|
||||
sInstances[i] = sInstances[size - 1] ;
|
||||
sInstances.pop_back() ;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -42,7 +42,7 @@
|
||||
#include "llmotioncontroller.h"
|
||||
#include "llvisualparam.h"
|
||||
#include "string_table.h"
|
||||
#include "llmemory.h"
|
||||
#include "llpointer.h"
|
||||
#include "llthread.h"
|
||||
|
||||
class LLPolyMesh;
|
||||
@@ -279,6 +279,7 @@ public:
|
||||
void setSkeletonSerialNum( U32 num ) { mSkeletonSerialNum = num; }
|
||||
|
||||
static std::vector< LLCharacter* > sInstances;
|
||||
static BOOL sAllowInstancesChange ; //debug use
|
||||
|
||||
protected:
|
||||
LLMotionController mMotionController;
|
||||
|
||||
@@ -56,6 +56,9 @@ LLJoint::LLJoint()
|
||||
mUpdateXform = TRUE;
|
||||
mJointNum = -1;
|
||||
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()
|
||||
|
||||
@@ -86,10 +86,19 @@ protected:
|
||||
|
||||
// explicit transformation members
|
||||
LLXformMatrix mXform;
|
||||
#if MESH_ENABLED
|
||||
LLXformMatrix mOldXform;
|
||||
LLXformMatrix mDefaultXform;
|
||||
|
||||
LLUUID mId;
|
||||
#endif //MESH_ENABLED
|
||||
public:
|
||||
U32 mDirtyFlags;
|
||||
BOOL mUpdateXform;
|
||||
|
||||
#if MESH_ENABLED
|
||||
BOOL mResetAfterRestoreOldXform;
|
||||
#endif //MESH_ENABLED
|
||||
|
||||
// describes the skin binding pose
|
||||
LLVector3 mSkinOffset;
|
||||
@@ -179,6 +188,24 @@ public:
|
||||
S32 getJointNum() const { return mJointNum; }
|
||||
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>
|
||||
std::string exportString(U32 tabs = 0);
|
||||
// </edit>
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
// Header Files
|
||||
//-----------------------------------------------------------------------------
|
||||
#include "lljoint.h"
|
||||
#include "llmemory.h"
|
||||
#include "llrefcount.h"
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// class LLJointState
|
||||
|
||||
@@ -89,6 +89,7 @@ LLJointState *LLPose::getNextJointState()
|
||||
//-----------------------------------------------------------------------------
|
||||
BOOL LLPose::addJointState(const LLPointer<LLJointState>& jointState)
|
||||
{
|
||||
llassert_always(jointState.notNull());
|
||||
if (mJointMap.find(jointState->getJoint()->getName()) == mJointMap.end())
|
||||
{
|
||||
mJointMap[jointState->getJoint()->getName()] = jointState;
|
||||
@@ -161,6 +162,7 @@ void LLPose::setWeight(F32 weight)
|
||||
// <edit>
|
||||
// there was a crash here
|
||||
// </edit>
|
||||
llassert_always(iter->second.notNull());
|
||||
iter->second->setWeight(weight);
|
||||
}
|
||||
mWeight = weight;
|
||||
|
||||
@@ -40,6 +40,8 @@
|
||||
#include "lljointstate.h"
|
||||
#include "lljoint.h"
|
||||
#include "llmap.h"
|
||||
#include "llpointer.h"
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
|
||||
@@ -211,7 +211,7 @@ LLFSMState* LLStateDiagram::getState(U32 state_id)
|
||||
BOOL LLStateDiagram::saveDotFile(const std::string& filename)
|
||||
{
|
||||
LLAPRFile outfile ;
|
||||
outfile.open(filename, LL_APR_W, LLAPRFile::global);
|
||||
outfile.open(filename, LL_APR_W);
|
||||
apr_file_t* dot_file = outfile.getFileHandle() ;
|
||||
|
||||
if (!dot_file)
|
||||
|
||||
@@ -58,12 +58,14 @@ set(llcommon_SOURCE_FILES
|
||||
llprocessor.cpp
|
||||
llqueuedthread.cpp
|
||||
llrand.cpp
|
||||
llrefcount.cpp
|
||||
llrun.cpp
|
||||
llsd.cpp
|
||||
llsdserialize.cpp
|
||||
llsdserialize_xml.cpp
|
||||
llsdutil.cpp
|
||||
llsecondlifeurls.cpp
|
||||
llsingleton.cpp
|
||||
llstat.cpp
|
||||
llstacktrace.cpp
|
||||
llstreamtools.cpp
|
||||
@@ -94,6 +96,7 @@ set(llcommon_HEADER_FILES
|
||||
indra_constants.h
|
||||
linden_common.h
|
||||
linked_lists.h
|
||||
llaccountingcost.h
|
||||
llagentconstants.h
|
||||
llavatarname.h
|
||||
llapp.h
|
||||
@@ -159,6 +162,7 @@ set(llcommon_HEADER_FILES
|
||||
llmortician.h
|
||||
llnametable.h
|
||||
lloptioninterface.h
|
||||
llpointer.h
|
||||
llpreprocessor.h
|
||||
llpriqueuemap.h
|
||||
llprocesslauncher.h
|
||||
@@ -168,6 +172,8 @@ set(llcommon_HEADER_FILES
|
||||
llqueuedthread.h
|
||||
llrand.h
|
||||
llrun.h
|
||||
llrefcount.h
|
||||
llsafehandle.h
|
||||
llscopedvolatileaprpool.h
|
||||
llsd.h
|
||||
llsdserialize.h
|
||||
@@ -175,6 +181,7 @@ set(llcommon_HEADER_FILES
|
||||
llsdutil.h
|
||||
llsecondlifeurls.h
|
||||
llsimplehash.h
|
||||
llsingleton.h
|
||||
llskiplist.h
|
||||
llskipmap.h
|
||||
llstack.h
|
||||
@@ -189,6 +196,7 @@ set(llcommon_HEADER_FILES
|
||||
llsys.h
|
||||
llthread.h
|
||||
lltimer.h
|
||||
lltreeiterators.h
|
||||
lluri.h
|
||||
lluuid.h
|
||||
lluuidhashmap.h
|
||||
@@ -205,6 +213,7 @@ set(llcommon_HEADER_FILES
|
||||
stdenums.h
|
||||
stdtypes.h
|
||||
string_table.h
|
||||
stringize.h
|
||||
timer.h
|
||||
timing.h
|
||||
u64.h
|
||||
@@ -224,7 +233,9 @@ target_link_libraries(
|
||||
${EXPAT_LIBRARIES}
|
||||
${ZLIB_LIBRARIES}
|
||||
${WINDOWS_LIBRARIES}
|
||||
${BOOST_REGEX_LIBRARY}
|
||||
${CWDEBUG_LIBRARIES}
|
||||
${CORESERVICES_LIBRARY}
|
||||
)
|
||||
|
||||
if (LINUX)
|
||||
|
||||
@@ -153,6 +153,11 @@ const char LAND_LAYER_CODE = 'L';
|
||||
const char WATER_LAYER_CODE = 'W';
|
||||
const char WIND_LAYER_CODE = '7';
|
||||
const char CLOUD_LAYER_CODE = '8';
|
||||
// Extended land layer for Aurora Sim
|
||||
const char AURORA_LAND_LAYER_CODE = 'M';
|
||||
const char AURORA_WATER_LAYER_CODE = 'X';
|
||||
const char AURORA_WIND_LAYER_CODE = '9';
|
||||
const char AURORA_CLOUD_LAYER_CODE = ':';
|
||||
|
||||
// keys
|
||||
// Bit masks for various keyboard modifier keys.
|
||||
|
||||
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];
|
||||
}
|
||||
|
||||
void LLApp::stepFrame()
|
||||
{
|
||||
LLFrameTimer::updateFrameTime();
|
||||
LLFrameTimer::updateFrameCount();
|
||||
LLEventTimer::updateClass();
|
||||
mRunner.run();
|
||||
}
|
||||
|
||||
|
||||
void LLApp::setupErrorHandling()
|
||||
{
|
||||
// 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
|
||||
// when the app goes into the APP_STATUS_ERROR state
|
||||
//
|
||||
llinfos << "Starting error thread" << llendl;
|
||||
mThreadErrorp = new LLErrorThread();
|
||||
mThreadErrorp->setUserData((void *) this);
|
||||
mThreadErrorp->start();
|
||||
if(!mThreadErrorp)
|
||||
{
|
||||
llinfos << "Starting error thread" << llendl;
|
||||
mThreadErrorp = new LLErrorThread();
|
||||
mThreadErrorp->setUserData((void *) this);
|
||||
mThreadErrorp->start();
|
||||
}
|
||||
}
|
||||
|
||||
void LLApp::setErrorHandler(LLAppErrorHandler handler)
|
||||
|
||||
@@ -236,17 +236,6 @@ public:
|
||||
pid_t fork();
|
||||
#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:
|
||||
typedef std::map<std::string, std::string> string_map;
|
||||
string_map mOptionMap; // Contains all command-line options and arguments in a map
|
||||
@@ -264,11 +253,6 @@ protected:
|
||||
static LLAppChildCallback sDefaultChildCallback;
|
||||
#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.
|
||||
*/
|
||||
@@ -289,9 +273,6 @@ private:
|
||||
// Default application threads
|
||||
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 */
|
||||
//@{
|
||||
|
||||
|
||||
@@ -191,6 +191,10 @@ apr_status_t LLAPRFile::open(std::string const& filename, apr_int32_t flags, acc
|
||||
return status;
|
||||
}
|
||||
|
||||
apr_status_t LLAPRFile::open(const std::string& filename, apr_int32_t flags, BOOL use_global_pool)
|
||||
{
|
||||
return open(filename, flags, use_global_pool ? LLAPRFile::global : LLAPRFile::local);
|
||||
}
|
||||
// File I/O
|
||||
S32 LLAPRFile::read(void *buf, S32 nbytes)
|
||||
{
|
||||
|
||||
@@ -150,10 +150,11 @@ public:
|
||||
};
|
||||
|
||||
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() ;
|
||||
|
||||
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() ;
|
||||
|
||||
// Returns actual offset, -1 if seek fails
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
#include "llassettype.h"
|
||||
#include "lldictionary.h"
|
||||
#include "llmemory.h"
|
||||
#include "llsingleton.h"
|
||||
|
||||
///----------------------------------------------------------------------------
|
||||
/// 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_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));
|
||||
#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));
|
||||
};
|
||||
|
||||
|
||||
@@ -138,13 +138,19 @@ public:
|
||||
|
||||
// Inventory folder link
|
||||
AT_LINK_FOLDER = 25,
|
||||
|
||||
|
||||
//AT_CURRENT_OUTFIT = 46,
|
||||
|
||||
//AT_OUTFIT = 47,
|
||||
|
||||
//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: |
|
||||
// +*********************************************+
|
||||
@@ -155,8 +161,9 @@ public:
|
||||
// +*********************************************+
|
||||
|
||||
//AT_COUNT = 49,
|
||||
|
||||
#if !MESH_ENABLED
|
||||
AT_COUNT = 26,
|
||||
#endif //!MESH_ENABLED
|
||||
AT_NONE = -1
|
||||
};
|
||||
|
||||
|
||||
@@ -38,6 +38,8 @@
|
||||
#include <iosfwd>
|
||||
#include <string>
|
||||
|
||||
#include "llpreprocessor.h"
|
||||
|
||||
#include "stdtypes.h"
|
||||
|
||||
/**
|
||||
|
||||
@@ -44,63 +44,40 @@
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//std::list<LLEventTimer*> LLEventTimer::sActiveList;
|
||||
|
||||
LLEventTimer::LLEventTimer(F32 period)
|
||||
: mEventTimer()
|
||||
{
|
||||
mPeriod = period;
|
||||
//sActiveList.push_back(this);
|
||||
}
|
||||
|
||||
LLEventTimer::LLEventTimer(const LLDate& time)
|
||||
: mEventTimer()
|
||||
{
|
||||
mPeriod = (F32)(time.secondsSinceEpoch() - LLDate::now().secondsSinceEpoch());
|
||||
//sActiveList.push_back(this);
|
||||
}
|
||||
|
||||
|
||||
LLEventTimer::~LLEventTimer()
|
||||
LLEventTimer::~LLEventTimer()
|
||||
{
|
||||
//sActiveList.remove(this);
|
||||
}
|
||||
|
||||
//static
|
||||
void LLEventTimer::updateClass()
|
||||
{
|
||||
std::list<LLEventTimer*> completed_timers;
|
||||
|
||||
/*{
|
||||
for (std::list<LLEventTimer*>::iterator iter = sActiveList.begin(); iter != sActiveList.end(); )
|
||||
{
|
||||
LLEventTimer* timer = *iter++;
|
||||
F32 et = timer->mEventTimer.getElapsedTimeF32();
|
||||
if (timer->mEventTimer.getStarted() && et > timer->mPeriod) {
|
||||
timer->mEventTimer.reset();
|
||||
if ( timer->tick() )
|
||||
{
|
||||
completed_timers.push_back( timer );
|
||||
}
|
||||
}
|
||||
}
|
||||
}*/
|
||||
for (instance_iter iter = beginInstances(); iter != endInstances(); )
|
||||
{
|
||||
LLInstanceTrackerScopedGuard guard;
|
||||
for (instance_iter iter = guard.beginInstances(); iter != guard.endInstances(); )
|
||||
{
|
||||
LLEventTimer& timer = *iter++;
|
||||
F32 et = timer.mEventTimer.getElapsedTimeF32();
|
||||
if (timer.mEventTimer.getStarted() && et > timer.mPeriod) {
|
||||
timer.mEventTimer.reset();
|
||||
if ( timer.tick() )
|
||||
{
|
||||
completed_timers.push_back( &timer );
|
||||
}
|
||||
LLEventTimer& timer = *iter++;
|
||||
F32 et = timer.mEventTimer.getElapsedTimeF32();
|
||||
if (timer.mEventTimer.getStarted() && et > timer.mPeriod) {
|
||||
timer.mEventTimer.reset();
|
||||
if ( timer.tick() )
|
||||
{
|
||||
completed_timers.push_back( &timer );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if ( completed_timers.size() > 0 )
|
||||
{
|
||||
for (std::list<LLEventTimer*>::iterator completed_iter = completed_timers.begin();
|
||||
|
||||
@@ -56,11 +56,6 @@ public:
|
||||
protected:
|
||||
LLTimer mEventTimer;
|
||||
F32 mPeriod;
|
||||
|
||||
//private:
|
||||
//list of active timers
|
||||
// static std::list<LLEventTimer*> sActiveList; // TODO should this be a vector
|
||||
};
|
||||
|
||||
|
||||
#endif //LL_EVENTTIMER_H
|
||||
|
||||
@@ -29,33 +29,22 @@
|
||||
* COMPLETENESS OR PERFORMANCE.
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#include "linden_common.h"
|
||||
|
||||
#include "llfasttimer.h"
|
||||
|
||||
#include "llmemory.h"
|
||||
#include "llprocessor.h"
|
||||
|
||||
|
||||
#if LL_WINDOWS
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#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
|
||||
#include "lltimer.h"
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// statics
|
||||
|
||||
|
||||
LLFastTimer::EFastTimerType LLFastTimer::sCurType = LLFastTimer::FTM_OTHER;
|
||||
int LLFastTimer::sCurDepth = 0;
|
||||
U64 LLFastTimer::sStart[LLFastTimer::FTM_MAX_DEPTH];
|
||||
@@ -70,44 +59,12 @@ S32 LLFastTimer::sLastFrameIndex = -1;
|
||||
int LLFastTimer::sPauseHistory = 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
|
||||
{
|
||||
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()
|
||||
{
|
||||
@@ -162,139 +119,17 @@ void LLFastTimer::reset()
|
||||
// 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
|
||||
// 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
|
||||
// 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()
|
||||
{
|
||||
return (U32)(get_clock_count()>>8);
|
||||
return get_clock_count() >> 8;
|
||||
}
|
||||
|
||||
U64 LLFastTimer::getCPUClockCount64()
|
||||
{
|
||||
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_TREE,
|
||||
FTM_UPDATE_AVATAR,
|
||||
|
||||
#if MESH_ENABLED
|
||||
FTM_UPDATE_RIGGED_VOLUME,
|
||||
FTM_SKIN_RIGGED,
|
||||
FTM_RIGGED_OCTREE,
|
||||
#endif //MESH_ENABLED
|
||||
|
||||
// common render components
|
||||
FTM_SHADOW_GEOMETRY,
|
||||
FTM_SHADOW_RENDER,
|
||||
@@ -131,6 +136,12 @@ public:
|
||||
FTM_STATESORT,
|
||||
FTM_STATESORT_DRAWABLE,
|
||||
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_VOLUME_VB,
|
||||
FTM_REBUILD_BRIDGE_VB,
|
||||
@@ -256,7 +267,6 @@ public:
|
||||
static void reset();
|
||||
static U64 countsPerSecond();
|
||||
|
||||
static std::string sClockType;
|
||||
public:
|
||||
static int sCurDepth;
|
||||
static U64 sStart[FTM_MAX_DEPTH];
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
#include "llfoldertype.h"
|
||||
#include "lldictionary.h"
|
||||
#include "llmemory.h"
|
||||
#include "llsingleton.h"
|
||||
|
||||
///----------------------------------------------------------------------------
|
||||
/// Class LLFolderType
|
||||
@@ -95,7 +96,12 @@ LLFolderDictionary::LLFolderDictionary()
|
||||
addEntry(LLFolderType::FT_CURRENT_OUTFIT, new FolderEntry("current", TRUE));
|
||||
addEntry(LLFolderType::FT_OUTFIT, new FolderEntry("outfit", FALSE));
|
||||
addEntry(LLFolderType::FT_MY_OUTFITS, new FolderEntry("my_otfts", TRUE));
|
||||
|
||||
addEntry(LLFolderType::FT_MESH, new FolderEntry("mesh", TRUE));
|
||||
|
||||
addEntry(LLFolderType::FT_INBOX, new FolderEntry("inbox", TRUE));
|
||||
addEntry(LLFolderType::FT_OUTBOX, new FolderEntry("outbox", TRUE));
|
||||
addEntry(LLFolderType::FT_BASIC_ROOT, new FolderEntry("basic_rt", TRUE));
|
||||
|
||||
addEntry(LLFolderType::FT_NONE, new FolderEntry("-1", FALSE));
|
||||
};
|
||||
|
||||
@@ -87,9 +87,14 @@ public:
|
||||
FT_OUTFIT = 47,
|
||||
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
|
||||
};
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
* $LicenseInfo:firstyear=2002&license=viewergpl$
|
||||
*
|
||||
* Copyright (c) 2002-2009, Linden Research, Inc.
|
||||
* Copyright (c) 2011, Aleric Inglewood.
|
||||
*
|
||||
* Second Life Viewer Source Code
|
||||
* The source code in this file ("Source Code") is provided by Linden Lab
|
||||
@@ -35,48 +36,55 @@
|
||||
|
||||
#include "llframetimer.h"
|
||||
|
||||
// Local constants.
|
||||
static F64 const USEC_PER_SECOND = 1000000.0;
|
||||
static F64 const USEC_TO_SEC_F64 = 0.000001;
|
||||
|
||||
// Static members
|
||||
//LLTimer LLFrameTimer::sInternalTimer;
|
||||
U64 LLFrameTimer::sStartTotalTime = totalTime();
|
||||
F64 LLFrameTimer::sFrameTime = 0.0;
|
||||
U64 LLFrameTimer::sTotalTime = 0;
|
||||
F64 LLFrameTimer::sTotalSeconds = 0.0;
|
||||
S32 LLFrameTimer::sFrameCount = 0;
|
||||
U64 LLFrameTimer::sFrameDeltaTime = 0;
|
||||
const F64 USEC_PER_SECOND = 1000000.0;
|
||||
const F64 USEC_TO_SEC_F64 = 0.000001;
|
||||
U64 const LLFrameTimer::sStartTotalTime = totalTime(); // Application start in microseconds since epoch.
|
||||
U64 LLFrameTimer::sTotalTime = LLFrameTimer::sStartTotalTime; // Current time in microseconds since epoch, updated at least once per frame.
|
||||
F64 LLFrameTimer::sTotalSeconds = // Current time in seconds since epoch, updated together with LLFrameTimer::sTotalTime.
|
||||
U64_to_F64(LLFrameTimer::sTotalTime) * USEC_TO_SEC_F64;
|
||||
F64 LLFrameTimer::sFrameTime = 0.0; // Current time in seconds since application start, updated together with LLFrameTimer::sTotalTime.
|
||||
// Updated exactly once per frame:
|
||||
S32 LLFrameTimer::sFrameCount = 0; // Current frame number (number of frames since application start).
|
||||
U64 LLFrameTimer::sPrevTotalTime = LLFrameTimer::sStartTotalTime; // Previous (frame) time in microseconds since epoch, updated once per frame.
|
||||
U64 LLFrameTimer::sFrameDeltaTime = 0; // Microseconds between last two calls to LLFrameTimer::updateFrameTimeAndCount.
|
||||
|
||||
// static
|
||||
void LLFrameTimer::updateFrameTime()
|
||||
{
|
||||
U64 total_time = totalTime();
|
||||
sFrameDeltaTime = total_time - sTotalTime;
|
||||
sTotalTime = total_time;
|
||||
sTotalTime = totalTime();
|
||||
sTotalSeconds = U64_to_F64(sTotalTime) * USEC_TO_SEC_F64;
|
||||
sFrameTime = U64_to_F64(sTotalTime - sStartTotalTime) * USEC_TO_SEC_F64;
|
||||
}
|
||||
|
||||
void LLFrameTimer::start()
|
||||
// static
|
||||
void LLFrameTimer::updateFrameTimeAndCount()
|
||||
{
|
||||
reset();
|
||||
mStarted = TRUE;
|
||||
updateFrameTime();
|
||||
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()
|
||||
{
|
||||
mStarted = FALSE;
|
||||
}
|
||||
|
||||
void LLFrameTimer::reset()
|
||||
{
|
||||
mStartTime = sFrameTime;
|
||||
mExpiry = sFrameTime;
|
||||
}
|
||||
|
||||
void LLFrameTimer::resetWithExpiry(F32 expiration)
|
||||
{
|
||||
reset();
|
||||
setTimerExpirySec(expiration);
|
||||
llassert(!mPaused);
|
||||
mRunning = false;
|
||||
}
|
||||
|
||||
// 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)
|
||||
void LLFrameTimer::pause()
|
||||
{
|
||||
if (mStarted)
|
||||
mStartTime = sFrameTime - mStartTime; // save dtime
|
||||
mStarted = FALSE;
|
||||
if (!mPaused)
|
||||
{
|
||||
mStartTime = sFrameTime - mStartTime; // Abuse mStartTime to store the elapsed time so far.
|
||||
}
|
||||
mPaused = true;
|
||||
}
|
||||
|
||||
void LLFrameTimer::unpause()
|
||||
{
|
||||
if (!mStarted)
|
||||
mStartTime = sFrameTime - mStartTime; // restore dtime
|
||||
mStarted = TRUE;
|
||||
if (mPaused)
|
||||
{
|
||||
mStartTime = sFrameTime - mStartTime; // Set mStartTime consistent with the elapsed time so far.
|
||||
}
|
||||
mPaused = false;
|
||||
}
|
||||
|
||||
void LLFrameTimer::setTimerExpirySec(F32 expiration)
|
||||
{
|
||||
mExpiry = expiration + mStartTime;
|
||||
llassert(!mPaused);
|
||||
mExpiry = mStartTime + expiration;
|
||||
}
|
||||
|
||||
void LLFrameTimer::setExpiryAt(F64 seconds_since_epoch)
|
||||
{
|
||||
llassert(!mPaused);
|
||||
mStartTime = sFrameTime;
|
||||
mExpiry = seconds_since_epoch - (USEC_TO_SEC_F64 * sStartTotalTime);
|
||||
}
|
||||
@@ -119,20 +133,14 @@ F64 LLFrameTimer::expiresAt() const
|
||||
return expires_at;
|
||||
}
|
||||
|
||||
BOOL LLFrameTimer::checkExpirationAndReset(F32 expiration)
|
||||
bool LLFrameTimer::checkExpirationAndReset(F32 expiration)
|
||||
{
|
||||
//llinfos << "LLFrameTimer::checkExpirationAndReset()" << llendl;
|
||||
//llinfos << " mStartTime:" << mStartTime << llendl;
|
||||
//llinfos << " sFrameTime:" << sFrameTime << llendl;
|
||||
//llinfos << " mExpiry: " << mExpiry << llendl;
|
||||
|
||||
if(hasExpired())
|
||||
if (hasExpired())
|
||||
{
|
||||
reset();
|
||||
setTimerExpirySec(expiration);
|
||||
return TRUE;
|
||||
reset(expiration);
|
||||
return true;
|
||||
}
|
||||
return FALSE;
|
||||
return false;
|
||||
}
|
||||
|
||||
// static
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
* $LicenseInfo:firstyear=2002&license=viewergpl$
|
||||
*
|
||||
* Copyright (c) 2002-2009, Linden Research, Inc.
|
||||
* Copyright (c) 2011, Aleric Inglewood.
|
||||
*
|
||||
* Second Life Viewer Source Code
|
||||
* 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
|
||||
* 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"
|
||||
@@ -46,61 +47,64 @@
|
||||
class LL_COMMON_API LLFrameTimer
|
||||
{
|
||||
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
|
||||
// application instance.
|
||||
// Return the number of seconds since the start of the application.
|
||||
static F64 getElapsedSeconds()
|
||||
{
|
||||
// Loses msec precision after ~4.5 hours...
|
||||
return sFrameTime;
|
||||
}
|
||||
|
||||
// Return a low precision usec since epoch
|
||||
// Return a low precision usec since epoch.
|
||||
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()
|
||||
{
|
||||
return sTotalSeconds;
|
||||
}
|
||||
|
||||
// Call this method once per frame to update the current frame time. This is actually called
|
||||
// at some other times as well
|
||||
// Call this method once per frame to update the current frame time.
|
||||
// This is actually called at some other times as well.
|
||||
static void updateFrameTime();
|
||||
|
||||
// Call this method once, and only once, per frame to update the current frame count.
|
||||
static void updateFrameCount() { sFrameCount++; }
|
||||
// Call this method once, and only once, per frame to update the current frame count and sFrameDeltaTime.
|
||||
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
|
||||
static F32 getCurrentFrameTime();
|
||||
static F32 getCurrentFrameTime();
|
||||
|
||||
// MANIPULATORS
|
||||
void start();
|
||||
void stop();
|
||||
void reset();
|
||||
void resetWithExpiry(F32 expiration);
|
||||
void pause();
|
||||
void unpause();
|
||||
|
||||
void reset(F32 expiration = 0.f); // Same as start() but leaves mRunning off when called after stop().
|
||||
void start(F32 expiration = 0.f); // Reset and (re)start with expiration.
|
||||
void stop(); // Stop running.
|
||||
|
||||
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 setExpiryAt(F64 seconds_since_epoch);
|
||||
BOOL checkExpirationAndReset(F32 expiration);
|
||||
F32 getElapsedTimeAndResetF32() { F32 t = F32(sFrameTime - mStartTime); reset(); return t; }
|
||||
|
||||
void setAge(const F64 age) { mStartTime = sFrameTime - age; }
|
||||
bool checkExpirationAndReset(F32 expiration); // Returns true when expired. Only resets if expired.
|
||||
F32 getElapsedTimeAndResetF32() { F32 t = getElapsedTimeF32(); reset(); return t; }
|
||||
void setAge(const F64 age) { llassert(!mPaused); mStartTime = sFrameTime - age; }
|
||||
|
||||
// ACCESSORS
|
||||
BOOL hasExpired() const { return (sFrameTime >= mExpiry); }
|
||||
F32 getTimeToExpireF32() const { return (F32)(mExpiry - sFrameTime); }
|
||||
F32 getElapsedTimeF32() const { return mStarted ? (F32)(sFrameTime - mStartTime) : (F32)mStartTime; }
|
||||
BOOL getStarted() const { return mStarted; }
|
||||
bool hasExpired() const { return sFrameTime >= mExpiry; }
|
||||
F32 getElapsedTimeF32() const { llassert(mRunning); return mPaused ? (F32)mStartTime : (F32)(sFrameTime - mStartTime); }
|
||||
bool getStarted() const { return mRunning; }
|
||||
|
||||
// return the seconds since epoch when this timer will expire.
|
||||
F64 expiresAt() const;
|
||||
@@ -114,45 +118,52 @@ protected:
|
||||
// Aplication constants
|
||||
//
|
||||
|
||||
// Start time of opp in usec since epoch
|
||||
static U64 sStartTotalTime;
|
||||
// Application start in microseconds since epoch.
|
||||
static U64 const sStartTotalTime;
|
||||
|
||||
//
|
||||
// Data updated per frame
|
||||
//
|
||||
|
||||
// Seconds since application start
|
||||
// Current time in seconds since application start, updated together with sTotalTime.
|
||||
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;
|
||||
|
||||
// Total microseconds since epoch.
|
||||
// Current time in microseconds since epoch, updated at least once per frame.
|
||||
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;
|
||||
|
||||
// Total number of frames elapsed in application
|
||||
// Current frame number (number of frames since application start).
|
||||
static S32 sFrameCount;
|
||||
|
||||
//
|
||||
// Member data
|
||||
//
|
||||
|
||||
// Number of seconds after application start when this timer was
|
||||
// started. Set equal to sFrameTime when reset.
|
||||
// When not paused (mPaused is false): number of seconds since application start,
|
||||
// otherwise this value is equal to the accumulated run time (ElapsedTime).
|
||||
// Set equal to sFrameTime when reset.
|
||||
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;
|
||||
|
||||
// Useful bit of state usually associated with timers, but does
|
||||
// not affect actual functionality
|
||||
BOOL mStarted;
|
||||
// True when running, merely a boolean return by getStarted(). The timer always runs.
|
||||
bool mRunning;
|
||||
|
||||
// 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)
|
||||
extern F32 getCurrentFrameTime();
|
||||
extern F32 getCurrentFrameTime();
|
||||
|
||||
#endif // LL_LLFRAMETIMER_H
|
||||
|
||||
@@ -49,6 +49,7 @@ class LL_COMMON_API LLInstanceTrackerBase : public boost::noncopyable
|
||||
protected:
|
||||
static void * & getInstances(std::type_info const & info);
|
||||
};
|
||||
|
||||
/// This mix-in class adds support for tracking all instances of the specified class parameter T
|
||||
/// The (optional) key associates a value of type KEY with a given instance of T, for quick lookup
|
||||
/// If KEY is not provided, then instances are stored in a simple set
|
||||
@@ -58,13 +59,80 @@ class LLInstanceTracker : public LLInstanceTrackerBase
|
||||
{
|
||||
typedef typename std::map<KEY, T*> InstanceMap;
|
||||
typedef LLInstanceTracker<T, KEY> MyT;
|
||||
typedef boost::function<const KEY&(typename InstanceMap::value_type&)> KeyGetter;
|
||||
typedef boost::function<T*(typename InstanceMap::value_type&)> InstancePtrGetter;
|
||||
public:
|
||||
/// Dereferencing key_iter gives you a const KEY&
|
||||
typedef boost::transform_iterator<KeyGetter, typename InstanceMap::iterator> key_iter;
|
||||
/// Dereferencing instance_iter gives you a T&
|
||||
typedef boost::indirect_iterator< boost::transform_iterator<InstancePtrGetter, typename InstanceMap::iterator> > instance_iter;
|
||||
class instance_iter : public boost::iterator_facade<instance_iter, T, boost::forward_traversal_tag>
|
||||
{
|
||||
public:
|
||||
typedef boost::iterator_facade<instance_iter, T, boost::forward_traversal_tag> super_t;
|
||||
|
||||
instance_iter(const typename InstanceMap::iterator& it)
|
||||
: mIterator(it)
|
||||
{
|
||||
++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)
|
||||
{
|
||||
@@ -72,42 +140,47 @@ public:
|
||||
return (found == getMap_().end()) ? NULL : found->second;
|
||||
}
|
||||
|
||||
static instance_iter beginInstances()
|
||||
{
|
||||
return instance_iter(getMap_().begin());
|
||||
}
|
||||
|
||||
static instance_iter endInstances()
|
||||
{
|
||||
return instance_iter(getMap_().end());
|
||||
}
|
||||
|
||||
static S32 instanceCount() { return getMap_().size(); }
|
||||
|
||||
static key_iter beginKeys()
|
||||
{
|
||||
return boost::make_transform_iterator(getMap_().begin(),
|
||||
boost::bind(&InstanceMap::value_type::first, _1));
|
||||
return key_iter(getMap_().begin());
|
||||
}
|
||||
static key_iter endKeys()
|
||||
{
|
||||
return boost::make_transform_iterator(getMap_().end(),
|
||||
boost::bind(&InstanceMap::value_type::first, _1));
|
||||
return key_iter(getMap_().end());
|
||||
}
|
||||
static instance_iter beginInstances()
|
||||
{
|
||||
return instance_iter(boost::make_transform_iterator(getMap_().begin(),
|
||||
boost::bind(&InstanceMap::value_type::second, _1)));
|
||||
}
|
||||
static instance_iter endInstances()
|
||||
{
|
||||
return instance_iter(boost::make_transform_iterator(getMap_().end(),
|
||||
boost::bind(&InstanceMap::value_type::second, _1)));
|
||||
}
|
||||
static S32 instanceCount() { return getMap_().size(); }
|
||||
|
||||
protected:
|
||||
LLInstanceTracker(KEY key) { add_(key); }
|
||||
virtual ~LLInstanceTracker() { remove_(); }
|
||||
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 const KEY& getKey() const { return mKey; }
|
||||
virtual const KEY& getKey() const { return mInstanceKey; }
|
||||
|
||||
private:
|
||||
void add_(KEY key)
|
||||
{
|
||||
mKey = key;
|
||||
mInstanceKey = key;
|
||||
getMap_()[key] = static_cast<T*>(this);
|
||||
}
|
||||
void remove_()
|
||||
{
|
||||
getMap_().erase(mKey);
|
||||
getMap_().erase(mInstanceKey);
|
||||
}
|
||||
|
||||
static InstanceMap& getMap_()
|
||||
@@ -122,9 +195,12 @@ 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*
|
||||
/// use a simple std::set<T*>
|
||||
template<typename T>
|
||||
@@ -133,42 +209,55 @@ class LLInstanceTracker<T, T*> : public LLInstanceTrackerBase
|
||||
typedef typename std::set<T*> InstanceSet;
|
||||
typedef LLInstanceTracker<T, T*> MyT;
|
||||
public:
|
||||
/// Dereferencing key_iter gives you a T* (since T* is the key)
|
||||
typedef typename InstanceSet::iterator key_iter;
|
||||
/// Dereferencing instance_iter gives you a T&
|
||||
typedef boost::indirect_iterator<key_iter> instance_iter;
|
||||
|
||||
/// for completeness of analogy with the generic implementation
|
||||
static T* getInstance(T* k) { return k; }
|
||||
static S32 instanceCount() { return getSet_().size(); }
|
||||
|
||||
// Instantiate this to get access to iterators for this type. It's a 'guard' in the sense
|
||||
// that it treats deletes of this type as errors as long as there is an instance of
|
||||
// this class alive in scope somewhere (i.e. deleting while iterating is bad).
|
||||
class LLInstanceTrackerScopedGuard
|
||||
class instance_iter : public boost::iterator_facade<instance_iter, T, boost::forward_traversal_tag>
|
||||
{
|
||||
public:
|
||||
LLInstanceTrackerScopedGuard()
|
||||
instance_iter(const typename InstanceSet::iterator& it)
|
||||
: mIterator(it)
|
||||
{
|
||||
++sIterationNestDepth;
|
||||
}
|
||||
|
||||
~LLInstanceTrackerScopedGuard()
|
||||
instance_iter(const instance_iter& other)
|
||||
: mIterator(other.mIterator)
|
||||
{
|
||||
++sIterationNestDepth;
|
||||
}
|
||||
|
||||
~instance_iter()
|
||||
{
|
||||
--sIterationNestDepth;
|
||||
}
|
||||
|
||||
static instance_iter beginInstances() { return instance_iter(getSet_().begin()); }
|
||||
static instance_iter endInstances() { return instance_iter(getSet_().end()); }
|
||||
static key_iter beginKeys() { return getSet_().begin(); }
|
||||
static key_iter endKeys() { return getSet_().end(); }
|
||||
private:
|
||||
friend class boost::iterator_core_access;
|
||||
|
||||
void increment() { mIterator++; }
|
||||
bool equal(instance_iter const& other) const
|
||||
{
|
||||
return mIterator == other.mIterator;
|
||||
}
|
||||
|
||||
T& dereference() const
|
||||
{
|
||||
return **mIterator;
|
||||
}
|
||||
|
||||
typename InstanceSet::iterator mIterator;
|
||||
};
|
||||
|
||||
static instance_iter beginInstances() { return instance_iter(getSet_().begin()); }
|
||||
static instance_iter endInstances() { return instance_iter(getSet_().end()); }
|
||||
|
||||
protected:
|
||||
LLInstanceTracker()
|
||||
{
|
||||
// it's safe but unpredictable to create instances of this type while all instances are being iterated over. I hate unpredictable. This assert will probably be turned on early in the next development cycle.
|
||||
//llassert(sIterationNestDepth == 0);
|
||||
getSet_().insert(static_cast<T*>(this));
|
||||
}
|
||||
virtual ~LLInstanceTracker()
|
||||
@@ -180,7 +269,6 @@ protected:
|
||||
|
||||
LLInstanceTracker(const LLInstanceTracker& other)
|
||||
{
|
||||
//llassert(sIterationNestDepth == 0);
|
||||
getSet_().insert(static_cast<T*>(this));
|
||||
}
|
||||
|
||||
|
||||
@@ -118,6 +118,62 @@ public:
|
||||
THROTTLE_BLOCKED, // rate exceed, block key
|
||||
};
|
||||
|
||||
F64 getActionCount(const T& id)
|
||||
{
|
||||
U64 now = 0;
|
||||
if ( mIsRealtime )
|
||||
{
|
||||
now = LLKeyThrottleImpl<T>::getTime();
|
||||
}
|
||||
else
|
||||
{
|
||||
now = LLKeyThrottleImpl<T>::getFrame();
|
||||
}
|
||||
|
||||
if (now >= (m.startTime + m.intervalLength))
|
||||
{
|
||||
if (now < (m.startTime + 2 * m.intervalLength))
|
||||
{
|
||||
// prune old data
|
||||
delete m.prevMap;
|
||||
m.prevMap = m.currMap;
|
||||
m.currMap = new typename LLKeyThrottleImpl<T>::EntryMap;
|
||||
|
||||
m.startTime += m.intervalLength;
|
||||
}
|
||||
else
|
||||
{
|
||||
// lots of time has passed, all data is stale
|
||||
delete m.prevMap;
|
||||
delete m.currMap;
|
||||
m.prevMap = new typename LLKeyThrottleImpl<T>::EntryMap;
|
||||
m.currMap = new typename LLKeyThrottleImpl<T>::EntryMap;
|
||||
|
||||
m.startTime = now;
|
||||
}
|
||||
}
|
||||
|
||||
U32 prevCount = 0;
|
||||
|
||||
typename LLKeyThrottleImpl<T>::EntryMap::const_iterator prev = m.prevMap->find(id);
|
||||
if (prev != m.prevMap->end())
|
||||
{
|
||||
prevCount = prev->second.count;
|
||||
}
|
||||
|
||||
typename LLKeyThrottleImpl<T>::Entry& curr = (*m.currMap)[id];
|
||||
|
||||
// curr.count is the number of keys in
|
||||
// this current 'time slice' from the beginning of it until now
|
||||
// prevCount is the number of keys in the previous
|
||||
// time slice scaled to be one full time slice back from the current
|
||||
// (now) time.
|
||||
|
||||
// compute current, windowed rate
|
||||
F64 timeInCurrent = ((F64)(now - m.startTime) / m.intervalLength);
|
||||
F64 averageCount = curr.count + prevCount * (1.0 - timeInCurrent);
|
||||
return averageCount;
|
||||
}
|
||||
// call each time the key wants use
|
||||
State noteAction(const T& id, S32 weight = 1)
|
||||
{
|
||||
|
||||
@@ -48,6 +48,7 @@ const U32 AGENT_TYPING = 0x0200;
|
||||
const U32 AGENT_CROUCHING = 0x0400;
|
||||
const U32 AGENT_BUSY = 0x0800;
|
||||
const U32 AGENT_ALWAYS_RUN = 0x1000;
|
||||
const U32 AGENT_AUTOPILOT = 0x2000;
|
||||
|
||||
const S32 LSL_REMOTE_DATA_CHANNEL = 1;
|
||||
const S32 LSL_REMOTE_DATA_REQUEST = 2;
|
||||
@@ -184,6 +185,10 @@ const S32 OBJECT_VELOCITY = 5;
|
||||
const S32 OBJECT_OWNER = 6;
|
||||
const S32 OBJECT_GROUP = 7;
|
||||
const S32 OBJECT_CREATOR = 8;
|
||||
const S32 OBJECT_RUNNING_SCRIPT_COUNT = 9;
|
||||
const S32 OBJECT_TOTAL_SCRIPT_COUNT = 10;
|
||||
const S32 OBJECT_SCRIPT_MEMORY = 11;
|
||||
const S32 OBJECT_SCRIPT_TIME = 12;
|
||||
|
||||
// changed() event flags
|
||||
const U32 CHANGED_NONE = 0x0;
|
||||
@@ -198,5 +203,17 @@ const U32 CHANGED_OWNER = 0x80;
|
||||
const U32 CHANGED_REGION = 0x100;
|
||||
const U32 CHANGED_TELEPORT = 0x200;
|
||||
const U32 CHANGED_REGION_START = 0x400;
|
||||
const U32 CHANGED_MEDIA = 0x800;
|
||||
|
||||
// Possible error results
|
||||
const U32 LSL_STATUS_OK = 0;
|
||||
const U32 LSL_STATUS_MALFORMED_PARAMS = 1000;
|
||||
const U32 LSL_STATUS_TYPE_MISMATCH = 1001;
|
||||
const U32 LSL_STATUS_BOUNDS_ERROR = 1002;
|
||||
const U32 LSL_STATUS_NOT_FOUND = 1003;
|
||||
const U32 LSL_STATUS_NOT_SUPPORTED = 1004;
|
||||
const U32 LSL_STATUS_INTERNAL_ERROR = 1999;
|
||||
|
||||
// Start per-function errors below, starting at 2000:
|
||||
const U32 LSL_STATUS_WHITELIST_FAILED = 2001;
|
||||
#endif
|
||||
|
||||
@@ -276,37 +276,12 @@ void operator delete[] (void *p)
|
||||
|
||||
#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)
|
||||
|
||||
U64 getCurrentRSS()
|
||||
U64 LLMemory::getCurrentRSS()
|
||||
{
|
||||
HANDLE self = GetCurrentProcess();
|
||||
PROCESS_MEMORY_COUNTERS counters;
|
||||
@@ -320,6 +295,20 @@ U64 getCurrentRSS()
|
||||
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)
|
||||
|
||||
/*
|
||||
@@ -344,7 +333,7 @@ U64 getCurrentRSS()
|
||||
// }
|
||||
// }
|
||||
|
||||
U64 getCurrentRSS()
|
||||
U64 LLMemory::getCurrentRSS()
|
||||
{
|
||||
U64 residentSize = 0;
|
||||
task_basic_info_data_t basicInfo;
|
||||
@@ -366,9 +355,14 @@ U64 getCurrentRSS()
|
||||
return residentSize;
|
||||
}
|
||||
|
||||
U32 LLMemory::getWorkingSetSize()
|
||||
{
|
||||
return 0 ;
|
||||
}
|
||||
|
||||
#elif defined(LL_LINUX)
|
||||
|
||||
U64 getCurrentRSS()
|
||||
U64 LLMemory::getCurrentRSS()
|
||||
{
|
||||
static const char statPath[] = "/proc/self/stat";
|
||||
LLFILE *fp = LLFile::fopen(statPath, "r");
|
||||
@@ -400,6 +394,10 @@ bail:
|
||||
return rss;
|
||||
}
|
||||
|
||||
U32 LLMemory::getWorkingSetSize()
|
||||
{
|
||||
return 0 ;
|
||||
}
|
||||
#elif LL_SOLARIS
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
@@ -407,7 +405,7 @@ bail:
|
||||
#define _STRUCTURED_PROC 1
|
||||
#include <sys/procfs.h>
|
||||
|
||||
U64 getCurrentRSS()
|
||||
U64 LLMemory::getCurrentRSS()
|
||||
{
|
||||
char path [LL_MAX_PATH]; /* Flawfinder: ignore */
|
||||
|
||||
@@ -428,11 +426,22 @@ U64 getCurrentRSS()
|
||||
|
||||
return((U64)proc_psinfo.pr_rssize * 1024);
|
||||
}
|
||||
|
||||
U32 LLMemory::getWorkingSetSize()
|
||||
{
|
||||
return 0 ;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
U64 getCurrentRSS()
|
||||
U64 LLMemory::getCurrentRSS()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
U32 LLMemory::getWorkingSetSize()
|
||||
{
|
||||
return 0 ;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -29,453 +29,115 @@
|
||||
* COMPLETENESS OR PERFORMANCE.
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
#ifndef LL_MEMORY_H
|
||||
#define LL_MEMORY_H
|
||||
#ifndef LLMEMORY_H
|
||||
#define LLMEMORY_H
|
||||
|
||||
|
||||
#include <new>
|
||||
#include <cstdlib>
|
||||
#if !LL_WINDOWS
|
||||
#include <stdint.h> // uintptr_t
|
||||
#endif
|
||||
|
||||
#include "llerror.h"
|
||||
|
||||
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
|
||||
{
|
||||
public:
|
||||
static void initClass();
|
||||
static void cleanupClass();
|
||||
static void freeReserve();
|
||||
// Return the resident set size of the current process, in bytes.
|
||||
// Return value is zero if not known.
|
||||
static U64 getCurrentRSS();
|
||||
static U32 getWorkingSetSize();
|
||||
private:
|
||||
static char* reserveMem;
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// RefCount objects should generally only be accessed by way of LLPointer<>'s
|
||||
// NOTE: LLPointer<LLFoo> x = new LLFoo(); MAY NOT BE THREAD SAFE
|
||||
// if LLFoo::LLFoo() does anything like put itself in an update queue.
|
||||
// The queue may get accessed before it gets assigned to x.
|
||||
// The correct implementation is:
|
||||
// LLPointer<LLFoo> x = new LLFoo; // constructor does not do anything interesting
|
||||
// x->instantiate(); // does stuff like place x into an update queue
|
||||
|
||||
// see llthread.h for LLThreadSafeRefCount
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
class LL_COMMON_API LLRefCount
|
||||
{
|
||||
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();
|
||||
//EVENTUALLY REMOVE THESE:
|
||||
#include "llpointer.h"
|
||||
#include "llrefcount.h"
|
||||
#include "llsingleton.h"
|
||||
#include "llsafehandle.h"
|
||||
|
||||
#endif
|
||||
|
||||
@@ -74,9 +74,3 @@ void LLMortician::setZealous(BOOL b)
|
||||
{
|
||||
sDestroyImmediate = b;
|
||||
}
|
||||
|
||||
// static
|
||||
BOOL LLMortician::getZealous()
|
||||
{
|
||||
return sDestroyImmediate;
|
||||
}
|
||||
|
||||
@@ -46,7 +46,6 @@ public:
|
||||
|
||||
// sets destroy immediate true
|
||||
static void setZealous(BOOL b);
|
||||
static BOOL getZealous();
|
||||
|
||||
private:
|
||||
static BOOL sDestroyImmediate;
|
||||
|
||||
170
indra/llcommon/llpointer.h
Normal file
170
indra/llcommon/llpointer.h
Normal file
@@ -0,0 +1,170 @@
|
||||
/**
|
||||
* @file llpointer.h
|
||||
* @brief A reference-counted pointer for objects derived from LLRefCount
|
||||
*
|
||||
* $LicenseInfo:firstyear=2002&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2010, Linden Research, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
#ifndef LLPOINTER_H
|
||||
#define LLPOINTER_H
|
||||
|
||||
#include "llerror.h" // *TODO: consider eliminating this
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// RefCount objects should generally only be accessed by way of LLPointer<>'s
|
||||
// NOTE: LLPointer<LLFoo> x = new LLFoo(); MAY NOT BE THREAD SAFE
|
||||
// if LLFoo::LLFoo() does anything like put itself in an update queue.
|
||||
// The queue may get accessed before it gets assigned to x.
|
||||
// The correct implementation is:
|
||||
// LLPointer<LLFoo> x = new LLFoo; // constructor does not do anything interesting
|
||||
// x->instantiate(); // does stuff like place x into an update queue
|
||||
|
||||
// see llthread.h for LLThreadSafeRefCount
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
// Note: relies on Type having ref() and unref() methods
|
||||
template <class Type> class LLPointer
|
||||
{
|
||||
public:
|
||||
|
||||
LLPointer() :
|
||||
mPointer(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
LLPointer(Type* ptr) :
|
||||
mPointer(ptr)
|
||||
{
|
||||
ref();
|
||||
}
|
||||
|
||||
LLPointer(const LLPointer<Type>& ptr) :
|
||||
mPointer(ptr.mPointer)
|
||||
{
|
||||
ref();
|
||||
}
|
||||
|
||||
// support conversion up the type hierarchy. See Item 45 in Effective C++, 3rd Ed.
|
||||
template<typename Subclass>
|
||||
LLPointer(const LLPointer<Subclass>& ptr) :
|
||||
mPointer(ptr.get())
|
||||
{
|
||||
ref();
|
||||
}
|
||||
|
||||
~LLPointer()
|
||||
{
|
||||
unref();
|
||||
}
|
||||
|
||||
Type* get() const { return mPointer; }
|
||||
const Type* operator->() const { return mPointer; }
|
||||
Type* operator->() { return mPointer; }
|
||||
const Type& operator*() const { return *mPointer; }
|
||||
Type& operator*() { return *mPointer; }
|
||||
|
||||
operator BOOL() const { return (mPointer != NULL); }
|
||||
operator bool() const { return (mPointer != NULL); }
|
||||
bool operator!() const { return (mPointer == NULL); }
|
||||
bool isNull() const { return (mPointer == NULL); }
|
||||
bool notNull() const { return (mPointer != NULL); }
|
||||
|
||||
operator Type*() const { return mPointer; }
|
||||
bool operator !=(Type* ptr) const { return (mPointer != ptr); }
|
||||
bool operator ==(Type* ptr) const { return (mPointer == ptr); }
|
||||
bool operator ==(const LLPointer<Type>& ptr) const { return (mPointer == ptr.mPointer); }
|
||||
bool operator < (const LLPointer<Type>& ptr) const { return (mPointer < ptr.mPointer); }
|
||||
bool operator > (const LLPointer<Type>& ptr) const { return (mPointer > ptr.mPointer); }
|
||||
|
||||
LLPointer<Type>& operator =(Type* ptr)
|
||||
{
|
||||
if( mPointer != ptr )
|
||||
{
|
||||
unref();
|
||||
mPointer = ptr;
|
||||
ref();
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
LLPointer<Type>& operator =(const LLPointer<Type>& ptr)
|
||||
{
|
||||
if( mPointer != ptr.mPointer )
|
||||
{
|
||||
unref();
|
||||
mPointer = ptr.mPointer;
|
||||
ref();
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
// support assignment up the type hierarchy. See Item 45 in Effective C++, 3rd Ed.
|
||||
template<typename Subclass>
|
||||
LLPointer<Type>& operator =(const LLPointer<Subclass>& ptr)
|
||||
{
|
||||
if( mPointer != ptr.get() )
|
||||
{
|
||||
unref();
|
||||
mPointer = ptr.get();
|
||||
ref();
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Just exchange the pointers, which will not change the reference counts.
|
||||
static void swap(LLPointer<Type>& a, LLPointer<Type>& b)
|
||||
{
|
||||
Type* temp = a.mPointer;
|
||||
a.mPointer = b.mPointer;
|
||||
b.mPointer = temp;
|
||||
}
|
||||
|
||||
protected:
|
||||
void ref()
|
||||
{
|
||||
if (mPointer)
|
||||
{
|
||||
mPointer->ref();
|
||||
}
|
||||
}
|
||||
|
||||
void unref()
|
||||
{
|
||||
if (mPointer)
|
||||
{
|
||||
Type *tempp = mPointer;
|
||||
mPointer = NULL;
|
||||
tempp->unref();
|
||||
if (mPointer != NULL)
|
||||
{
|
||||
llwarns << "Unreference did assignment to non-NULL because of destructor" << llendl;
|
||||
unref();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
Type* mPointer;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -107,7 +107,17 @@
|
||||
|
||||
#endif
|
||||
|
||||
// Deal with the differences on Windows
|
||||
|
||||
// Static linking with apr on windows needs to be declared.
|
||||
#if LL_WINDOWS && !LL_COMMON_LINK_SHARED
|
||||
#ifndef APR_DECLARE_STATIC
|
||||
#define APR_DECLARE_STATIC // For APR on Windows
|
||||
#endif
|
||||
#ifndef APU_DECLARE_STATIC
|
||||
#define APU_DECLARE_STATIC // For APR util on Windows
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(LL_WINDOWS)
|
||||
#define BOOST_REGEX_NO_LIB 1
|
||||
#define CURL_STATICLIB 1
|
||||
@@ -159,12 +169,19 @@
|
||||
#define LL_DLLIMPORT
|
||||
#endif // LL_WINDOWS
|
||||
|
||||
#ifdef llcommon_EXPORTS
|
||||
// Compiling llcommon (shared)
|
||||
#define LL_COMMON_API LL_DLLEXPORT
|
||||
#else // llcommon_EXPORTS
|
||||
// Using llcommon (shared)
|
||||
#define LL_COMMON_API LL_DLLIMPORT
|
||||
#endif // llcommon_EXPORTS
|
||||
#if LL_COMMON_LINK_SHARED
|
||||
// CMake automagically defines llcommon_EXPORTS only when building llcommon
|
||||
// sources, and only when llcommon is a shared library (i.e. when
|
||||
// LL_COMMON_LINK_SHARED). We must still test LL_COMMON_LINK_SHARED because
|
||||
// otherwise we can't distinguish between (non-llcommon source) and (llcommon
|
||||
// not shared).
|
||||
# if defined(llcommon_EXPORTS)
|
||||
# define LL_COMMON_API LL_DLLEXPORT
|
||||
# else //llcommon_EXPORTS
|
||||
# define LL_COMMON_API LL_DLLIMPORT
|
||||
# endif //llcommon_EXPORTS
|
||||
#else // LL_COMMON_LINK_SHARED
|
||||
# define LL_COMMON_API
|
||||
#endif // LL_COMMON_LINK_SHARED
|
||||
|
||||
#endif // not LL_LINDEN_PREPROCESSOR_H
|
||||
|
||||
@@ -102,7 +102,7 @@ int LLProcessLauncher::launch(void)
|
||||
STARTUPINFOA sinfo;
|
||||
memset(&sinfo, 0, sizeof(sinfo));
|
||||
|
||||
std::string args = "\"" + mExecutable + "\"";
|
||||
std::string args = mExecutable;
|
||||
for(int i = 0; i < (int)mLaunchArguments.size(); i++)
|
||||
{
|
||||
args += " ";
|
||||
@@ -114,10 +114,30 @@ int LLProcessLauncher::launch(void)
|
||||
char *args2 = new char[args.size() + 1];
|
||||
strcpy(args2, args.c_str());
|
||||
|
||||
if( ! CreateProcessA( NULL, args2, NULL, NULL, FALSE, 0, NULL, NULL, &sinfo, &pinfo ) )
|
||||
const char * working_directory = 0;
|
||||
if(!mWorkingDir.empty()) working_directory = mWorkingDir.c_str();
|
||||
if( ! CreateProcessA( NULL, args2, NULL, NULL, FALSE, 0, NULL, working_directory, &sinfo, &pinfo ) )
|
||||
{
|
||||
// TODO: do better than returning the OS-specific error code on failure...
|
||||
result = GetLastError();
|
||||
|
||||
LPTSTR error_str = 0;
|
||||
if(
|
||||
FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
|
||||
NULL,
|
||||
result,
|
||||
0,
|
||||
(LPTSTR)&error_str,
|
||||
0,
|
||||
NULL)
|
||||
!= 0)
|
||||
{
|
||||
char message[256];
|
||||
wcstombs(message, error_str, 256);
|
||||
message[255] = 0;
|
||||
llwarns << "CreateProcessA failed: " << message << llendl;
|
||||
LocalFree(error_str);
|
||||
}
|
||||
|
||||
if(result == 0)
|
||||
{
|
||||
// Make absolutely certain we return a non-zero value on failure.
|
||||
@@ -328,7 +348,11 @@ int LLProcessLauncher::launch(void)
|
||||
apr_file_t* out;
|
||||
AIAPRPool pool;
|
||||
pool.create();
|
||||
#if(APR_VERSION_MAJOR==1 && APR_VERSION_MINOR>=3 || APR_VERSION_MAJOR>1)
|
||||
apr_status_t status = apr_file_pipe_create_ex(&in, &out, APR_FULL_BLOCK, pool());
|
||||
#else
|
||||
apr_status_t status = apr_file_pipe_create(&in, &out, pool());
|
||||
#endif
|
||||
assert(status == APR_SUCCESS);
|
||||
bool success = (status == APR_SUCCESS);
|
||||
if (success)
|
||||
|
||||
@@ -31,8 +31,9 @@
|
||||
|
||||
#include "linden_common.h"
|
||||
#include "llqueuedthread.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),
|
||||
mThreaded(threaded),
|
||||
mIdleThread(TRUE),
|
||||
mNextHandle(0)
|
||||
mNextHandle(0),
|
||||
mStarted(FALSE)
|
||||
{
|
||||
if (mThreaded)
|
||||
{
|
||||
@@ -52,6 +54,10 @@ LLQueuedThread::LLQueuedThread(const std::string& name, bool threaded) :
|
||||
// MAIN THREAD
|
||||
LLQueuedThread::~LLQueuedThread()
|
||||
{
|
||||
if (!mThreaded)
|
||||
{
|
||||
endThread();
|
||||
}
|
||||
shutdown();
|
||||
// ~LLThread() will be called here
|
||||
}
|
||||
@@ -90,6 +96,7 @@ void LLQueuedThread::shutdown()
|
||||
if (req->getStatus() == STATUS_QUEUED || req->getStatus() == STATUS_INPROGRESS)
|
||||
{
|
||||
++active_count;
|
||||
req->setStatus(STATUS_ABORTED); // avoid assert in deleteRequest
|
||||
}
|
||||
req->deleteRequest();
|
||||
}
|
||||
@@ -105,6 +112,14 @@ void LLQueuedThread::shutdown()
|
||||
// virtual
|
||||
S32 LLQueuedThread::update(U32 max_time_ms)
|
||||
{
|
||||
if (!mStarted)
|
||||
{
|
||||
if (!mThreaded)
|
||||
{
|
||||
startThread();
|
||||
mStarted = TRUE;
|
||||
}
|
||||
}
|
||||
return updateQueue(max_time_ms);
|
||||
}
|
||||
|
||||
@@ -118,8 +133,11 @@ S32 LLQueuedThread::updateQueue(U32 max_time_ms)
|
||||
if (mThreaded)
|
||||
{
|
||||
pending = getPending();
|
||||
if(pending > 0)
|
||||
{
|
||||
unpause();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
while (pending > 0)
|
||||
@@ -349,9 +367,9 @@ bool LLQueuedThread::completeRequest(handle_t handle)
|
||||
#if _DEBUG
|
||||
// llinfos << llformat("LLQueuedThread::Completed req [%08d]",handle) << llendl;
|
||||
#endif
|
||||
//re insert to the queue to schedule for a delete later
|
||||
req->setStatus(STATUS_DELETE);
|
||||
mRequestQueue.insert(req);
|
||||
mRequestHash.erase(handle);
|
||||
req->deleteRequest();
|
||||
// check();
|
||||
res = true;
|
||||
}
|
||||
unlockData();
|
||||
@@ -395,19 +413,11 @@ S32 LLQueuedThread::processNextRequest()
|
||||
}
|
||||
req = *mRequestQueue.begin();
|
||||
mRequestQueue.erase(mRequestQueue.begin());
|
||||
|
||||
if(req->getStatus() == STATUS_DELETE)
|
||||
{
|
||||
mRequestHash.erase(req);
|
||||
req->deleteRequest();
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((req->getFlags() & FLAG_ABORT) || (mStatus == QUITTING))
|
||||
{
|
||||
req->setStatus(STATUS_ABORTED);
|
||||
req->finishRequest(false);
|
||||
if ((req->getFlags() & FLAG_AUTO_COMPLETE))
|
||||
if (req->getFlags() & FLAG_AUTO_COMPLETE)
|
||||
{
|
||||
mRequestHash.erase(req);
|
||||
req->deleteRequest();
|
||||
@@ -418,9 +428,11 @@ S32 LLQueuedThread::processNextRequest()
|
||||
llassert_always(req->getStatus() == STATUS_QUEUED);
|
||||
break;
|
||||
}
|
||||
U32 start_priority = 0 ;
|
||||
if (req)
|
||||
{
|
||||
req->setStatus(STATUS_INPROGRESS);
|
||||
start_priority = req->getPriority();
|
||||
}
|
||||
unlockData();
|
||||
|
||||
@@ -436,13 +448,12 @@ S32 LLQueuedThread::processNextRequest()
|
||||
{
|
||||
lockData();
|
||||
req->setStatus(STATUS_COMPLETE);
|
||||
|
||||
req->finishRequest(true);
|
||||
|
||||
if ((req->getFlags() & FLAG_AUTO_COMPLETE))
|
||||
if (req->getFlags() & FLAG_AUTO_COMPLETE)
|
||||
{
|
||||
mRequestHash.erase(req);
|
||||
req->deleteRequest();
|
||||
// check();
|
||||
}
|
||||
unlockData();
|
||||
}
|
||||
@@ -451,9 +462,8 @@ S32 LLQueuedThread::processNextRequest()
|
||||
lockData();
|
||||
req->setStatus(STATUS_QUEUED);
|
||||
mRequestQueue.insert(req);
|
||||
U32 priority = req->getPriority();
|
||||
unlockData();
|
||||
if (priority < PRIORITY_NORMAL)
|
||||
if (mThreaded && start_priority < PRIORITY_NORMAL)
|
||||
{
|
||||
ms_sleep(1); // sleep the thread a little
|
||||
}
|
||||
@@ -481,6 +491,7 @@ void LLQueuedThread::run()
|
||||
// call checPause() immediately so we don't try to do anything before the class is fully constructed
|
||||
checkPause();
|
||||
startThread();
|
||||
mStarted = TRUE;
|
||||
|
||||
while (1)
|
||||
{
|
||||
|
||||
@@ -184,7 +184,7 @@ public:
|
||||
void waitOnPending();
|
||||
void printQueueStats();
|
||||
|
||||
S32 getPending();
|
||||
virtual S32 getPending();
|
||||
bool getThreaded() { return mThreaded ? true : false; }
|
||||
|
||||
// Request accessors
|
||||
@@ -202,6 +202,7 @@ public:
|
||||
|
||||
protected:
|
||||
BOOL mThreaded; // if false, run on main thread and do updates during update()
|
||||
BOOL mStarted; // required when mThreaded is false to call startThread() from update()
|
||||
LLAtomic32<BOOL> mIdleThread; // request queue is empty (or we are quitting) and the thread is idle
|
||||
|
||||
typedef std::set<QueuedRequest*, queued_request_less> request_queue_t;
|
||||
|
||||
164
indra/llcommon/llrefcount.cpp
Normal file
164
indra/llcommon/llrefcount.cpp
Normal file
@@ -0,0 +1,164 @@
|
||||
/**
|
||||
* @file llrefcount.cpp
|
||||
* @brief Base class for reference counted objects for use with LLPointer
|
||||
*
|
||||
* $LicenseInfo:firstyear=2002&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2010, Linden Research, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
#include "linden_common.h"
|
||||
|
||||
#include "llrefcount.h"
|
||||
|
||||
#include "llerror.h"
|
||||
|
||||
#if LL_REF_COUNT_DEBUG
|
||||
#include "llthread.h"
|
||||
#include "llapr.h"
|
||||
#endif
|
||||
|
||||
LLRefCount::LLRefCount(const LLRefCount& other)
|
||||
: mRef(0)
|
||||
{
|
||||
#if LL_REF_COUNT_DEBUG
|
||||
if(gAPRPoolp)
|
||||
{
|
||||
mMutexp = new LLMutex(gAPRPoolp) ;
|
||||
}
|
||||
else
|
||||
{
|
||||
mMutexp = NULL ;
|
||||
}
|
||||
mCrashAtUnlock = FALSE ;
|
||||
#endif
|
||||
}
|
||||
|
||||
LLRefCount& LLRefCount::operator=(const LLRefCount&)
|
||||
{
|
||||
// do nothing, since ref count is specific to *this* reference
|
||||
return *this;
|
||||
}
|
||||
|
||||
LLRefCount::LLRefCount() :
|
||||
mRef(0)
|
||||
{
|
||||
#if LL_REF_COUNT_DEBUG
|
||||
if(gAPRPoolp)
|
||||
{
|
||||
mMutexp = new LLMutex(gAPRPoolp) ;
|
||||
}
|
||||
else
|
||||
{
|
||||
mMutexp = NULL ;
|
||||
}
|
||||
mCrashAtUnlock = FALSE ;
|
||||
#endif
|
||||
}
|
||||
|
||||
LLRefCount::~LLRefCount()
|
||||
{
|
||||
if (mRef != 0)
|
||||
{
|
||||
llerrs << "deleting non-zero reference" << llendl;
|
||||
}
|
||||
|
||||
#if LL_REF_COUNT_DEBUG
|
||||
if(gAPRPoolp)
|
||||
{
|
||||
delete mMutexp ;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#if LL_REF_COUNT_DEBUG
|
||||
void LLRefCount::ref() const
|
||||
{
|
||||
if(mMutexp)
|
||||
{
|
||||
if(mMutexp->isLocked())
|
||||
{
|
||||
mCrashAtUnlock = TRUE ;
|
||||
llerrs << "the mutex is locked by the thread: " << mLockedThreadID
|
||||
<< " Current thread: " << LLThread::currentID() << llendl ;
|
||||
}
|
||||
|
||||
mMutexp->lock() ;
|
||||
mLockedThreadID = LLThread::currentID() ;
|
||||
|
||||
mRef++;
|
||||
|
||||
if(mCrashAtUnlock)
|
||||
{
|
||||
while(1); //crash here.
|
||||
}
|
||||
mMutexp->unlock() ;
|
||||
}
|
||||
else
|
||||
{
|
||||
mRef++;
|
||||
}
|
||||
}
|
||||
|
||||
S32 LLRefCount::unref() const
|
||||
{
|
||||
if(mMutexp)
|
||||
{
|
||||
if(mMutexp->isLocked())
|
||||
{
|
||||
mCrashAtUnlock = TRUE ;
|
||||
llerrs << "the mutex is locked by the thread: " << mLockedThreadID
|
||||
<< " Current thread: " << LLThread::currentID() << llendl ;
|
||||
}
|
||||
|
||||
mMutexp->lock() ;
|
||||
mLockedThreadID = LLThread::currentID() ;
|
||||
|
||||
llassert(mRef >= 1);
|
||||
if (0 == --mRef)
|
||||
{
|
||||
if(mCrashAtUnlock)
|
||||
{
|
||||
while(1); //crash here.
|
||||
}
|
||||
mMutexp->unlock() ;
|
||||
|
||||
delete this;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(mCrashAtUnlock)
|
||||
{
|
||||
while(1); //crash here.
|
||||
}
|
||||
mMutexp->unlock() ;
|
||||
return mRef;
|
||||
}
|
||||
else
|
||||
{
|
||||
llassert(mRef >= 1);
|
||||
if (0 == --mRef)
|
||||
{
|
||||
delete this;
|
||||
return 0;
|
||||
}
|
||||
return mRef;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
89
indra/llcommon/llrefcount.h
Normal file
89
indra/llcommon/llrefcount.h
Normal file
@@ -0,0 +1,89 @@
|
||||
/**
|
||||
* @file llrefcount.h
|
||||
* @brief Base class for reference counted objects for use with LLPointer
|
||||
*
|
||||
* $LicenseInfo:firstyear=2002&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2010, Linden Research, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
#ifndef LLREFCOUNT_H
|
||||
#define LLREFCOUNT_H
|
||||
|
||||
#include <boost/noncopyable.hpp>
|
||||
|
||||
#define LL_REF_COUNT_DEBUG 0
|
||||
#if LL_REF_COUNT_DEBUG
|
||||
class LLMutex ;
|
||||
#endif
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// RefCount objects should generally only be accessed by way of LLPointer<>'s
|
||||
// see llthread.h for LLThreadSafeRefCount
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
class LL_COMMON_API LLRefCount
|
||||
{
|
||||
protected:
|
||||
LLRefCount(const LLRefCount& other);
|
||||
LLRefCount& operator=(const LLRefCount&);
|
||||
virtual ~LLRefCount(); // use unref()
|
||||
|
||||
public:
|
||||
LLRefCount();
|
||||
|
||||
#if LL_REF_COUNT_DEBUG
|
||||
void ref() const ;
|
||||
S32 unref() const ;
|
||||
#else
|
||||
inline void ref() const
|
||||
{
|
||||
mRef++;
|
||||
}
|
||||
|
||||
inline S32 unref() const
|
||||
{
|
||||
llassert(mRef >= 1);
|
||||
if (0 == --mRef)
|
||||
{
|
||||
delete this;
|
||||
return 0;
|
||||
}
|
||||
return mRef;
|
||||
}
|
||||
#endif
|
||||
|
||||
//NOTE: when passing around a const LLRefCount object, this can return different results
|
||||
// at different types, since mRef is mutable
|
||||
S32 getNumRefs() const
|
||||
{
|
||||
return mRef;
|
||||
}
|
||||
|
||||
private:
|
||||
mutable S32 mRef;
|
||||
|
||||
#if LL_REF_COUNT_DEBUG
|
||||
LLMutex* mMutexp ;
|
||||
mutable U32 mLockedThreadID ;
|
||||
mutable BOOL mCrashAtUnlock ;
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif
|
||||
162
indra/llcommon/llsafehandle.h
Normal file
162
indra/llcommon/llsafehandle.h
Normal file
@@ -0,0 +1,162 @@
|
||||
/**
|
||||
* @file llsafehandle.h
|
||||
* @brief Reference-counted object where Object() is valid, not NULL.
|
||||
*
|
||||
* $LicenseInfo:firstyear=2002&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2010, Linden Research, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
#ifndef LLSAFEHANDLE_H
|
||||
#define LLSAFEHANDLE_H
|
||||
|
||||
#include "llerror.h" // *TODO: consider eliminating this
|
||||
|
||||
// Expands LLPointer to return a pointer to a special instance of class Type instead of NULL.
|
||||
// This is useful in instances where operations on NULL pointers are semantically safe and/or
|
||||
// when error checking occurs at a different granularity or in a different part of the code
|
||||
// than when referencing an object via a LLSafeHandle.
|
||||
|
||||
template <class Type>
|
||||
class LLSafeHandle
|
||||
{
|
||||
public:
|
||||
LLSafeHandle() :
|
||||
mPointer(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
LLSafeHandle(Type* ptr) :
|
||||
mPointer(NULL)
|
||||
{
|
||||
assign(ptr);
|
||||
}
|
||||
|
||||
LLSafeHandle(const LLSafeHandle<Type>& ptr) :
|
||||
mPointer(NULL)
|
||||
{
|
||||
assign(ptr.mPointer);
|
||||
}
|
||||
|
||||
// support conversion up the type hierarchy. See Item 45 in Effective C++, 3rd Ed.
|
||||
template<typename Subclass>
|
||||
LLSafeHandle(const LLSafeHandle<Subclass>& ptr) :
|
||||
mPointer(NULL)
|
||||
{
|
||||
assign(ptr.get());
|
||||
}
|
||||
|
||||
~LLSafeHandle()
|
||||
{
|
||||
unref();
|
||||
}
|
||||
|
||||
const Type* operator->() const { return nonNull(mPointer); }
|
||||
Type* operator->() { return nonNull(mPointer); }
|
||||
|
||||
Type* get() const { return mPointer; }
|
||||
void clear() { assign(NULL); }
|
||||
// we disallow these operations as they expose our null objects to direct manipulation
|
||||
// and bypass the reference counting semantics
|
||||
//const Type& operator*() const { return *nonNull(mPointer); }
|
||||
//Type& operator*() { return *nonNull(mPointer); }
|
||||
|
||||
operator BOOL() const { return mPointer != NULL; }
|
||||
operator bool() const { return mPointer != NULL; }
|
||||
bool operator!() const { return mPointer == NULL; }
|
||||
bool isNull() const { return mPointer == NULL; }
|
||||
bool notNull() const { return mPointer != NULL; }
|
||||
|
||||
|
||||
operator Type*() const { return mPointer; }
|
||||
operator const Type*() const { return mPointer; }
|
||||
bool operator !=(Type* ptr) const { return (mPointer != ptr); }
|
||||
bool operator ==(Type* ptr) const { return (mPointer == ptr); }
|
||||
bool operator ==(const LLSafeHandle<Type>& ptr) const { return (mPointer == ptr.mPointer); }
|
||||
bool operator < (const LLSafeHandle<Type>& ptr) const { return (mPointer < ptr.mPointer); }
|
||||
bool operator > (const LLSafeHandle<Type>& ptr) const { return (mPointer > ptr.mPointer); }
|
||||
|
||||
LLSafeHandle<Type>& operator =(Type* ptr)
|
||||
{
|
||||
assign(ptr);
|
||||
return *this;
|
||||
}
|
||||
|
||||
LLSafeHandle<Type>& operator =(const LLSafeHandle<Type>& ptr)
|
||||
{
|
||||
assign(ptr.mPointer);
|
||||
return *this;
|
||||
}
|
||||
|
||||
// support assignment up the type hierarchy. See Item 45 in Effective C++, 3rd Ed.
|
||||
template<typename Subclass>
|
||||
LLSafeHandle<Type>& operator =(const LLSafeHandle<Subclass>& ptr)
|
||||
{
|
||||
assign(ptr.get());
|
||||
return *this;
|
||||
}
|
||||
|
||||
public:
|
||||
typedef Type* (*NullFunc)();
|
||||
static const NullFunc sNullFunc;
|
||||
|
||||
protected:
|
||||
void ref()
|
||||
{
|
||||
if (mPointer)
|
||||
{
|
||||
mPointer->ref();
|
||||
}
|
||||
}
|
||||
|
||||
void unref()
|
||||
{
|
||||
if (mPointer)
|
||||
{
|
||||
Type *tempp = mPointer;
|
||||
mPointer = NULL;
|
||||
tempp->unref();
|
||||
if (mPointer != NULL)
|
||||
{
|
||||
llwarns << "Unreference did assignment to non-NULL because of destructor" << llendl;
|
||||
unref();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void assign(Type* ptr)
|
||||
{
|
||||
if( mPointer != ptr )
|
||||
{
|
||||
unref();
|
||||
mPointer = ptr;
|
||||
ref();
|
||||
}
|
||||
}
|
||||
|
||||
static Type* nonNull(Type* ptr)
|
||||
{
|
||||
return ptr == NULL ? sNullFunc() : ptr;
|
||||
}
|
||||
|
||||
protected:
|
||||
Type* mPointer;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -754,11 +754,7 @@ void LLSD::insert(const String& k, const LLSD& v) { makeMap(impl).insert(k, v);
|
||||
LLSD& LLSD::with(const String& k, const LLSD& v)
|
||||
{
|
||||
makeMap(impl).insert(k, v);
|
||||
#ifdef LL_MSVC7
|
||||
return *dynamic_cast<LLSD*>(this);
|
||||
#else
|
||||
return *this;
|
||||
#endif
|
||||
return *this;
|
||||
}
|
||||
void LLSD::erase(const String& k) { makeMap(impl).erase(k); }
|
||||
|
||||
@@ -784,11 +780,7 @@ void LLSD::insert(Integer i, const LLSD& v) { makeArray(impl).insert(i, v); }
|
||||
LLSD& LLSD::with(Integer i, const LLSD& v)
|
||||
{
|
||||
makeArray(impl).insert(i, v);
|
||||
#ifdef LL_MSVC7
|
||||
return *dynamic_cast<LLSD*>(this);
|
||||
#else
|
||||
return *this;
|
||||
#endif
|
||||
return *this;
|
||||
}
|
||||
void LLSD::append(const LLSD& v) { makeArray(impl).append(v); }
|
||||
void LLSD::erase(Integer i) { makeArray(impl).erase(i); }
|
||||
|
||||
@@ -34,11 +34,18 @@
|
||||
|
||||
#include "linden_common.h"
|
||||
#include "llsdserialize.h"
|
||||
#include "llmemory.h"
|
||||
#include "llpointer.h"
|
||||
#include "llstreamtools.h" // for fullread
|
||||
|
||||
#include <iostream>
|
||||
#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
|
||||
#include <netinet/in.h> // htonl & ntohl
|
||||
@@ -1990,3 +1997,181 @@ std::ostream& operator<<(std::ostream& s, const LLSD& llsd)
|
||||
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
|
||||
|
||||
#include <iosfwd>
|
||||
#include "llpointer.h"
|
||||
#include "llrefcount.h"
|
||||
#include "llsd.h"
|
||||
#include "llmemory.h"
|
||||
|
||||
/**
|
||||
* @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
|
||||
|
||||
@@ -37,6 +37,7 @@
|
||||
#include <deque>
|
||||
|
||||
#include "apr_base64.h"
|
||||
#include <boost/regex.hpp>
|
||||
|
||||
extern "C"
|
||||
{
|
||||
@@ -734,6 +735,7 @@ void LLSDXMLParser::Impl::endElementHandler(const XML_Char* name)
|
||||
case ELEMENT_INTEGER:
|
||||
{
|
||||
S32 i;
|
||||
// sscanf okay here with different locales - ints don't change for different locale settings like floats do.
|
||||
if ( sscanf(mCurrentContent.c_str(), "%d", &i ) == 1 )
|
||||
{ // See if sscanf works - it's faster
|
||||
value = i;
|
||||
@@ -747,15 +749,19 @@ void LLSDXMLParser::Impl::endElementHandler(const XML_Char* name)
|
||||
|
||||
case ELEMENT_REAL:
|
||||
{
|
||||
F64 r;
|
||||
if ( sscanf(mCurrentContent.c_str(), "%lf", &r ) == 1 )
|
||||
{ // See if sscanf works - it's faster
|
||||
value = r;
|
||||
}
|
||||
else
|
||||
{
|
||||
value = LLSD(mCurrentContent).asReal();
|
||||
}
|
||||
value = LLSD(mCurrentContent).asReal();
|
||||
// removed since this breaks when locale has decimal separator that isn't '.'
|
||||
// investigated changing local to something compatible each time but deemed higher
|
||||
// risk that just using LLSD.asReal() each time.
|
||||
//F64 r;
|
||||
//if ( sscanf(mCurrentContent.c_str(), "%lf", &r ) == 1 )
|
||||
//{ // See if sscanf works - it's faster
|
||||
// value = r;
|
||||
//}
|
||||
//else
|
||||
//{
|
||||
// value = LLSD(mCurrentContent).asReal();
|
||||
//}
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -777,10 +783,17 @@ void LLSDXMLParser::Impl::endElementHandler(const XML_Char* name)
|
||||
|
||||
case ELEMENT_BINARY:
|
||||
{
|
||||
S32 len = apr_base64_decode_len(mCurrentContent.c_str());
|
||||
// Regex is expensive, but only fix for whitespace in base64,
|
||||
// created by python and other non-linden systems - DEV-39358
|
||||
// Fortunately we have very little binary passing now,
|
||||
// so performance impact shold be negligible. + poppy 2009-09-04
|
||||
boost::regex r;
|
||||
r.assign("\\s");
|
||||
std::string stripped = boost::regex_replace(mCurrentContent, r, "");
|
||||
S32 len = apr_base64_decode_len(stripped.c_str());
|
||||
std::vector<U8> data;
|
||||
data.resize(len);
|
||||
len = apr_base64_decode_binary(&data[0], mCurrentContent.c_str());
|
||||
len = apr_base64_decode_binary(&data[0], stripped.c_str());
|
||||
data.resize(len);
|
||||
value = data;
|
||||
break;
|
||||
|
||||
@@ -46,6 +46,12 @@
|
||||
#endif
|
||||
|
||||
#include "llsdserialize.h"
|
||||
#include "stringize.h"
|
||||
#include "is_approx_equal_fraction.h"
|
||||
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <boost/range.hpp>
|
||||
|
||||
// U32
|
||||
LLSD ll_sd_from_U32(const U32 val)
|
||||
@@ -171,6 +177,15 @@ char* ll_print_sd(const LLSD& sd)
|
||||
return buffer;
|
||||
}
|
||||
|
||||
char* ll_pretty_print_sd_ptr(const LLSD* sd)
|
||||
{
|
||||
if (sd)
|
||||
{
|
||||
return ll_pretty_print_sd(*sd);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char* ll_pretty_print_sd(const LLSD& sd)
|
||||
{
|
||||
const U32 bufferSize = 10 * 1024;
|
||||
@@ -304,3 +319,363 @@ BOOL compare_llsd_with_template(
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* Helpers for llsd_matches()
|
||||
*****************************************************************************/
|
||||
// raw data used for LLSD::Type lookup
|
||||
struct Data
|
||||
{
|
||||
LLSD::Type type;
|
||||
const char* name;
|
||||
} typedata[] =
|
||||
{
|
||||
#define def(type) { LLSD::type, #type + 4 }
|
||||
def(TypeUndefined),
|
||||
def(TypeBoolean),
|
||||
def(TypeInteger),
|
||||
def(TypeReal),
|
||||
def(TypeString),
|
||||
def(TypeUUID),
|
||||
def(TypeDate),
|
||||
def(TypeURI),
|
||||
def(TypeBinary),
|
||||
def(TypeMap),
|
||||
def(TypeArray)
|
||||
#undef def
|
||||
};
|
||||
|
||||
// LLSD::Type lookup class into which we load the above static data
|
||||
class TypeLookup
|
||||
{
|
||||
typedef std::map<LLSD::Type, std::string> MapType;
|
||||
|
||||
public:
|
||||
TypeLookup()
|
||||
{
|
||||
for (const Data *di(boost::begin(typedata)), *dend(boost::end(typedata)); di != dend; ++di)
|
||||
{
|
||||
mMap[di->type] = di->name;
|
||||
}
|
||||
}
|
||||
|
||||
std::string lookup(LLSD::Type type) const
|
||||
{
|
||||
MapType::const_iterator found = mMap.find(type);
|
||||
if (found != mMap.end())
|
||||
{
|
||||
return found->second;
|
||||
}
|
||||
return STRINGIZE("<unknown LLSD type " << type << ">");
|
||||
}
|
||||
|
||||
private:
|
||||
MapType mMap;
|
||||
};
|
||||
|
||||
// static instance of the lookup class
|
||||
static const TypeLookup sTypes;
|
||||
|
||||
// describe a mismatch; phrasing may want tweaking
|
||||
const std::string op(" required instead of ");
|
||||
|
||||
// llsd_matches() wants to identify specifically where in a complex prototype
|
||||
// structure the mismatch occurred. This entails passing a prefix string,
|
||||
// empty for the top-level call. If the prototype contains an array of maps,
|
||||
// and the mismatch occurs in the second map in a key 'foo', we want to
|
||||
// decorate the returned string with: "[1]['foo']: etc." On the other hand, we
|
||||
// want to omit the entire prefix -- including colon -- if the mismatch is at
|
||||
// top level. This helper accepts the (possibly empty) recursively-accumulated
|
||||
// prefix string, returning either empty or the original string with colon
|
||||
// appended.
|
||||
static std::string colon(const std::string& pfx)
|
||||
{
|
||||
if (pfx.empty())
|
||||
return pfx;
|
||||
return pfx + ": ";
|
||||
}
|
||||
|
||||
// param type for match_types
|
||||
typedef std::vector<LLSD::Type> TypeVector;
|
||||
|
||||
// The scalar cases in llsd_matches() use this helper. In most cases, we can
|
||||
// accept not only the exact type specified in the prototype, but also other
|
||||
// types convertible to the expected type. That implies looping over an array
|
||||
// of such types. If the actual type doesn't match any of them, we want to
|
||||
// provide a list of acceptable conversions as well as the exact type, e.g.:
|
||||
// "Integer (or Boolean, Real, String) required instead of UUID". Both the
|
||||
// implementation and the calling logic are simplified by separating out the
|
||||
// expected type from the convertible types.
|
||||
static std::string match_types(LLSD::Type expect, // prototype.type()
|
||||
const TypeVector& accept, // types convertible to that type
|
||||
LLSD::Type actual, // type we're checking
|
||||
const std::string& pfx) // as for llsd_matches
|
||||
{
|
||||
// Trivial case: if the actual type is exactly what we expect, we're good.
|
||||
if (actual == expect)
|
||||
return "";
|
||||
|
||||
// For the rest of the logic, build up a suitable error string as we go so
|
||||
// we only have to make a single pass over the list of acceptable types.
|
||||
// If we detect success along the way, we'll simply discard the partial
|
||||
// error string.
|
||||
std::ostringstream out;
|
||||
out << colon(pfx) << sTypes.lookup(expect);
|
||||
|
||||
// If there are any convertible types, append that list.
|
||||
if (! accept.empty())
|
||||
{
|
||||
out << " (";
|
||||
const char* sep = "or ";
|
||||
for (TypeVector::const_iterator ai(accept.begin()), aend(accept.end());
|
||||
ai != aend; ++ai, sep = ", ")
|
||||
{
|
||||
// Don't forget to return success if we match any of those types...
|
||||
if (actual == *ai)
|
||||
return "";
|
||||
out << sep << sTypes.lookup(*ai);
|
||||
}
|
||||
out << ')';
|
||||
}
|
||||
// If we got this far, it's because 'actual' was not one of the acceptable
|
||||
// types, so we must return an error. 'out' already contains colon(pfx)
|
||||
// and the formatted list of acceptable types, so just append the mismatch
|
||||
// phrase and the actual type.
|
||||
out << op << sTypes.lookup(actual);
|
||||
return out.str();
|
||||
}
|
||||
|
||||
// see docstring in .h file
|
||||
std::string llsd_matches(const LLSD& prototype, const LLSD& data, const std::string& pfx)
|
||||
{
|
||||
// An undefined prototype means that any data is valid.
|
||||
// An undefined slot in an array or map prototype means that any data
|
||||
// may fill that slot.
|
||||
if (prototype.isUndefined())
|
||||
return "";
|
||||
// A prototype array must match a data array with at least as many
|
||||
// entries. Moreover, every prototype entry must match the
|
||||
// corresponding data entry.
|
||||
if (prototype.isArray())
|
||||
{
|
||||
if (! data.isArray())
|
||||
{
|
||||
return STRINGIZE(colon(pfx) << "Array" << op << sTypes.lookup(data.type()));
|
||||
}
|
||||
if (data.size() < prototype.size())
|
||||
{
|
||||
return STRINGIZE(colon(pfx) << "Array size " << prototype.size() << op
|
||||
<< "Array size " << data.size());
|
||||
}
|
||||
for (LLSD::Integer i = 0; i < prototype.size(); ++i)
|
||||
{
|
||||
std::string match(llsd_matches(prototype[i], data[i], STRINGIZE('[' << i << ']')));
|
||||
if (! match.empty())
|
||||
{
|
||||
return match;
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
// A prototype map must match a data map. Every key in the prototype
|
||||
// must have a corresponding key in the data map; every value in the
|
||||
// prototype must match the corresponding key's value in the data.
|
||||
if (prototype.isMap())
|
||||
{
|
||||
if (! data.isMap())
|
||||
{
|
||||
return STRINGIZE(colon(pfx) << "Map" << op << sTypes.lookup(data.type()));
|
||||
}
|
||||
// If there are a number of keys missing from the data, it would be
|
||||
// frustrating to a coder to discover them one at a time, with a big
|
||||
// build each time. Enumerate all missing keys.
|
||||
std::ostringstream out;
|
||||
out << colon(pfx);
|
||||
const char* init = "Map missing keys: ";
|
||||
const char* sep = init;
|
||||
for (LLSD::map_const_iterator mi = prototype.beginMap(); mi != prototype.endMap(); ++mi)
|
||||
{
|
||||
if (! data.has(mi->first))
|
||||
{
|
||||
out << sep << mi->first;
|
||||
sep = ", ";
|
||||
}
|
||||
}
|
||||
// So... are we missing any keys?
|
||||
if (sep != init)
|
||||
{
|
||||
return out.str();
|
||||
}
|
||||
// Good, the data block contains all the keys required by the
|
||||
// prototype. Now match the prototype entries.
|
||||
for (LLSD::map_const_iterator mi2 = prototype.beginMap(); mi2 != prototype.endMap(); ++mi2)
|
||||
{
|
||||
std::string match(llsd_matches(mi2->second, data[mi2->first],
|
||||
STRINGIZE("['" << mi2->first << "']")));
|
||||
if (! match.empty())
|
||||
{
|
||||
return match;
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
// A String prototype can match String, Boolean, Integer, Real, UUID,
|
||||
// Date and URI, because any of these can be converted to String.
|
||||
if (prototype.isString())
|
||||
{
|
||||
static LLSD::Type accept[] =
|
||||
{
|
||||
LLSD::TypeBoolean,
|
||||
LLSD::TypeInteger,
|
||||
LLSD::TypeReal,
|
||||
LLSD::TypeUUID,
|
||||
LLSD::TypeDate,
|
||||
LLSD::TypeURI
|
||||
};
|
||||
return match_types(prototype.type(),
|
||||
TypeVector(boost::begin(accept), boost::end(accept)),
|
||||
data.type(),
|
||||
pfx);
|
||||
}
|
||||
// Boolean, Integer, Real match each other or String. TBD: ensure that
|
||||
// a String value is numeric.
|
||||
if (prototype.isBoolean() || prototype.isInteger() || prototype.isReal())
|
||||
{
|
||||
static LLSD::Type all[] =
|
||||
{
|
||||
LLSD::TypeBoolean,
|
||||
LLSD::TypeInteger,
|
||||
LLSD::TypeReal,
|
||||
LLSD::TypeString
|
||||
};
|
||||
// Funny business: shuffle the set of acceptable types to include all
|
||||
// but the prototype's type. Get the acceptable types in a set.
|
||||
std::set<LLSD::Type> rest(boost::begin(all), boost::end(all));
|
||||
// Remove the prototype's type because we pass that separately.
|
||||
rest.erase(prototype.type());
|
||||
return match_types(prototype.type(),
|
||||
TypeVector(rest.begin(), rest.end()),
|
||||
data.type(),
|
||||
pfx);
|
||||
}
|
||||
// UUID, Date and URI match themselves or String.
|
||||
if (prototype.isUUID() || prototype.isDate() || prototype.isURI())
|
||||
{
|
||||
static LLSD::Type accept[] =
|
||||
{
|
||||
LLSD::TypeString
|
||||
};
|
||||
return match_types(prototype.type(),
|
||||
TypeVector(boost::begin(accept), boost::end(accept)),
|
||||
data.type(),
|
||||
pfx);
|
||||
}
|
||||
// We don't yet know the conversion semantics associated with any new LLSD
|
||||
// data type that might be added, so until we've been extended to handle
|
||||
// them, assume it's strict: the new type matches only itself. (This is
|
||||
// true of Binary, which is why we don't handle that case separately.) Too
|
||||
// bad LLSD doesn't define isConvertible(Type to, Type from).
|
||||
return match_types(prototype.type(), TypeVector(), data.type(), pfx);
|
||||
}
|
||||
|
||||
bool llsd_equals(const LLSD& lhs, const LLSD& rhs, unsigned bits)
|
||||
{
|
||||
// We're comparing strict equality of LLSD representation rather than
|
||||
// performing any conversions. So if the types aren't equal, the LLSD
|
||||
// values aren't equal.
|
||||
if (lhs.type() != rhs.type())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Here we know both types are equal. Now compare values.
|
||||
switch (lhs.type())
|
||||
{
|
||||
case LLSD::TypeUndefined:
|
||||
// Both are TypeUndefined. There's nothing more to know.
|
||||
return true;
|
||||
|
||||
case LLSD::TypeReal:
|
||||
// This is where the 'bits' argument comes in handy. If passed
|
||||
// explicitly, it means to use is_approx_equal_fraction() to compare.
|
||||
if (bits >= 0)
|
||||
{
|
||||
return is_approx_equal_fraction(lhs.asReal(), rhs.asReal(), bits);
|
||||
}
|
||||
// Otherwise we compare bit representations, and the usual caveats
|
||||
// about comparing floating-point numbers apply. Omitting 'bits' when
|
||||
// comparing Real values is only useful when we expect identical bit
|
||||
// representation for a given Real value, e.g. for integer-valued
|
||||
// Reals.
|
||||
return (lhs.asReal() == rhs.asReal());
|
||||
|
||||
#define COMPARE_SCALAR(type) \
|
||||
case LLSD::Type##type: \
|
||||
/* LLSD::URI has operator!=() but not operator==() */ \
|
||||
/* rely on the optimizer for all others */ \
|
||||
return (! (lhs.as##type() != rhs.as##type()))
|
||||
|
||||
COMPARE_SCALAR(Boolean);
|
||||
COMPARE_SCALAR(Integer);
|
||||
COMPARE_SCALAR(String);
|
||||
COMPARE_SCALAR(UUID);
|
||||
COMPARE_SCALAR(Date);
|
||||
COMPARE_SCALAR(URI);
|
||||
COMPARE_SCALAR(Binary);
|
||||
|
||||
#undef COMPARE_SCALAR
|
||||
|
||||
case LLSD::TypeArray:
|
||||
{
|
||||
LLSD::array_const_iterator
|
||||
lai(lhs.beginArray()), laend(lhs.endArray()),
|
||||
rai(rhs.beginArray()), raend(rhs.endArray());
|
||||
// Compare array elements, walking the two arrays in parallel.
|
||||
for ( ; lai != laend && rai != raend; ++lai, ++rai)
|
||||
{
|
||||
// If any one array element is unequal, the arrays are unequal.
|
||||
if (! llsd_equals(*lai, *rai, bits))
|
||||
return false;
|
||||
}
|
||||
// Here we've reached the end of one or the other array. They're equal
|
||||
// only if they're BOTH at end: that is, if they have equal length too.
|
||||
return (lai == laend && rai == raend);
|
||||
}
|
||||
|
||||
case LLSD::TypeMap:
|
||||
{
|
||||
// Build a set of all rhs keys.
|
||||
std::set<LLSD::String> rhskeys;
|
||||
for (LLSD::map_const_iterator rmi(rhs.beginMap()), rmend(rhs.endMap());
|
||||
rmi != rmend; ++rmi)
|
||||
{
|
||||
rhskeys.insert(rmi->first);
|
||||
}
|
||||
// Now walk all the lhs keys.
|
||||
for (LLSD::map_const_iterator lmi(lhs.beginMap()), lmend(lhs.endMap());
|
||||
lmi != lmend; ++lmi)
|
||||
{
|
||||
// Try to erase this lhs key from the set of rhs keys. If rhs has
|
||||
// no such key, the maps are unequal. erase(key) returns count of
|
||||
// items erased.
|
||||
if (rhskeys.erase(lmi->first) != 1)
|
||||
return false;
|
||||
// Both maps have the current key. Compare values.
|
||||
if (! llsd_equals(lmi->second, rhs[lmi->first], bits))
|
||||
return false;
|
||||
}
|
||||
// We've now established that all the lhs keys have equal values in
|
||||
// both maps. The maps are equal unless rhs contains a superset of
|
||||
// those keys.
|
||||
return rhskeys.empty();
|
||||
}
|
||||
|
||||
default:
|
||||
// We expect that every possible type() value is specifically handled
|
||||
// above. Failing to extend this switch to support a new LLSD type is
|
||||
// an error that must be brought to the coder's attention.
|
||||
LL_ERRS("llsd_equals") << "llsd_equals(" << lhs << ", " << rhs << ", " << bits << "): "
|
||||
"unknown type " << lhs.type() << LL_ENDL;
|
||||
return false; // pacify the compiler
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
#ifndef LL_LLSDUTIL_H
|
||||
#define LL_LLSDUTIL_H
|
||||
|
||||
#include "llsd.h"
|
||||
class LLSD;
|
||||
|
||||
// U32
|
||||
LL_COMMON_API LLSD ll_sd_from_U32(const U32);
|
||||
@@ -59,6 +59,7 @@ LL_COMMON_API LLSD ll_binary_from_string(const LLSD& sd);
|
||||
LL_COMMON_API char* ll_print_sd(const LLSD& sd);
|
||||
|
||||
// Serializes sd to static buffer and returns pointer, using "pretty printing" mode.
|
||||
LL_COMMON_API char* ll_pretty_print_sd_ptr(const LLSD* sd);
|
||||
LL_COMMON_API char* ll_pretty_print_sd(const LLSD& sd);
|
||||
|
||||
//compares the structure of an LLSD to a template LLSD and stores the
|
||||
@@ -73,6 +74,66 @@ LL_COMMON_API BOOL compare_llsd_with_template(
|
||||
const LLSD& template_llsd,
|
||||
LLSD& resultant_llsd);
|
||||
|
||||
/**
|
||||
* Recursively determine whether a given LLSD data block "matches" another
|
||||
* LLSD prototype. The returned string is empty() on success, non-empty() on
|
||||
* mismatch.
|
||||
*
|
||||
* This function tests structure (types) rather than data values. It is
|
||||
* intended for when a consumer expects an LLSD block with a particular
|
||||
* structure, and must succinctly detect whether the arriving block is
|
||||
* well-formed. For instance, a test of the form:
|
||||
* @code
|
||||
* if (! (data.has("request") && data.has("target") && data.has("modifier") ...))
|
||||
* @endcode
|
||||
* could instead be expressed by initializing a prototype LLSD map with the
|
||||
* required keys and writing:
|
||||
* @code
|
||||
* if (! llsd_matches(prototype, data).empty())
|
||||
* @endcode
|
||||
*
|
||||
* A non-empty return value is an error-message fragment intended to indicate
|
||||
* to (English-speaking) developers where in the prototype structure the
|
||||
* mismatch occurred.
|
||||
*
|
||||
* * If a slot in the prototype isUndefined(), then anything is valid at that
|
||||
* place in the real object. (Passing prototype == LLSD() matches anything
|
||||
* at all.)
|
||||
* * An array in the prototype must match a data array at least that large.
|
||||
* (Additional entries in the data array are ignored.) Every isDefined()
|
||||
* entry in the prototype array must match the corresponding entry in the
|
||||
* data array.
|
||||
* * A map in the prototype must match a map in the data. Every key in the
|
||||
* prototype map must match a corresponding key in the data map. (Additional
|
||||
* keys in the data map are ignored.) Every isDefined() value in the
|
||||
* prototype map must match the corresponding key's value in the data map.
|
||||
* * Scalar values in the prototype are tested for @em type rather than value.
|
||||
* For instance, a String in the prototype matches any String at all. In
|
||||
* effect, storing an Integer at a particular place in the prototype asserts
|
||||
* that the caller intends to apply asInteger() to the corresponding slot in
|
||||
* the data.
|
||||
* * A String in the prototype matches String, Boolean, Integer, Real, UUID,
|
||||
* Date and URI, because asString() applied to any of these produces a
|
||||
* meaningful result.
|
||||
* * Similarly, a Boolean, Integer or Real in the prototype can match any of
|
||||
* Boolean, Integer or Real in the data -- or even String.
|
||||
* * UUID matches UUID or String.
|
||||
* * Date matches Date or String.
|
||||
* * URI matches URI or String.
|
||||
* * Binary in the prototype matches only Binary in the data.
|
||||
*
|
||||
* @TODO: when a Boolean, Integer or Real in the prototype matches a String in
|
||||
* the data, we should examine the String @em value to ensure it can be
|
||||
* meaningfully converted to the requested type. The same goes for UUID, Date
|
||||
* and URI.
|
||||
*/
|
||||
LL_COMMON_API std::string llsd_matches(const LLSD& prototype, const LLSD& data, const std::string& pfx="");
|
||||
|
||||
/// Deep equality. If you want to compare LLSD::Real values for approximate
|
||||
/// equality rather than bitwise equality, pass @a bits as for
|
||||
/// is_approx_equal_fraction().
|
||||
LL_COMMON_API bool llsd_equals(const LLSD& lhs, const LLSD& rhs, unsigned bits=-1);
|
||||
|
||||
// Simple function to copy data out of input & output iterators if
|
||||
// there is no need for casting.
|
||||
template<typename Input> LLSD llsd_copy_array(Input iter, Input end)
|
||||
@@ -85,4 +146,283 @@ template<typename Input> LLSD llsd_copy_array(Input iter, Input end)
|
||||
return dest;
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* LLSDArray
|
||||
*****************************************************************************/
|
||||
/**
|
||||
* Construct an LLSD::Array inline, with implicit conversion to LLSD. Usage:
|
||||
*
|
||||
* @code
|
||||
* void somefunc(const LLSD&);
|
||||
* ...
|
||||
* somefunc(LLSDArray("text")(17)(3.14));
|
||||
* @endcode
|
||||
*
|
||||
* For completeness, LLSDArray() with no args constructs an empty array, so
|
||||
* <tt>LLSDArray()("text")(17)(3.14)</tt> produces an array equivalent to the
|
||||
* above. But for most purposes, LLSD() is already equivalent to an empty
|
||||
* array, and if you explicitly want an empty isArray(), there's
|
||||
* LLSD::emptyArray(). However, supporting a no-args LLSDArray() constructor
|
||||
* follows the principle of least astonishment.
|
||||
*/
|
||||
class LLSDArray
|
||||
{
|
||||
public:
|
||||
LLSDArray():
|
||||
_data(LLSD::emptyArray())
|
||||
{}
|
||||
|
||||
/**
|
||||
* Need an explicit copy constructor. Consider the following:
|
||||
*
|
||||
* @code
|
||||
* LLSD array_of_arrays(LLSDArray(LLSDArray(17)(34))
|
||||
* (LLSDArray("x")("y")));
|
||||
* @endcode
|
||||
*
|
||||
* The coder intends to construct [[17, 34], ["x", "y"]].
|
||||
*
|
||||
* With the compiler's implicit copy constructor, s/he gets instead
|
||||
* [17, 34, ["x", "y"]].
|
||||
*
|
||||
* The expression LLSDArray(17)(34) constructs an LLSDArray with those two
|
||||
* values. The reader assumes it should be converted to LLSD, as we always
|
||||
* want with LLSDArray, before passing it to the @em outer LLSDArray
|
||||
* constructor! This copy constructor makes that happen.
|
||||
*/
|
||||
LLSDArray(const LLSDArray& inner):
|
||||
_data(LLSD::emptyArray())
|
||||
{
|
||||
_data.append(inner);
|
||||
}
|
||||
|
||||
LLSDArray(const LLSD& value):
|
||||
_data(LLSD::emptyArray())
|
||||
{
|
||||
_data.append(value);
|
||||
}
|
||||
|
||||
LLSDArray& operator()(const LLSD& value)
|
||||
{
|
||||
_data.append(value);
|
||||
return *this;
|
||||
}
|
||||
|
||||
operator LLSD() const { return _data; }
|
||||
LLSD get() const { return _data; }
|
||||
|
||||
private:
|
||||
LLSD _data;
|
||||
};
|
||||
|
||||
/*****************************************************************************
|
||||
* LLSDMap
|
||||
*****************************************************************************/
|
||||
/**
|
||||
* Construct an LLSD::Map inline, with implicit conversion to LLSD. Usage:
|
||||
*
|
||||
* @code
|
||||
* void somefunc(const LLSD&);
|
||||
* ...
|
||||
* somefunc(LLSDMap("alpha", "abc")("number", 17)("pi", 3.14));
|
||||
* @endcode
|
||||
*
|
||||
* For completeness, LLSDMap() with no args constructs an empty map, so
|
||||
* <tt>LLSDMap()("alpha", "abc")("number", 17)("pi", 3.14)</tt> produces a map
|
||||
* equivalent to the above. But for most purposes, LLSD() is already
|
||||
* equivalent to an empty map, and if you explicitly want an empty isMap(),
|
||||
* there's LLSD::emptyMap(). However, supporting a no-args LLSDMap()
|
||||
* constructor follows the principle of least astonishment.
|
||||
*/
|
||||
class LLSDMap
|
||||
{
|
||||
public:
|
||||
LLSDMap():
|
||||
_data(LLSD::emptyMap())
|
||||
{}
|
||||
LLSDMap(const LLSD::String& key, const LLSD& value):
|
||||
_data(LLSD::emptyMap())
|
||||
{
|
||||
_data[key] = value;
|
||||
}
|
||||
|
||||
LLSDMap& operator()(const LLSD::String& key, const LLSD& value)
|
||||
{
|
||||
_data[key] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
operator LLSD() const { return _data; }
|
||||
LLSD get() const { return _data; }
|
||||
|
||||
private:
|
||||
LLSD _data;
|
||||
};
|
||||
|
||||
/*****************************************************************************
|
||||
* LLSDParam
|
||||
*****************************************************************************/
|
||||
/**
|
||||
* LLSDParam is a customization point for passing LLSD values to function
|
||||
* parameters of more or less arbitrary type. LLSD provides a small set of
|
||||
* native conversions; but if a generic algorithm explicitly constructs an
|
||||
* LLSDParam object in the function's argument list, a consumer can provide
|
||||
* LLSDParam specializations to support more different parameter types than
|
||||
* LLSD's native conversions.
|
||||
*
|
||||
* Usage:
|
||||
*
|
||||
* @code
|
||||
* void somefunc(const paramtype&);
|
||||
* ...
|
||||
* somefunc(..., LLSDParam<paramtype>(someLLSD), ...);
|
||||
* @endcode
|
||||
*/
|
||||
template <typename T>
|
||||
class LLSDParam
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Default implementation converts to T on construction, saves converted
|
||||
* value for later retrieval
|
||||
*/
|
||||
LLSDParam(const LLSD& value):
|
||||
_value(value)
|
||||
{}
|
||||
|
||||
operator T() const { return _value; }
|
||||
|
||||
private:
|
||||
T _value;
|
||||
};
|
||||
|
||||
/**
|
||||
* Turns out that several target types could accept an LLSD param using any of
|
||||
* a few different conversions, e.g. LLUUID's constructor can accept LLUUID or
|
||||
* std::string. Therefore, the compiler can't decide which LLSD conversion
|
||||
* operator to choose, even though to us it seems obvious. But that's okay, we
|
||||
* can specialize LLSDParam for such target types, explicitly specifying the
|
||||
* desired conversion -- that's part of what LLSDParam is all about. Turns out
|
||||
* we have to do that enough to make it worthwhile generalizing. Use a macro
|
||||
* because I need to specify one of the asReal, etc., explicit conversion
|
||||
* methods as well as a type. If I'm overlooking a clever way to implement
|
||||
* that using a template instead, feel free to reimplement.
|
||||
*/
|
||||
#define LLSDParam_for(T, AS) \
|
||||
template <> \
|
||||
class LLSDParam<T> \
|
||||
{ \
|
||||
public: \
|
||||
LLSDParam(const LLSD& value): \
|
||||
_value(value.AS()) \
|
||||
{} \
|
||||
\
|
||||
operator T() const { return _value; } \
|
||||
\
|
||||
private: \
|
||||
T _value; \
|
||||
}
|
||||
|
||||
LLSDParam_for(float, asReal);
|
||||
LLSDParam_for(LLUUID, asUUID);
|
||||
LLSDParam_for(LLDate, asDate);
|
||||
LLSDParam_for(LLURI, asURI);
|
||||
LLSDParam_for(LLSD::Binary, asBinary);
|
||||
|
||||
/**
|
||||
* LLSDParam<const char*> is an example of the kind of conversion you can
|
||||
* support with LLSDParam beyond native LLSD conversions. Normally you can't
|
||||
* pass an LLSD object to a function accepting const char* -- but you can
|
||||
* safely pass an LLSDParam<const char*>(yourLLSD).
|
||||
*/
|
||||
template <>
|
||||
class LLSDParam<const char*>
|
||||
{
|
||||
private:
|
||||
// The difference here is that we store a std::string rather than a const
|
||||
// char*. It's important that the LLSDParam object own the std::string.
|
||||
std::string _value;
|
||||
// We don't bother storing the incoming LLSD object, but we do have to
|
||||
// distinguish whether _value is an empty string because the LLSD object
|
||||
// contains an empty string or because it's isUndefined().
|
||||
bool _undefined;
|
||||
|
||||
public:
|
||||
LLSDParam(const LLSD& value):
|
||||
_value(value),
|
||||
_undefined(value.isUndefined())
|
||||
{}
|
||||
|
||||
// The const char* we retrieve is for storage owned by our _value member.
|
||||
// That's how we guarantee that the const char* is valid for the lifetime
|
||||
// of this LLSDParam object. Constructing your LLSDParam in the argument
|
||||
// list should ensure that the LLSDParam object will persist for the
|
||||
// duration of the function call.
|
||||
operator const char*() const
|
||||
{
|
||||
if (_undefined)
|
||||
{
|
||||
// By default, an isUndefined() LLSD object's asString() method
|
||||
// will produce an empty string. But for a function accepting
|
||||
// const char*, it's often important to be able to pass NULL, and
|
||||
// isUndefined() seems like the best way. If you want to pass an
|
||||
// empty string, you can still pass LLSD(""). Without this special
|
||||
// case, though, no LLSD value could pass NULL.
|
||||
return NULL;
|
||||
}
|
||||
return _value.c_str();
|
||||
}
|
||||
};
|
||||
|
||||
namespace llsd
|
||||
{
|
||||
|
||||
/*****************************************************************************
|
||||
* BOOST_FOREACH() helpers for LLSD
|
||||
*****************************************************************************/
|
||||
/// Usage: BOOST_FOREACH(LLSD item, inArray(someLLSDarray)) { ... }
|
||||
class inArray
|
||||
{
|
||||
public:
|
||||
inArray(const LLSD& array):
|
||||
_array(array)
|
||||
{}
|
||||
|
||||
typedef LLSD::array_const_iterator const_iterator;
|
||||
typedef LLSD::array_iterator iterator;
|
||||
|
||||
iterator begin() { return _array.beginArray(); }
|
||||
iterator end() { return _array.endArray(); }
|
||||
const_iterator begin() const { return _array.beginArray(); }
|
||||
const_iterator end() const { return _array.endArray(); }
|
||||
|
||||
private:
|
||||
LLSD _array;
|
||||
};
|
||||
|
||||
/// MapEntry is what you get from dereferencing an LLSD::map_[const_]iterator.
|
||||
typedef std::map<LLSD::String, LLSD>::value_type MapEntry;
|
||||
|
||||
/// Usage: BOOST_FOREACH([const] MapEntry& e, inMap(someLLSDmap)) { ... }
|
||||
class inMap
|
||||
{
|
||||
public:
|
||||
inMap(const LLSD& map):
|
||||
_map(map)
|
||||
{}
|
||||
|
||||
typedef LLSD::map_const_iterator const_iterator;
|
||||
typedef LLSD::map_iterator iterator;
|
||||
|
||||
iterator begin() { return _map.beginMap(); }
|
||||
iterator end() { return _map.endMap(); }
|
||||
const_iterator begin() const { return _map.beginMap(); }
|
||||
const_iterator end() const { return _map.endMap(); }
|
||||
|
||||
private:
|
||||
LLSD _map;
|
||||
};
|
||||
|
||||
} // namespace llsd
|
||||
|
||||
#endif // LL_LLSDUTIL_H
|
||||
|
||||
32
indra/llcommon/llsingleton.cpp
Normal file
32
indra/llcommon/llsingleton.cpp
Normal file
@@ -0,0 +1,32 @@
|
||||
/**
|
||||
* @file llsingleton.cpp
|
||||
* @author Brad Kittenbrink
|
||||
*
|
||||
* $LicenseInfo:firstyear=2009&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2010, Linden Research, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#include "linden_common.h"
|
||||
|
||||
#include "llsingleton.h"
|
||||
|
||||
std::map<std::string, void *> * LLSingletonRegistry::sSingletonMap = NULL;
|
||||
|
||||
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
|
||||
BOOL LLPerfBlock::sStatsEnabled = FALSE; // Flag for detailed information
|
||||
S32 LLPerfBlock::sStatsFlags = LLPerfBlock::LLSTATS_NO_OPTIONAL_STATS; // Control what is being recorded
|
||||
LLPerfBlock::stat_map_t LLPerfBlock::sStatMap; // Map full path string to LLStatTime objects, tracks all active objects
|
||||
std::string LLPerfBlock::sCurrentStatPath = ""; // Something like "/total_time/physics/physics step"
|
||||
LLStat::stat_map_t LLStat::sStatList;
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// Live config file to trigger stats logging
|
||||
@@ -129,6 +130,7 @@ bool LLStatsConfigFile::loadFile()
|
||||
|
||||
F32 duration = 0.f;
|
||||
F32 interval = 0.f;
|
||||
S32 flags = LLPerfBlock::LLSTATS_BASIC_STATS;
|
||||
|
||||
const char * w = "duration";
|
||||
if (stats_config.has(w))
|
||||
@@ -140,8 +142,18 @@ bool LLStatsConfigFile::loadFile()
|
||||
{
|
||||
interval = (F32)stats_config[w].asReal();
|
||||
}
|
||||
w = "flags";
|
||||
if (stats_config.has(w))
|
||||
{
|
||||
flags = (S32)stats_config[w].asInteger();
|
||||
if (flags == LLPerfBlock::LLSTATS_NO_OPTIONAL_STATS &&
|
||||
duration > 0)
|
||||
{ // No flags passed in, but have a duration, so reset to basic stats
|
||||
flags = LLPerfBlock::LLSTATS_BASIC_STATS;
|
||||
}
|
||||
}
|
||||
|
||||
mStatsp->setReportPerformanceDuration( duration );
|
||||
mStatsp->setReportPerformanceDuration( duration, flags );
|
||||
mStatsp->setReportPerformanceInterval( interval );
|
||||
|
||||
if ( duration > 0 )
|
||||
@@ -253,13 +265,14 @@ void LLPerfStats::dumpIntervalPerformanceStats()
|
||||
}
|
||||
}
|
||||
|
||||
// Set length of performance stat recording
|
||||
void LLPerfStats::setReportPerformanceDuration( F32 seconds )
|
||||
// Set length of performance stat recording.
|
||||
// If turning stats on, caller must provide flags
|
||||
void LLPerfStats::setReportPerformanceDuration( F32 seconds, S32 flags /* = LLSTATS_NO_OPTIONAL_STATS */ )
|
||||
{
|
||||
if ( seconds <= 0.f )
|
||||
{
|
||||
mReportPerformanceStatEnd = 0.0;
|
||||
LLPerfBlock::setStatsEnabled( FALSE );
|
||||
LLPerfBlock::setStatsFlags(LLPerfBlock::LLSTATS_NO_OPTIONAL_STATS); // Make sure all recording is off
|
||||
mFrameStatsFile.close();
|
||||
LLPerfBlock::clearDynamicStats();
|
||||
}
|
||||
@@ -268,8 +281,8 @@ void LLPerfStats::setReportPerformanceDuration( F32 seconds )
|
||||
mReportPerformanceStatEnd = LLFrameTimer::getElapsedSeconds() + ((F64) seconds);
|
||||
// Clear failure flag to try and create the log file once
|
||||
mFrameStatsFileFailure = FALSE;
|
||||
LLPerfBlock::setStatsEnabled( TRUE );
|
||||
mSkipFirstFrameStats = TRUE; // Skip the first report (at the end of this frame)
|
||||
LLPerfBlock::setStatsFlags(flags);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -611,11 +624,26 @@ LLPerfBlock::LLPerfBlock(LLStatTime* stat ) : mPredefinedStat(stat), mDynamicSta
|
||||
}
|
||||
}
|
||||
|
||||
// Use this constructor for dynamically created LLStatTime objects (not pre-defined) with a multi-part key.
|
||||
// These are also turned on or off via the switch passed in
|
||||
LLPerfBlock::LLPerfBlock( const char* key1, const char* key2 ) : mPredefinedStat(NULL), mDynamicStat(NULL)
|
||||
// Use this constructor for normal, optional LLPerfBlock time slices
|
||||
LLPerfBlock::LLPerfBlock( const char* key ) : mPredefinedStat(NULL), mDynamicStat(NULL)
|
||||
{
|
||||
if (!sStatsEnabled) return;
|
||||
if ((sStatsFlags & LLSTATS_BASIC_STATS) == 0)
|
||||
{ // These are off unless the base set is enabled
|
||||
return;
|
||||
}
|
||||
|
||||
initDynamicStat(key);
|
||||
}
|
||||
|
||||
|
||||
// Use this constructor for dynamically created LLPerfBlock time slices
|
||||
// that are only enabled by specific control flags
|
||||
LLPerfBlock::LLPerfBlock( const char* key1, const char* key2, S32 flags ) : mPredefinedStat(NULL), mDynamicStat(NULL)
|
||||
{
|
||||
if ((sStatsFlags & flags) == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (NULL == key2 || strlen(key2) == 0)
|
||||
{
|
||||
@@ -629,10 +657,12 @@ LLPerfBlock::LLPerfBlock( const char* key1, const char* key2 ) : mPredefinedStat
|
||||
}
|
||||
}
|
||||
|
||||
// Set up the result data map if dynamic stats are enabled
|
||||
void LLPerfBlock::initDynamicStat(const std::string& key)
|
||||
{
|
||||
// Early exit if dynamic stats aren't enabled.
|
||||
if (!sStatsEnabled) return;
|
||||
if (sStatsFlags == LLSTATS_NO_OPTIONAL_STATS)
|
||||
return;
|
||||
|
||||
mLastPath = sCurrentStatPath; // Save and restore current path
|
||||
sCurrentStatPath += "/" + key; // Add key to current path
|
||||
@@ -713,7 +743,7 @@ void LLPerfBlock::addStatsToLLSDandReset( LLSD & stats,
|
||||
}
|
||||
}
|
||||
else
|
||||
{ // WTF? Shouldn't have a NULL pointer in the map.
|
||||
{ // Shouldn't have a NULL pointer in the map.
|
||||
llwarns << "Unexpected NULL dynamic stat at '" << stats_full_path << "'" << llendl;
|
||||
}
|
||||
}
|
||||
@@ -725,14 +755,12 @@ void LLPerfBlock::addStatsToLLSDandReset( LLSD & stats,
|
||||
LLTimer LLStat::sTimer;
|
||||
LLFrameTimer LLStat::sFrameTimer;
|
||||
|
||||
LLStat::LLStat(const U32 num_bins, const BOOL use_frame_timer)
|
||||
void LLStat::init()
|
||||
{
|
||||
llassert(num_bins > 0);
|
||||
mUseFrameTimer = use_frame_timer;
|
||||
llassert(mNumBins > 0);
|
||||
mNumValues = 0;
|
||||
mLastValue = 0.f;
|
||||
mLastTime = 0.f;
|
||||
mNumBins = num_bins;
|
||||
mCurBin = (mNumBins-1);
|
||||
mNextBin = 0;
|
||||
mBins = new F32[mNumBins];
|
||||
@@ -746,6 +774,29 @@ LLStat::LLStat(const U32 num_bins, const BOOL use_frame_timer)
|
||||
mTime[i] = 0.0;
|
||||
mDT[i] = 0.f;
|
||||
}
|
||||
|
||||
if (!mName.empty())
|
||||
{
|
||||
stat_map_t::iterator iter = sStatList.find(mName);
|
||||
if (iter != sStatList.end())
|
||||
llwarns << "LLStat with duplicate name: " << mName << llendl;
|
||||
sStatList.insert(std::make_pair(mName, this));
|
||||
}
|
||||
}
|
||||
|
||||
LLStat::LLStat(const U32 num_bins, const BOOL use_frame_timer)
|
||||
: mUseFrameTimer(use_frame_timer),
|
||||
mNumBins(num_bins)
|
||||
{
|
||||
init();
|
||||
}
|
||||
|
||||
LLStat::LLStat(std::string name, U32 num_bins, BOOL use_frame_timer)
|
||||
: mUseFrameTimer(use_frame_timer),
|
||||
mNumBins(num_bins),
|
||||
mName(name)
|
||||
{
|
||||
init();
|
||||
}
|
||||
|
||||
LLStat::~LLStat()
|
||||
@@ -754,6 +805,15 @@ LLStat::~LLStat()
|
||||
delete[] mBeginTime;
|
||||
delete[] mTime;
|
||||
delete[] mDT;
|
||||
|
||||
if (!mName.empty())
|
||||
{
|
||||
// handle multiple entries with the same name
|
||||
stat_map_t::iterator iter = sStatList.find(mName);
|
||||
while (iter != sStatList.end() && iter->second != this)
|
||||
++iter;
|
||||
sStatList.erase(iter);
|
||||
}
|
||||
}
|
||||
|
||||
void LLStat::reset()
|
||||
|
||||
@@ -192,14 +192,23 @@ public:
|
||||
// Use this constructor for pre-defined LLStatTime objects
|
||||
LLPerfBlock(LLStatTime* stat);
|
||||
|
||||
// Use this constructor for dynamically created LLStatTime objects (not pre-defined) with a multi-part key
|
||||
LLPerfBlock( const char* key1, const char* key2 = NULL);
|
||||
// Use this constructor for normal, optional LLPerfBlock time slices
|
||||
LLPerfBlock( const char* key );
|
||||
|
||||
// Use this constructor for dynamically created LLPerfBlock time slices
|
||||
// that are only enabled by specific control flags
|
||||
LLPerfBlock( const char* key1, const char* key2, S32 flags = LLSTATS_BASIC_STATS );
|
||||
|
||||
~LLPerfBlock();
|
||||
|
||||
static void setStatsEnabled( BOOL enable ) { sStatsEnabled = enable; };
|
||||
static S32 getStatsEnabled() { return sStatsEnabled; };
|
||||
enum
|
||||
{ // Stats bitfield flags
|
||||
LLSTATS_NO_OPTIONAL_STATS = 0x00, // No optional stats gathering, just pre-defined LLStatTime objects
|
||||
LLSTATS_BASIC_STATS = 0x01, // Gather basic optional runtime stats
|
||||
LLSTATS_SCRIPT_FUNCTIONS = 0x02, // Include LSL function calls
|
||||
};
|
||||
static void setStatsFlags( S32 flags ) { sStatsFlags = flags; };
|
||||
static S32 getStatsFlags() { return sStatsFlags; };
|
||||
|
||||
static void clearDynamicStats(); // Reset maps to clear out dynamic objects
|
||||
static void addStatsToLLSDandReset( LLSD & stats, // Get current information and clear time bin
|
||||
@@ -213,7 +222,7 @@ private:
|
||||
LLStatTime * mPredefinedStat; // LLStatTime object to get data
|
||||
StatEntry * mDynamicStat; // StatEntryobject to get data
|
||||
|
||||
static BOOL sStatsEnabled; // Normally FALSE
|
||||
static S32 sStatsFlags; // Control what is being recorded
|
||||
static stat_map_t sStatMap; // Map full path string to LLStatTime objects
|
||||
static std::string sCurrentStatPath; // Something like "frame/physics/physics step"
|
||||
};
|
||||
@@ -236,7 +245,7 @@ public:
|
||||
BOOL frameStatsIsRunning() { return (mReportPerformanceStatEnd > 0.); };
|
||||
F32 getReportPerformanceInterval() const { return mReportPerformanceStatInterval; };
|
||||
void setReportPerformanceInterval( F32 interval ) { mReportPerformanceStatInterval = interval; };
|
||||
void setReportPerformanceDuration( F32 seconds );
|
||||
void setReportPerformanceDuration( F32 seconds, S32 flags = LLPerfBlock::LLSTATS_NO_OPTIONAL_STATS );
|
||||
void setProcessName(const std::string& process_name) { mProcessName = process_name; }
|
||||
void setProcessPID(S32 process_pid) { mProcessPID = process_pid; }
|
||||
|
||||
@@ -258,8 +267,15 @@ private:
|
||||
// ----------------------------------------------------------------------------
|
||||
class LL_COMMON_API LLStat
|
||||
{
|
||||
private:
|
||||
typedef std::multimap<std::string, LLStat*> stat_map_t;
|
||||
static stat_map_t sStatList;
|
||||
|
||||
void init();
|
||||
|
||||
public:
|
||||
LLStat(const U32 num_bins = 32, BOOL use_frame_timer = FALSE);
|
||||
LLStat(U32 num_bins = 32, BOOL use_frame_timer = FALSE);
|
||||
LLStat(std::string name, U32 num_bins = 32, BOOL use_frame_timer = FALSE);
|
||||
~LLStat();
|
||||
|
||||
void reset();
|
||||
@@ -322,8 +338,22 @@ private:
|
||||
F32 *mDT;
|
||||
S32 mCurBin;
|
||||
S32 mNextBin;
|
||||
|
||||
std::string mName;
|
||||
|
||||
static LLTimer sTimer;
|
||||
static LLFrameTimer sFrameTimer;
|
||||
|
||||
public:
|
||||
static LLStat* getStat(const std::string& name)
|
||||
{
|
||||
// return the first stat that matches 'name'
|
||||
stat_map_t::iterator iter = sStatList.find(name);
|
||||
if (iter != sStatList.end())
|
||||
return iter->second;
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
#endif // LL_STAT_
|
||||
|
||||
@@ -45,7 +45,7 @@
|
||||
// skips spaces and tabs
|
||||
bool skip_whitespace(std::istream& input_stream)
|
||||
{
|
||||
char c = input_stream.peek();
|
||||
int c = input_stream.peek();
|
||||
while (('\t' == c || ' ' == c) && input_stream.good())
|
||||
{
|
||||
input_stream.get();
|
||||
@@ -57,7 +57,7 @@ bool skip_whitespace(std::istream& input_stream)
|
||||
// skips whitespace, newlines, and carriage returns
|
||||
bool skip_emptyspace(std::istream& input_stream)
|
||||
{
|
||||
char c = input_stream.peek();
|
||||
int c = input_stream.peek();
|
||||
while ( input_stream.good()
|
||||
&& ('\t' == c || ' ' == c || '\n' == c || '\r' == c) )
|
||||
{
|
||||
@@ -72,7 +72,7 @@ bool skip_comments_and_emptyspace(std::istream& input_stream)
|
||||
{
|
||||
while (skip_emptyspace(input_stream))
|
||||
{
|
||||
char c = input_stream.peek();
|
||||
int c = input_stream.peek();
|
||||
if ('#' == c )
|
||||
{
|
||||
while ('\n' != c && input_stream.good())
|
||||
@@ -90,7 +90,7 @@ bool skip_comments_and_emptyspace(std::istream& input_stream)
|
||||
|
||||
bool skip_line(std::istream& input_stream)
|
||||
{
|
||||
char c;
|
||||
int c;
|
||||
do
|
||||
{
|
||||
c = input_stream.get();
|
||||
@@ -100,7 +100,7 @@ bool skip_line(std::istream& input_stream)
|
||||
|
||||
bool skip_to_next_word(std::istream& input_stream)
|
||||
{
|
||||
char c = input_stream.peek();
|
||||
int c = input_stream.peek();
|
||||
while ( input_stream.good()
|
||||
&& ( (c >= 'a' && c <= 'z')
|
||||
|| (c >= 'A' && c <= 'Z')
|
||||
@@ -132,7 +132,7 @@ bool skip_to_end_of_next_keyword(const char* keyword, std::istream& input_stream
|
||||
while (input_stream.good())
|
||||
{
|
||||
skip_emptyspace(input_stream);
|
||||
char c = input_stream.get();
|
||||
int c = input_stream.get();
|
||||
if (keyword[0] != c)
|
||||
{
|
||||
skip_line(input_stream);
|
||||
@@ -181,7 +181,7 @@ bool skip_to_start_of_next_keyword(const char* keyword, std::istream& input_stre
|
||||
while (input_stream.good())
|
||||
{
|
||||
skip_emptyspace(input_stream);
|
||||
char c = input_stream.get();
|
||||
int c = input_stream.get();
|
||||
if (keyword[0] != c)
|
||||
{
|
||||
skip_line(input_stream);
|
||||
@@ -229,7 +229,7 @@ bool skip_to_start_of_next_keyword(const char* keyword, std::istream& input_stre
|
||||
bool get_word(std::string& output_string, std::istream& input_stream)
|
||||
{
|
||||
skip_emptyspace(input_stream);
|
||||
char c = input_stream.peek();
|
||||
int c = input_stream.peek();
|
||||
while ( !isspace(c)
|
||||
&& '\n' != c
|
||||
&& '\r' != c
|
||||
@@ -246,7 +246,7 @@ bool get_word(std::string& output_string, std::istream& input_stream, int n)
|
||||
{
|
||||
skip_emptyspace(input_stream);
|
||||
int char_count = 0;
|
||||
char c = input_stream.peek();
|
||||
int c = input_stream.peek();
|
||||
while (!isspace(c)
|
||||
&& '\n' != c
|
||||
&& '\r' != c
|
||||
@@ -265,7 +265,7 @@ bool get_word(std::string& output_string, std::istream& input_stream, int n)
|
||||
bool get_line(std::string& output_string, std::istream& input_stream)
|
||||
{
|
||||
output_string.clear();
|
||||
char c = input_stream.get();
|
||||
int c = input_stream.get();
|
||||
while (input_stream.good())
|
||||
{
|
||||
output_string += c;
|
||||
@@ -285,7 +285,7 @@ bool get_line(std::string& output_string, std::istream& input_stream, int n)
|
||||
{
|
||||
output_string.clear();
|
||||
int char_count = 0;
|
||||
char c = input_stream.get();
|
||||
int c = input_stream.get();
|
||||
while (input_stream.good() && char_count < n)
|
||||
{
|
||||
char_count++;
|
||||
|
||||
@@ -42,14 +42,17 @@ template <class Object> class LLStrider
|
||||
U8* mBytep;
|
||||
};
|
||||
U32 mSkip;
|
||||
U32 mTypeSize;
|
||||
public:
|
||||
|
||||
LLStrider() { mObjectp = NULL; mSkip = sizeof(Object); }
|
||||
LLStrider() { mObjectp = NULL; mTypeSize = mSkip = sizeof(Object); }
|
||||
~LLStrider() { }
|
||||
|
||||
const LLStrider<Object>& operator = (Object *first) { mObjectp = first; return *this;}
|
||||
void setStride (S32 skipBytes) { mSkip = (skipBytes ? skipBytes : sizeof(Object));}
|
||||
void setTypeSize (S32 typeBytes){ mTypeSize = (typeBytes ? typeBytes : sizeof(Object)); }
|
||||
|
||||
bool isStrided() const { return mTypeSize != mSkip; }
|
||||
void skip(const U32 index) { mBytep += mSkip*index;}
|
||||
U32 getSkip() const { return mSkip; }
|
||||
Object* get() { return mObjectp; }
|
||||
@@ -58,6 +61,71 @@ public:
|
||||
Object* operator ++(int) { Object* old = mObjectp; mBytep += mSkip; return old; }
|
||||
Object* operator +=(int i) { mBytep += mSkip*i; return mObjectp; }
|
||||
Object& operator[](U32 index) { return *(Object*)(mBytep + (mSkip * index)); }
|
||||
void assignArray(U8* __restrict source, const size_t elem_size, const size_t elem_count)
|
||||
{
|
||||
llassert_always(sizeof(Object) <= elem_size);
|
||||
|
||||
U8* __restrict dest = mBytep; //refer to dest instead of mBytep to benefit from __restrict hint
|
||||
const U32 bytes = elem_size * elem_count; //total bytes to copy from source to dest
|
||||
|
||||
//stride == sizeof(element) implies entire buffer is unstrided and thus memcpy-able, provided source buffer elements match in size.
|
||||
//Because LLStrider is often passed an LLVector3 even if the reprensentation is LLVector4 in the vertex buffer, mTypeSize is set to
|
||||
//the TRUE vbo datatype size via VertexBufferStrider::get
|
||||
if(!isStrided() && mTypeSize == elem_size)
|
||||
{
|
||||
if(bytes >= sizeof(LLVector4) * 4) //Should be able to pull at least 3 16byte blocks from this. Smaller isn't really beneficial.
|
||||
{
|
||||
U8* __restrict aligned_source = LL_NEXT_ALIGNED_ADDRESS(source);
|
||||
U8* __restrict aligned_dest = LL_NEXT_ALIGNED_ADDRESS(dest);
|
||||
const U32 source_offset = aligned_source - source; //Offset to first aligned location in source buffer.
|
||||
const U32 dest_offset = aligned_dest - dest; //Offset to first aligned location in dest buffer.
|
||||
llassert_always(source_offset < 16);
|
||||
llassert_always(dest_offset < 16);
|
||||
if(source_offset == dest_offset) //delta to aligned location matches between source and destination! _mm_*_ps should be viable.
|
||||
{
|
||||
const U32 end_offset = (bytes - source_offset) % sizeof(LLVector4); //buffers may not neatly end on a 16byte alignment boundary.
|
||||
const U32 aligned_bytes = bytes - source_offset - end_offset; //how many bytes to copy from aligned start to aligned end.
|
||||
|
||||
llassert_always(aligned_bytes > 0);
|
||||
|
||||
if(source_offset) //memcpy up to the aligned location if needed
|
||||
memcpy(dest,source,source_offset);
|
||||
LLVector4a::memcpyNonAliased16((F32*) aligned_dest, (F32*) aligned_source, aligned_bytes);
|
||||
if(end_offset) //memcpy to the very end if needed.
|
||||
memcpy(aligned_dest+aligned_bytes,aligned_source+aligned_bytes,end_offset);
|
||||
}
|
||||
else //buffers non-uniformly offset from aligned location. Using _mm_*u_ps.
|
||||
{
|
||||
U32 end = bytes/sizeof(LLVector4); //sizeof(LLVector4) = 16 bytes = 128 bits
|
||||
|
||||
llassert_always(end > 0);
|
||||
|
||||
__m128* dst = (__m128*) dest;
|
||||
__m128* src = (__m128*) source;
|
||||
|
||||
for (U32 i = 0; i < end; i++) //copy 128bit chunks
|
||||
{
|
||||
__m128 res = _mm_loadu_ps((F32*)&src[i]);
|
||||
_mm_storeu_ps((F32*)&dst[i], res);
|
||||
}
|
||||
end*=16;//Convert to real byte offset
|
||||
if(end < bytes) //just memcopy the rest
|
||||
memcpy(dest+end,source+end,bytes-end);
|
||||
}
|
||||
}
|
||||
else //Too small. just do a simple memcpy.
|
||||
memcpy(dest,source,bytes);
|
||||
}
|
||||
else
|
||||
{
|
||||
for(U32 i=0;i<elem_count;i++)
|
||||
{
|
||||
memcpy(dest,source,sizeof(Object));
|
||||
dest+=mSkip;
|
||||
source+=elem_size;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#endif // LL_LLSTRIDER_H
|
||||
|
||||
@@ -52,7 +52,7 @@
|
||||
# include <sys/sysctl.h>
|
||||
# include <sys/utsname.h>
|
||||
# include <stdint.h>
|
||||
//# include <Carbon/Carbon.h> May be needed?
|
||||
# include <Carbon/Carbon.h>
|
||||
#elif LL_LINUX
|
||||
# include <errno.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
|
||||
//
|
||||
@@ -73,8 +88,10 @@ void *APR_THREAD_FUNC LLThread::staticRun(apr_thread_t *apr_threadp, void *datap
|
||||
|
||||
LLThread *threadp = (LLThread *)datap;
|
||||
|
||||
// Set thread state to running
|
||||
threadp->mStatus = RUNNING;
|
||||
#if !LL_DARWIN
|
||||
sThreadID = threadp->mID;
|
||||
#endif
|
||||
|
||||
|
||||
// Create a thread local data.
|
||||
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
|
||||
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.
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -98,6 +125,7 @@ LLThread::LLThread(std::string const& name) :
|
||||
mStatus(STOPPED),
|
||||
mThreadLocalData(NULL)
|
||||
{
|
||||
mID = ++sIDIter;
|
||||
mRunCondition = new LLCondition;
|
||||
}
|
||||
|
||||
@@ -119,7 +147,7 @@ void LLThread::shutdown()
|
||||
// First, set the flag that indicates that we're ready to die
|
||||
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
|
||||
// It's unclear whether I should even bother doing this - this destructor
|
||||
// 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
|
||||
llwarns << "LLThread::shutdown() exiting thread before clean exit!" << llendl;
|
||||
// Put a stake in its heart.
|
||||
apr_thread_exit(mAPRThreadp, -1);
|
||||
return;
|
||||
}
|
||||
mAPRThreadp = NULL;
|
||||
}
|
||||
|
||||
delete mRunCondition;
|
||||
mRunCondition = 0;
|
||||
}
|
||||
|
||||
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_thread_detach(mAPRThreadp);
|
||||
apr_status_t status =
|
||||
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()
|
||||
{
|
||||
if (!tryLock())
|
||||
@@ -328,6 +423,11 @@ bool LLMutexBase::isLocked()
|
||||
return false;
|
||||
}
|
||||
|
||||
U32 LLMutexBase::lockingThread() const
|
||||
{
|
||||
return mLockingThread;
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
|
||||
LLCondition::LLCondition(AIAPRPool& parent) : LLMutex(parent)
|
||||
@@ -335,6 +435,7 @@ LLCondition::LLCondition(AIAPRPool& parent) : LLMutex(parent)
|
||||
apr_thread_cond_create(&mAPRCondp, mPool());
|
||||
}
|
||||
|
||||
|
||||
LLCondition::~LLCondition()
|
||||
{
|
||||
apr_thread_cond_destroy(mAPRCondp);
|
||||
|
||||
@@ -48,6 +48,12 @@ class LLThread;
|
||||
class LLMutex;
|
||||
class LLCondition;
|
||||
|
||||
#if LL_WINDOWS
|
||||
#define ll_thread_local __declspec(thread)
|
||||
#else
|
||||
#define ll_thread_local __thread
|
||||
#endif
|
||||
|
||||
class LL_COMMON_API AIThreadLocalData
|
||||
{
|
||||
private:
|
||||
@@ -66,6 +72,9 @@ public:
|
||||
|
||||
class LL_COMMON_API LLThread
|
||||
{
|
||||
private:
|
||||
static U32 sIDIter;
|
||||
|
||||
public:
|
||||
typedef enum e_thread_status
|
||||
{
|
||||
@@ -106,6 +115,8 @@ public:
|
||||
// Return thread-local data for the current thread.
|
||||
static AIThreadLocalData& tldata(void) { return AIThreadLocalData::tldata(); }
|
||||
|
||||
U32 getID() const { return mID; }
|
||||
|
||||
private:
|
||||
BOOL mPaused;
|
||||
|
||||
@@ -117,7 +128,8 @@ protected:
|
||||
LLCondition* mRunCondition;
|
||||
|
||||
apr_thread_t *mAPRThreadp;
|
||||
EThreadStatus mStatus;
|
||||
volatile EThreadStatus mStatus;
|
||||
U32 mID;
|
||||
|
||||
friend void AIThreadLocalData::create(LLThread* threadp);
|
||||
AIThreadLocalData* mThreadLocalData;
|
||||
@@ -151,16 +163,26 @@ protected:
|
||||
class LL_COMMON_API LLMutexBase
|
||||
{
|
||||
public:
|
||||
void lock() { apr_thread_mutex_lock(mAPRMutexp); }
|
||||
void unlock() { apr_thread_mutex_unlock(mAPRMutexp); }
|
||||
typedef enum
|
||||
{
|
||||
NO_THREAD = 0xFFFFFFFF
|
||||
} e_locking_thread;
|
||||
|
||||
LLMutexBase() : mLockingThread(NO_THREAD), mCount(0) {}
|
||||
|
||||
void lock(); //blocks
|
||||
void unlock();
|
||||
// Returns true if lock was obtained successfully.
|
||||
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
|
||||
U32 lockingThread() const; //get ID of locking thread
|
||||
|
||||
protected:
|
||||
// mAPRMutexp is initialized and uninitialized in the derived class.
|
||||
apr_thread_mutex_t* mAPRMutexp;
|
||||
mutable U32 mCount;
|
||||
mutable U32 mLockingThread;
|
||||
};
|
||||
|
||||
class LL_COMMON_API LLMutex : public LLMutexBase
|
||||
@@ -350,6 +372,7 @@ void LLThread::unlockData()
|
||||
mRunCondition->unlock();
|
||||
}
|
||||
|
||||
|
||||
//============================================================================
|
||||
|
||||
// see llmemory.h for LLPointer<> definition
|
||||
|
||||
@@ -36,6 +36,8 @@
|
||||
|
||||
#include "u64.h"
|
||||
|
||||
#include "lldate.h"
|
||||
|
||||
#if LL_WINDOWS
|
||||
# define WIN32_LEAN_AND_MEAN
|
||||
# include <winsock2.h>
|
||||
|
||||
@@ -39,8 +39,6 @@
|
||||
#include <limits.h>
|
||||
|
||||
#include "stdtypes.h"
|
||||
#include "llpreprocessor.h"
|
||||
#include "lldate.h"
|
||||
|
||||
#include <string>
|
||||
#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 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
|
||||
{
|
||||
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 timeStructToFormattedString(struct tm * time, std::string format, std::string ×tr);
|
||||
|
||||
U64 LL_COMMON_API totalTime(); // Returns current system time in microseconds
|
||||
#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_MINOR = 5;
|
||||
const S32 LL_VERSION_PATCH = 9;
|
||||
const S32 LL_VERSION_PATCH = 10;
|
||||
const S32 LL_VERSION_BUILD = 1;
|
||||
|
||||
const char * const LL_CHANNEL = "Singularity";
|
||||
|
||||
@@ -245,7 +245,7 @@ U8* LLImageBase::allocateDataSize(S32 width, S32 height, S32 ncomponents, S32 si
|
||||
// LLImageRaw
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
S32 LLImageRaw::sGlobalRawMemory = 0;
|
||||
AITHREADSAFESIMPLE(S32, LLImageRaw::sGlobalRawMemory, );
|
||||
S32 LLImageRaw::sRawImageCount = 0;
|
||||
S32 LLImageRaw::sRawImageCachedCount = 0;
|
||||
|
||||
@@ -295,23 +295,25 @@ LLImageRaw::~LLImageRaw()
|
||||
U8* LLImageRaw::allocateData(S32 size)
|
||||
{
|
||||
U8* res = LLImageBase::allocateData(size);
|
||||
sGlobalRawMemory += getDataSize();
|
||||
*AIAccess<S32>(sGlobalRawMemory) += getDataSize();
|
||||
return res;
|
||||
}
|
||||
|
||||
// virtual
|
||||
U8* LLImageRaw::reallocateData(S32 size)
|
||||
{
|
||||
sGlobalRawMemory -= getDataSize();
|
||||
S32 old_data_size = getDataSize();
|
||||
U8* res = LLImageBase::reallocateData(size);
|
||||
sGlobalRawMemory += getDataSize();
|
||||
*AIAccess<S32>(sGlobalRawMemory) += getDataSize() - old_data_size;
|
||||
return res;
|
||||
}
|
||||
|
||||
// virtual
|
||||
void LLImageRaw::deleteData()
|
||||
{
|
||||
sGlobalRawMemory -= getDataSize();
|
||||
{
|
||||
*AIAccess<S32>(sGlobalRawMemory) -= getDataSize();
|
||||
}
|
||||
LLImageBase::deleteData();
|
||||
}
|
||||
|
||||
@@ -327,7 +329,7 @@ void LLImageRaw::setDataAndSize(U8 *data, S32 width, S32 height, S8 components)
|
||||
LLImageBase::setSize(width, height, components) ;
|
||||
LLImageBase::setDataAndSize(data, width * height * components) ;
|
||||
|
||||
sGlobalRawMemory += getDataSize();
|
||||
*AIAccess<S32>(sGlobalRawMemory) += getDataSize();
|
||||
}
|
||||
|
||||
BOOL LLImageRaw::resize(U16 width, U16 height, S8 components)
|
||||
|
||||
@@ -37,6 +37,7 @@
|
||||
#include "llstring.h"
|
||||
#include "llmemory.h"
|
||||
#include "llthread.h"
|
||||
#include "aithreadsafe.h"
|
||||
|
||||
const S32 MIN_IMAGE_MIP = 2; // 4x4, only used for expand/contract power of 2
|
||||
const S32 MAX_IMAGE_MIP = 11; // 2048x2048
|
||||
@@ -241,7 +242,7 @@ protected:
|
||||
void setDataAndSize(U8 *data, S32 width, S32 height, S8 components) ;
|
||||
|
||||
public:
|
||||
static S32 sGlobalRawMemory;
|
||||
static AIThreadSafeSimple<S32> sGlobalRawMemory;
|
||||
static S32 sRawImageCount;
|
||||
|
||||
static S32 sRawImageCachedCount;
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
#ifndef LL_LLECONOMY_H
|
||||
#define LL_LLECONOMY_H
|
||||
|
||||
#include "llmemory.h"
|
||||
#include "llsingleton.h"
|
||||
|
||||
class LLMessageSystem;
|
||||
class LLVector3;
|
||||
|
||||
@@ -36,10 +36,9 @@
|
||||
#include "lldarray.h"
|
||||
#include "llfoldertype.h"
|
||||
#include "llinventorytype.h"
|
||||
#include "llinventorydefines.h"
|
||||
#include "llmemtype.h"
|
||||
#include "llpermissions.h"
|
||||
#include "llmemory.h"
|
||||
#include "llrefcount.h"
|
||||
#include "llsaleinfo.h"
|
||||
#include "llsd.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);
|
||||
LLPointer<LLInventoryItem> ll_create_item_from_sd(const LLSD& sd_item);
|
||||
LLSD ll_create_sd_from_inventory_category(LLPointer<LLInventoryCategory> cat);
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
#include "llinventorytype.h"
|
||||
#include "lldictionary.h"
|
||||
#include "llmemory.h"
|
||||
#include "llsingleton.h"
|
||||
|
||||
static const std::string empty_string;
|
||||
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
#ifndef LL_NOTECARD_H
|
||||
#define LL_NOTECARD_H
|
||||
|
||||
#include "llmemory.h"
|
||||
#include "llpointer.h"
|
||||
#include "llinventory.h"
|
||||
|
||||
class LLNotecard
|
||||
|
||||
@@ -177,7 +177,7 @@ void LLParcel::init(const LLUUID &owner_id,
|
||||
mSaleTimerExpires.stop();
|
||||
mGraceExtension = 0;
|
||||
//mExpireAction = STEA_REVERT;
|
||||
mRecordTransaction = FALSE;
|
||||
//mRecordTransaction = FALSE;
|
||||
|
||||
mAuctionID = 0;
|
||||
mInEscrow = false;
|
||||
|
||||
@@ -38,8 +38,8 @@
|
||||
#include "lluuid.h"
|
||||
#include "llparcelflags.h"
|
||||
#include "llpermissions.h"
|
||||
#include "v3math.h"
|
||||
#include "lltimer.h"
|
||||
#include "v3math.h"
|
||||
|
||||
// Grid out of which parcels taken is stepped every 4 meters.
|
||||
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
|
||||
// Chunk 0 = southern rows, entire width
|
||||
// NOTE: NOT USABLE FOR VAR SIZED REGIONS!
|
||||
const S32 PARCEL_OVERLAY_CHUNKS = 4;
|
||||
|
||||
// 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 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);
|
||||
|
||||
|
||||
// more accessors
|
||||
U32 getParcelFlags() const { return mParcelFlags; }
|
||||
|
||||
@@ -473,7 +471,9 @@ public:
|
||||
{ return (mParcelFlags & PF_ALLOW_FLY) ? TRUE : FALSE; }
|
||||
|
||||
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
|
||||
{ return (mParcelFlags & PF_ALLOW_GROUP_SCRIPTS) ? TRUE : FALSE; }
|
||||
@@ -599,6 +599,7 @@ public:
|
||||
BOOL getPreviouslyGroupOwned() const { return mPreviouslyGroupOwned; }
|
||||
BOOL getSellWithObjects() const { return (mParcelFlags & PF_SELL_PARCEL_OBJECTS) ? TRUE : FALSE; }
|
||||
|
||||
|
||||
protected:
|
||||
LLUUID mID;
|
||||
LLUUID mOwnerID;
|
||||
@@ -618,8 +619,6 @@ protected:
|
||||
LLTimer mMediaResetTimer;
|
||||
|
||||
S32 mGraceExtension;
|
||||
BOOL mRecordTransaction;
|
||||
|
||||
|
||||
// This value is non-zero if there is an auction associated with
|
||||
// the parcel.
|
||||
@@ -672,7 +671,6 @@ protected:
|
||||
BOOL mRegionDenyAnonymousOverride;
|
||||
BOOL mRegionDenyAgeUnverifiedOverride;
|
||||
|
||||
|
||||
public:
|
||||
// HACK, make private
|
||||
S32 mLocalID;
|
||||
|
||||
@@ -132,5 +132,7 @@ const S32 PARCEL_DETAILS_DESC = 1;
|
||||
const S32 PARCEL_DETAILS_OWNER = 2;
|
||||
const S32 PARCEL_DETAILS_GROUP = 3;
|
||||
const S32 PARCEL_DETAILS_AREA = 4;
|
||||
const S32 PARCEL_DETAILS_ID = 5;
|
||||
const S32 PARCEL_DETAILS_SEE_AVATARS = 6;
|
||||
|
||||
#endif
|
||||
|
||||
@@ -30,8 +30,8 @@
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#include "linden_common.h"
|
||||
#include <iostream>
|
||||
#include "linden_common.h"
|
||||
|
||||
#include "llsaleinfo.h"
|
||||
|
||||
|
||||
@@ -17,13 +17,16 @@ set(llmath_SOURCE_FILES
|
||||
llcamera.cpp
|
||||
llcoordframe.cpp
|
||||
llline.cpp
|
||||
llmatrix3a.cpp
|
||||
llmodularmath.cpp
|
||||
llperlin.cpp
|
||||
llquaternion.cpp
|
||||
llrect.cpp
|
||||
llsphere.cpp
|
||||
llvector4a.cpp
|
||||
llvolume.cpp
|
||||
llvolumemgr.cpp
|
||||
llvolumeoctree.cpp
|
||||
llsdutil_math.cpp
|
||||
m3math.cpp
|
||||
m4math.cpp
|
||||
@@ -53,21 +56,32 @@ set(llmath_HEADER_FILES
|
||||
llinterp.h
|
||||
llline.h
|
||||
llmath.h
|
||||
llmatrix3a.h
|
||||
llmatrix3a.inl
|
||||
llmodularmath.h
|
||||
lloctree.h
|
||||
llperlin.h
|
||||
llplane.h
|
||||
llquantize.h
|
||||
llquaternion.h
|
||||
llquaternion2.h
|
||||
llquaternion2.inl
|
||||
llrect.h
|
||||
llsimdmath.h
|
||||
llsimdtypes.h
|
||||
llsimdtypes.inl
|
||||
llsphere.h
|
||||
lltreenode.h
|
||||
llvector4a.h
|
||||
llvector4a.inl
|
||||
llvector4logical.h
|
||||
llv4math.h
|
||||
llv4matrix3.h
|
||||
llv4matrix4.h
|
||||
llv4vector3.h
|
||||
llvolume.h
|
||||
llvolumemgr.h
|
||||
llvolumeoctree.h
|
||||
llsdutil_math.h
|
||||
m3math.h
|
||||
m4math.h
|
||||
|
||||
@@ -54,28 +54,20 @@ LLCalc* LLCalc::sInstance = NULL;
|
||||
|
||||
LLCalc::LLCalc() : mLastErrorPos(0)
|
||||
{
|
||||
// mUserVariables = new calc_map_t;
|
||||
mVariables = new calc_map_t;
|
||||
mConstants = new calc_map_t;
|
||||
|
||||
// Init table of constants
|
||||
(*mConstants)["PI"] = F_PI;
|
||||
(*mConstants)["TWO_PI"] = F_TWO_PI;
|
||||
(*mConstants)["PI_BY_TWO"] = F_PI_BY_TWO;
|
||||
(*mConstants)["SQRT2"] = F_SQRT2;
|
||||
(*mConstants)["DEG_TO_RAD"] = DEG_TO_RAD;
|
||||
(*mConstants)["RAD_TO_DEG"] = RAD_TO_DEG;
|
||||
(*mConstants)["GRAVITY"] = GRAVITY;
|
||||
(*mConstants)["ALMOST_ZERO"] = F_ALMOST_ZERO;
|
||||
(*mConstants)["ALMOST_ONE"] = F_ALMOST_ONE;
|
||||
(*mConstants)["THE_ANSWER"] = 42;
|
||||
mConstants["PI"] = F_PI;
|
||||
mConstants["TWO_PI"] = F_TWO_PI;
|
||||
mConstants["PI_BY_TWO"] = F_PI_BY_TWO;
|
||||
mConstants["SQRT_TWO_PI"] = F_SQRT_TWO_PI;
|
||||
mConstants["SQRT2"] = F_SQRT2;
|
||||
mConstants["SQRT3"] = F_SQRT3;
|
||||
mConstants["DEG_TO_RAD"] = DEG_TO_RAD;
|
||||
mConstants["RAD_TO_DEG"] = RAD_TO_DEG;
|
||||
mConstants["GRAVITY"] = GRAVITY;
|
||||
}
|
||||
|
||||
LLCalc::~LLCalc()
|
||||
{
|
||||
delete mConstants;
|
||||
delete mVariables;
|
||||
// delete mUserVariables;
|
||||
}
|
||||
|
||||
//static
|
||||
@@ -94,17 +86,17 @@ LLCalc* LLCalc::getInstance()
|
||||
|
||||
void LLCalc::setVar(const std::string& name, const F32& value)
|
||||
{
|
||||
(*mVariables)[name] = value;
|
||||
mVariables[name] = value;
|
||||
}
|
||||
|
||||
void LLCalc::clearVar(const std::string& name)
|
||||
{
|
||||
mVariables->erase(name);
|
||||
mVariables.erase(name);
|
||||
}
|
||||
|
||||
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;
|
||||
LLStringUtil::toUpper(expr_upper);
|
||||
|
||||
LLCalcParser calc(result, mConstants, mVariables);
|
||||
LLCalcParser calc(result, &mConstants, &mVariables);
|
||||
|
||||
mLastErrorPos = 0;
|
||||
std::string::iterator start = expr_upper.begin();
|
||||
|
||||
@@ -69,8 +69,8 @@ public:
|
||||
private:
|
||||
std::string::size_type mLastErrorPos;
|
||||
|
||||
calc_map_t* mConstants;
|
||||
calc_map_t* mVariables;
|
||||
calc_map_t mConstants;
|
||||
calc_map_t mVariables;
|
||||
|
||||
// *TODO: Add support for storing user defined variables, and stored functions.
|
||||
// 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("LOG") >> '(' >> expression[unary_func.value = bind(&LLCalcParser::_log)(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(')'))
|
||||
;
|
||||
|
||||
@@ -118,7 +120,8 @@ struct LLCalcParser : grammar<LLCalcParser>
|
||||
term =
|
||||
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 _log(const F32& a) const { return log(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); }
|
||||
|
||||
|
||||
@@ -92,7 +92,7 @@ F32 LLCamera::getMaxView() const
|
||||
|
||||
// ---------------- LLCamera::setFoo() member functions ----------------
|
||||
|
||||
void LLCamera::setUserClipPlane(LLPlane const& plane)
|
||||
void LLCamera::setUserClipPlane(const LLPlane& plane)
|
||||
{
|
||||
mPlaneCount = 7;
|
||||
mAgentPlanes[6] = plane;
|
||||
@@ -168,166 +168,91 @@ size_t LLCamera::readFrustumFromBuffer(const char *buffer)
|
||||
|
||||
// ---------------- test methods ----------------
|
||||
|
||||
S32 LLCamera::AABBInFrustum(const LLVector3 ¢er, const LLVector3& radius)
|
||||
S32 LLCamera::AABBInFrustum(const LLVector4a ¢er, const LLVector4a& radius)
|
||||
{
|
||||
static const LLVector3 scaler[] = {
|
||||
LLVector3(-1,-1,-1),
|
||||
LLVector3( 1,-1,-1),
|
||||
LLVector3(-1, 1,-1),
|
||||
LLVector3( 1, 1,-1),
|
||||
LLVector3(-1,-1, 1),
|
||||
LLVector3( 1,-1, 1),
|
||||
LLVector3(-1, 1, 1),
|
||||
LLVector3( 1, 1, 1)
|
||||
static const LLVector4a scaler[] = {
|
||||
LLVector4a(-1,-1,-1),
|
||||
LLVector4a( 1,-1,-1),
|
||||
LLVector4a(-1, 1,-1),
|
||||
LLVector4a( 1, 1,-1),
|
||||
LLVector4a(-1,-1, 1),
|
||||
LLVector4a( 1,-1, 1),
|
||||
LLVector4a(-1, 1, 1),
|
||||
LLVector4a( 1, 1, 1)
|
||||
};
|
||||
|
||||
U8 mask = 0;
|
||||
S32 result = 2;
|
||||
|
||||
/*if (radius.magVecSquared() > mFrustumCornerDist * mFrustumCornerDist)
|
||||
{ //box is larger than frustum, check frustum quads against box planes
|
||||
|
||||
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*/
|
||||
bool result = false;
|
||||
LLVector4a rscale, maxp, minp;
|
||||
LLSimdScalar d;
|
||||
for (U32 i = 0; i < mPlaneCount; i++)
|
||||
{
|
||||
for (U32 i = 0; i < mPlaneCount; i++)
|
||||
mask = mPlaneMask[i];
|
||||
if (mask != 0xff)
|
||||
{
|
||||
mask = mPlaneMask[i];
|
||||
if (mask == 0xff)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
LLPlane p = mAgentPlanes[i];
|
||||
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)
|
||||
const LLPlane& p(mAgentPlanes[i]);
|
||||
p.getAt<3>(d);
|
||||
rscale.setMul(radius, scaler[mask]);
|
||||
minp.setSub(center, rscale);
|
||||
d = -d;
|
||||
if (p.dot3(minp).getF32() > d)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (n * maxp > -d)
|
||||
|
||||
if(!result)
|
||||
{
|
||||
result = 1;
|
||||
maxp.setAdd(center, rscale);
|
||||
result = (p.dot3(maxp).getF32() > d);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return result;
|
||||
return result?1:2;
|
||||
}
|
||||
|
||||
S32 LLCamera::AABBInFrustumNoFarClip(const LLVector3 ¢er, const LLVector3& radius)
|
||||
|
||||
S32 LLCamera::AABBInFrustumNoFarClip(const LLVector4a& center, const LLVector4a& radius)
|
||||
{
|
||||
static const LLVector3 scaler[] = {
|
||||
LLVector3(-1,-1,-1),
|
||||
LLVector3( 1,-1,-1),
|
||||
LLVector3(-1, 1,-1),
|
||||
LLVector3( 1, 1,-1),
|
||||
LLVector3(-1,-1, 1),
|
||||
LLVector3( 1,-1, 1),
|
||||
LLVector3(-1, 1, 1),
|
||||
LLVector3( 1, 1, 1)
|
||||
static const LLVector4a scaler[] = {
|
||||
LLVector4a(-1,-1,-1),
|
||||
LLVector4a( 1,-1,-1),
|
||||
LLVector4a(-1, 1,-1),
|
||||
LLVector4a( 1, 1,-1),
|
||||
LLVector4a(-1,-1, 1),
|
||||
LLVector4a( 1,-1, 1),
|
||||
LLVector4a(-1, 1, 1),
|
||||
LLVector4a( 1, 1, 1)
|
||||
};
|
||||
|
||||
U8 mask = 0;
|
||||
S32 result = 2;
|
||||
|
||||
bool result = false;
|
||||
LLVector4a rscale, maxp, minp;
|
||||
LLSimdScalar d;
|
||||
for (U32 i = 0; i < mPlaneCount; i++)
|
||||
{
|
||||
if (i == 5)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
mask = mPlaneMask[i];
|
||||
if (mask == 0xff)
|
||||
if ((i != 5) && (mask != 0xff))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
LLPlane p = mAgentPlanes[i];
|
||||
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;
|
||||
}
|
||||
|
||||
if (n * maxp > -d)
|
||||
{
|
||||
result = 1;
|
||||
const LLPlane& p(mAgentPlanes[i]);
|
||||
p.getAt<3>(d);
|
||||
rscale.setMul(radius, scaler[mask]);
|
||||
minp.setSub(center, rscale);
|
||||
d = -d;
|
||||
if (p.dot3(minp).getF32() > d)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(!result)
|
||||
{
|
||||
maxp.setAdd(center, rscale);
|
||||
result = (p.dot3(maxp).getF32() > d);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
return result?1:2;
|
||||
}
|
||||
|
||||
int LLCamera::sphereInFrustumQuick(const LLVector3 &sphere_center, const F32 radius)
|
||||
@@ -715,9 +640,10 @@ void LLCamera::calculateWorldFrustumPlanes()
|
||||
F32 d;
|
||||
LLVector3 center = mOrigin - mXAxis*mNearPlane;
|
||||
mWorldPlanePos = center;
|
||||
LLVector3 pnorm;
|
||||
for (int p=0; p<4; p++)
|
||||
{
|
||||
LLVector3 pnorm = LLVector3(mLocalPlanes[p]);
|
||||
mLocalPlanes[p].getVector3(pnorm);
|
||||
LLVector3 norm = rotateToAbsolute(pnorm);
|
||||
norm.normVec();
|
||||
d = -(center * norm);
|
||||
@@ -727,13 +653,15 @@ void LLCamera::calculateWorldFrustumPlanes()
|
||||
LLVector3 zaxis(0, 0, 1.0f);
|
||||
F32 yaw = getYaw();
|
||||
{
|
||||
LLVector3 tnorm = LLVector3(mLocalPlanes[PLANE_LEFT]);
|
||||
LLVector3 tnorm;
|
||||
mLocalPlanes[PLANE_LEFT].getVector3(tnorm);
|
||||
tnorm.rotVec(yaw, zaxis);
|
||||
d = -(mOrigin * tnorm);
|
||||
mHorizPlanes[HORIZ_PLANE_LEFT] = LLPlane(tnorm, d);
|
||||
}
|
||||
{
|
||||
LLVector3 tnorm = LLVector3(mLocalPlanes[PLANE_RIGHT]);
|
||||
LLVector3 tnorm;
|
||||
mLocalPlanes[PLANE_RIGHT].getVector3(tnorm);
|
||||
tnorm.rotVec(yaw, zaxis);
|
||||
d = -(mOrigin * tnorm);
|
||||
mHorizPlanes[HORIZ_PLANE_RIGHT] = LLPlane(tnorm, d);
|
||||
|
||||
@@ -37,6 +37,7 @@
|
||||
#include "llmath.h"
|
||||
#include "llcoordframe.h"
|
||||
#include "llplane.h"
|
||||
#include "llvector4a.h"
|
||||
|
||||
const F32 DEFAULT_FIELD_OF_VIEW = 60.f * DEG_TO_RAD;
|
||||
const F32 DEFAULT_ASPECT_RATIO = 640.f / 480.f;
|
||||
@@ -143,7 +144,7 @@ public:
|
||||
virtual ~LLCamera();
|
||||
|
||||
|
||||
void setUserClipPlane(LLPlane const& plane);
|
||||
void setUserClipPlane(const LLPlane& plane);
|
||||
void disableUserClipPlane();
|
||||
virtual void setView(F32 vertical_fov_rads);
|
||||
void setViewHeightInPixels(S32 height);
|
||||
@@ -191,8 +192,8 @@ public:
|
||||
S32 sphereInFrustum(const LLVector3 ¢er, const F32 radius) const;
|
||||
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 AABBInFrustum(const LLVector3 ¢er, const LLVector3& radius);
|
||||
S32 AABBInFrustumNoFarClip(const LLVector3 ¢er, const LLVector3& radius);
|
||||
S32 AABBInFrustum(const LLVector4a& center, const LLVector4a& radius);
|
||||
S32 AABBInFrustumNoFarClip(const LLVector4a& center, const LLVector4a& radius);
|
||||
|
||||
//does a quick 'n dirty sphere-sphere check
|
||||
S32 sphereInFrustumQuick(const LLVector3 &sphere_center, const F32 radius);
|
||||
|
||||
@@ -38,6 +38,7 @@
|
||||
// So, let's define _USE_MATH_DEFINES before including math.h
|
||||
#define _USE_MATH_DEFINES
|
||||
#endif
|
||||
|
||||
#include "math.h"
|
||||
|
||||
// Class from which different types of interpolators can be derived
|
||||
|
||||
@@ -35,10 +35,10 @@
|
||||
|
||||
#include <cmath>
|
||||
#include <cstdlib>
|
||||
#include <complex>
|
||||
#include <vector>
|
||||
#include "lldefs.h"
|
||||
#include "llstl.h" // *TODO: Remove when LLString is gone
|
||||
#include "llstring.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
|
||||
// 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
|
||||
// llcommon depend on llmath.
|
||||
@@ -61,32 +61,11 @@
|
||||
#endif
|
||||
|
||||
// Single Precision Floating Point Routines
|
||||
#ifndef sqrtf
|
||||
#define sqrtf(x) ((F32)sqrt((F64)(x)))
|
||||
#endif
|
||||
#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
|
||||
// (There used to be more defined here, but they appeared to be redundant and
|
||||
// were breaking some other includes. Removed by Falcon, reviewed by Andrew, 11/25/09)
|
||||
/*#ifndef tanf
|
||||
#define tanf(x) ((F32)tan((F64)(x)))
|
||||
#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
|
||||
#endif*/
|
||||
|
||||
const F32 GRAVITY = -9.8f;
|
||||
|
||||
@@ -206,7 +185,7 @@ inline S32 llfloor( F32 f )
|
||||
}
|
||||
return result;
|
||||
#else
|
||||
return (S32)floorf(f);
|
||||
return (S32)floor(f);
|
||||
#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 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 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);
|
||||
}
|
||||
}
|
||||
|
||||
// Include simd math header
|
||||
#include "llsimdmath.h"
|
||||
#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 "v3math.h"
|
||||
#include "llvector4a.h"
|
||||
#include <vector>
|
||||
#include <set>
|
||||
|
||||
@@ -85,6 +86,7 @@ template <class T>
|
||||
class LLOctreeNode : public LLTreeNode<T>
|
||||
{
|
||||
public:
|
||||
|
||||
typedef LLOctreeTraveler<T> oct_traveler;
|
||||
typedef LLTreeTraveler<T> tree_traveler;
|
||||
typedef typename std::set<LLPointer<T> > element_list;
|
||||
@@ -96,23 +98,30 @@ public:
|
||||
typedef LLOctreeNode<T> oct_node;
|
||||
typedef LLOctreeListener<T> oct_listener;
|
||||
|
||||
static const U8 OCTANT_POSITIVE_X = 0x01;
|
||||
static const U8 OCTANT_POSITIVE_Y = 0x02;
|
||||
static const U8 OCTANT_POSITIVE_Z = 0x04;
|
||||
|
||||
LLOctreeNode( LLVector3d center,
|
||||
LLVector3d size,
|
||||
/*void* operator new(size_t size)
|
||||
{
|
||||
return ll_aligned_malloc_16(size);
|
||||
}
|
||||
|
||||
void operator delete(void* ptr)
|
||||
{
|
||||
ll_aligned_free_16(ptr);
|
||||
}*/
|
||||
|
||||
LLOctreeNode( const LLVector4a& center,
|
||||
const LLVector4a& size,
|
||||
BaseType* parent,
|
||||
U8 octant = 255)
|
||||
: mParent((oct_node*)parent),
|
||||
mCenter(center),
|
||||
mSize(size),
|
||||
mOctant(octant)
|
||||
{
|
||||
mCenter = center;
|
||||
mSize = size;
|
||||
|
||||
updateMinMax();
|
||||
if ((mOctant == 255) && mParent)
|
||||
{
|
||||
mOctant = ((oct_node*) mParent)->getOctant(mCenter.mdV);
|
||||
mOctant = ((oct_node*) mParent)->getOctant(mCenter);
|
||||
}
|
||||
|
||||
clearChildren();
|
||||
@@ -129,39 +138,24 @@ public:
|
||||
}
|
||||
|
||||
inline const BaseType* getParent() const { return mParent; }
|
||||
inline void setParent(BaseType* parent) { mParent = (oct_node*) parent; }
|
||||
inline const LLVector3d& getCenter() const { return mCenter; }
|
||||
inline const LLVector3d& getSize() const { return mSize; }
|
||||
inline void setCenter(const LLVector3d center) { mCenter = center; }
|
||||
inline void setSize(const LLVector3d size) { mSize = size; }
|
||||
inline void setParent(BaseType* parent) { mParent = (oct_node*) parent; }
|
||||
inline const LLVector4a& getCenter() const { return mCenter; }
|
||||
inline const LLVector4a& getSize() const { return mSize; }
|
||||
inline void setCenter(const LLVector4a& center) { mCenter = center; }
|
||||
inline void setSize(const LLVector4a& size) { mSize = size; }
|
||||
inline oct_node* getNodeAt(T* data) { return getNodeAt(data->getPositionGroup(), data->getBinRadius()); }
|
||||
inline U8 getOctant() const { return mOctant; }
|
||||
inline const oct_node* getOctParent() const { return (const 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;
|
||||
|
||||
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;
|
||||
return (U8) (pos.greaterThan(mCenter).getGatheredBits() & 0x7);
|
||||
}
|
||||
|
||||
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
|
||||
@@ -169,29 +163,27 @@ public:
|
||||
return isInside(data->getPositionGroup(), data->getBinRadius());
|
||||
}
|
||||
|
||||
bool isInside(const LLVector3d& pos) const
|
||||
bool isInside(const LLVector4a& pos) const
|
||||
{
|
||||
const F64& x = pos.mdV[0];
|
||||
const F64& y = pos.mdV[1];
|
||||
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])
|
||||
S32 gt = pos.greaterThan(mMax).getGatheredBits() & 0x7;
|
||||
if (gt)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
S32 lt = pos.lessEqual(mMin).getGatheredBits() & 0x7;
|
||||
if (lt)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void updateMinMax()
|
||||
{
|
||||
for (U32 i = 0; i < 3; i++)
|
||||
{
|
||||
mMax.mdV[i] = mCenter.mdV[i] + mSize.mdV[i];
|
||||
mMin.mdV[i] = mCenter.mdV[i] - mSize.mdV[i];
|
||||
}
|
||||
mMax.setAdd(mCenter, mSize);
|
||||
mMin.setSub(mCenter, mSize);
|
||||
}
|
||||
|
||||
inline oct_listener* getOctListener(U32 index)
|
||||
@@ -218,20 +210,20 @@ public:
|
||||
(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();
|
||||
for (U32 i = 0; i < 3; i++)
|
||||
{
|
||||
if (pos.mdV[i] > center.mdV[i])
|
||||
{
|
||||
center.mdV[i] += size.mdV[i];
|
||||
}
|
||||
else
|
||||
{
|
||||
center.mdV[i] -= size.mdV[i];
|
||||
}
|
||||
}
|
||||
const LLVector4a& pos = data->getPositionGroup();
|
||||
|
||||
LLVector4Logical gt = pos.greaterThan(center);
|
||||
|
||||
LLVector4a up;
|
||||
up = _mm_and_ps(size, gt);
|
||||
|
||||
LLVector4a down;
|
||||
down = _mm_andnot_ps(gt, size);
|
||||
|
||||
center.add(up);
|
||||
center.sub(down);
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
if (node->isInside(pos, rad))
|
||||
{
|
||||
//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
|
||||
//at the appropriate octant or is smaller than the object.
|
||||
@@ -291,7 +283,7 @@ public:
|
||||
while (next_node != 255 && node->getSize()[0] >= rad)
|
||||
{
|
||||
node = node->getChild(next_node);
|
||||
octant = node->getOctant(pos.mdV);
|
||||
octant = node->getOctant(pos);
|
||||
next_node = node->mChildMap[octant];
|
||||
}
|
||||
}
|
||||
@@ -307,7 +299,7 @@ public:
|
||||
{
|
||||
if (data == NULL)
|
||||
{
|
||||
//OCT_ERRS << "!!! INVALID ELEMENT ADDED TO OCTREE BRANCH !!!" << llendl;
|
||||
OCT_ERRS << "!!! INVALID ELEMENT ADDED TO OCTREE BRANCH !!!" << llendl;
|
||||
return false;
|
||||
}
|
||||
LLOctreeNode<T>* parent = getOctParent();
|
||||
@@ -347,16 +339,21 @@ public:
|
||||
}
|
||||
|
||||
//it's here, but no kids are in the right place, make a new kid
|
||||
LLVector3d center(getCenter());
|
||||
LLVector3d size(getSize()*0.5);
|
||||
LLVector4a center = getCenter();
|
||||
LLVector4a size = getSize();
|
||||
size.mul(0.5f);
|
||||
|
||||
//push center in direction of data
|
||||
LLOctreeNode<T>::pushCenter(center, size, data);
|
||||
|
||||
// handle case where floating point number gets too small
|
||||
if( llabs(center.mdV[0] - getCenter().mdV[0]) < F_APPROXIMATELY_ZERO &&
|
||||
llabs(center.mdV[1] - getCenter().mdV[1]) < F_APPROXIMATELY_ZERO &&
|
||||
llabs(center.mdV[2] - getCenter().mdV[2]) < F_APPROXIMATELY_ZERO)
|
||||
LLVector4a val;
|
||||
val.setSub(center, getCenter());
|
||||
val.setAbs(val);
|
||||
|
||||
S32 lt = val.lessThan(LLVector4a::getEpsilon()).getGatheredBits() & 0x7;
|
||||
|
||||
if( lt == 0x7 )
|
||||
{
|
||||
mData.insert(data);
|
||||
BaseType::insert(data);
|
||||
@@ -374,7 +371,7 @@ public:
|
||||
//make sure no existing node matches this position
|
||||
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;
|
||||
return false;
|
||||
@@ -392,7 +389,7 @@ public:
|
||||
else
|
||||
{
|
||||
//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;
|
||||
|
||||
@@ -503,18 +500,18 @@ public:
|
||||
{
|
||||
#if LL_OCTREE_PARANOIA_CHECK
|
||||
|
||||
if (child->getSize() == getSize())
|
||||
if (child->getSize().equals3(getSize()))
|
||||
{
|
||||
OCT_ERRS << "Child size is same as parent size!" << llendl;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
if (mChild[i]->getCenter() == child->getCenter())
|
||||
if (mChild[i]->getCenter().equals3(child->getCenter()))
|
||||
{
|
||||
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:
|
||||
@@ -605,11 +602,11 @@ protected:
|
||||
MIN = 3
|
||||
} eDName;
|
||||
|
||||
LLVector3d mCenter;
|
||||
LLVector3d mSize;
|
||||
LLVector3d mMax;
|
||||
LLVector3d mMin;
|
||||
|
||||
LLVector4a mCenter;
|
||||
LLVector4a mSize;
|
||||
LLVector4a mMax;
|
||||
LLVector4a mMin;
|
||||
|
||||
oct_node* mParent;
|
||||
U8 mOctant;
|
||||
|
||||
@@ -628,9 +625,9 @@ public:
|
||||
typedef LLOctreeNode<T> BaseType;
|
||||
typedef LLOctreeNode<T> oct_node;
|
||||
|
||||
LLOctreeRoot( const LLVector3d ¢er,
|
||||
const LLVector3d &size,
|
||||
BaseType* parent)
|
||||
LLOctreeRoot(const LLVector4a& center,
|
||||
const LLVector4a& size,
|
||||
BaseType* parent)
|
||||
: BaseType(center, size, parent)
|
||||
{
|
||||
}
|
||||
@@ -673,28 +670,33 @@ public:
|
||||
{
|
||||
if (data == NULL)
|
||||
{
|
||||
//OCT_ERRS << "!!! INVALID ELEMENT ADDED TO OCTREE ROOT !!!" << llendl;
|
||||
OCT_ERRS << "!!! INVALID ELEMENT ADDED TO OCTREE ROOT !!!" << llendl;
|
||||
return false;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
const F64 MAX_MAG = 1024.0*1024.0;
|
||||
LLVector4a MAX_MAG;
|
||||
MAX_MAG.splat(1024.f*1024.f);
|
||||
|
||||
const LLVector3d& v = data->getPositionGroup();
|
||||
if (!(fabs(v.mdV[0]-this->mCenter.mdV[0]) < MAX_MAG &&
|
||||
fabs(v.mdV[1]-this->mCenter.mdV[1]) < MAX_MAG &&
|
||||
fabs(v.mdV[2]-this->mCenter.mdV[2]) < MAX_MAG))
|
||||
const LLVector4a& v = data->getPositionGroup();
|
||||
|
||||
LLVector4a val;
|
||||
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;
|
||||
}
|
||||
|
||||
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
|
||||
oct_node* node = getNodeAt(data);
|
||||
@@ -710,31 +712,34 @@ public:
|
||||
else if (this->getChildCount() == 0)
|
||||
{
|
||||
//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();
|
||||
size = this->getSize();
|
||||
LLOctreeNode<T>::pushCenter(center, size, data);
|
||||
this->setCenter(center);
|
||||
this->setSize(size*2);
|
||||
size.mul(2.f);
|
||||
this->setSize(size);
|
||||
this->updateMinMax();
|
||||
}
|
||||
LLOctreeNode<T>::insert(data);
|
||||
}
|
||||
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
|
||||
LLVector3d center(this->getCenter());
|
||||
LLVector3d size(this->getSize());
|
||||
LLVector4a center(this->getCenter());
|
||||
LLVector4a size(this->getSize());
|
||||
|
||||
//expand this node
|
||||
LLVector3d newcenter(center);
|
||||
LLVector4a newcenter(center);
|
||||
LLOctreeNode<T>::pushCenter(newcenter, size, data);
|
||||
this->setCenter(newcenter);
|
||||
this->setSize(size*2);
|
||||
LLVector4a size2 = size;
|
||||
size2.mul(2.f);
|
||||
this->setSize(size2);
|
||||
this->updateMinMax();
|
||||
|
||||
//copy our children to a new branch
|
||||
|
||||
@@ -42,13 +42,17 @@
|
||||
// The plane normal = [A, B, C]
|
||||
// The closest approach = D / sqrt(A*A + B*B + C*C)
|
||||
|
||||
class LLPlane : public LLVector4
|
||||
class LLPlane
|
||||
{
|
||||
public:
|
||||
|
||||
// Constructors
|
||||
LLPlane() {}; // no default constructor
|
||||
LLPlane(const LLVector3 &p0, F32 d) { setVec(p0, d); }
|
||||
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)
|
||||
{
|
||||
F32 d = -(p0 * n);
|
||||
@@ -64,39 +68,38 @@ public:
|
||||
F32 d = -(w * p0);
|
||||
setVec(w, d);
|
||||
}
|
||||
|
||||
inline LLPlane& operator=(const LLVector4& v2) { LLVector4::setVec(v2[0],v2[1],v2[2],v2[3]); return *this;}
|
||||
|
||||
inline void set(const LLPlane& p2) { LLVector4::setVec(p2); }
|
||||
|
||||
inline LLPlane& operator=(const LLVector4& v2) { mV.set(v2[0],v2[1],v2[2],v2[3]); return *this;}
|
||||
|
||||
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]; }
|
||||
|
||||
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
|
||||
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]); }
|
||||
|
||||
|
||||
// Retrieve the mask indicating which of the x, y, or z axis are greater or equal to zero.
|
||||
inline U8 calcPlaneMask() const
|
||||
{
|
||||
U8 mask = 0;
|
||||
|
||||
if (mV[0] >= 0)
|
||||
{
|
||||
mask |= 1;
|
||||
}
|
||||
if (mV[1] >= 0)
|
||||
{
|
||||
mask |= 2;
|
||||
}
|
||||
if (mV[2] >= 0)
|
||||
{
|
||||
mask |= 4;
|
||||
}
|
||||
|
||||
return mask;
|
||||
{
|
||||
return mV.greaterEqual(LLVector4a::getZero()).getGatheredBits() & LLVector4Logical::MASK_XYZ;
|
||||
}
|
||||
|
||||
private:
|
||||
LLVector4a mV;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -35,10 +35,16 @@
|
||||
#define LL_LLQUANTIZE_H
|
||||
|
||||
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);
|
||||
LL_ALIGN_16( const F32 F_OOU16MAX_4A[4] ) = { OOU16MAX, OOU16MAX, OOU16MAX, OOU16MAX };
|
||||
|
||||
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);
|
||||
LL_ALIGN_16( const F32 F_OOU8MAX_4A[4] ) = { OOU8MAX, OOU8MAX, OOU8MAX, OOU8MAX };
|
||||
|
||||
const U8 FIRSTVALIDCHAR = 54;
|
||||
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"
|
||||
|
||||
// implementation is all in the header, this include dep ensures the unit test is rerun if the implementation changes.
|
||||
#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