Merge branch 'future' of git://github.com/siana/SingularityViewer.git into future

This commit is contained in:
Shyotl
2011-09-19 16:22:20 -05:00
816 changed files with 39828 additions and 10522 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View 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() ;
}

View File

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

View File

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

View File

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

View File

@@ -37,7 +37,7 @@
// Header Files
//-----------------------------------------------------------------------------
#include "lljoint.h"
#include "llmemory.h"
#include "llrefcount.h"
//-----------------------------------------------------------------------------
// class LLJointState

View File

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

View File

@@ -40,6 +40,8 @@
#include "lljointstate.h"
#include "lljoint.h"
#include "llmap.h"
#include "llpointer.h"
#include <map>
#include <string>

View File

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

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

View File

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

View 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

View File

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

View File

@@ -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 */
//@{

View File

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

View File

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

View File

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

View File

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

View File

@@ -38,6 +38,8 @@
#include <iosfwd>
#include <string>
#include "llpreprocessor.h"
#include "stdtypes.h"
/**

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -74,9 +74,3 @@ void LLMortician::setZealous(BOOL b)
{
sDestroyImmediate = b;
}
// static
BOOL LLMortician::getZealous()
{
return sDestroyImmediate;
}

View File

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

View File

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

View File

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

View File

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

View File

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

View 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

View 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

View 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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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

View 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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -36,6 +36,8 @@
#include "u64.h"
#include "lldate.h"
#if LL_WINDOWS
# define WIN32_LEAN_AND_MEAN
# include <winsock2.h>

View File

@@ -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 &timestr);
LL_COMMON_API void timeStructToFormattedString(struct tm * time, std::string format, std::string &timestr);
U64 LL_COMMON_API totalTime(); // Returns current system time in microseconds
#endif

View 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) */

View File

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

View File

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

View File

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

View File

@@ -32,7 +32,7 @@
#ifndef LL_LLECONOMY_H
#define LL_LLECONOMY_H
#include "llmemory.h"
#include "llsingleton.h"
class LLMessageSystem;
class LLVector3;

View File

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

View File

@@ -35,6 +35,7 @@
#include "llinventorytype.h"
#include "lldictionary.h"
#include "llmemory.h"
#include "llsingleton.h"
static const std::string empty_string;

View File

@@ -33,7 +33,7 @@
#ifndef LL_NOTECARD_H
#define LL_NOTECARD_H
#include "llmemory.h"
#include "llpointer.h"
#include "llinventory.h"
class LLNotecard

View File

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

View File

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

View File

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

View File

@@ -30,8 +30,8 @@
* $/LicenseInfo$
*/
#include "linden_common.h"
#include <iostream>
#include "linden_common.h"
#include "llsaleinfo.h"

View File

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

View File

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

View File

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

View File

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

View File

@@ -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 &center, const LLVector3& radius)
S32 LLCamera::AABBInFrustum(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;
/*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 &center, 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);

View File

@@ -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 &center, const F32 radius) const;
S32 pointInFrustum(const LLVector3 &point) const { return sphereInFrustum(point, 0.0f); }
S32 sphereInFrustumFull(const LLVector3 &center, const F32 radius) const { return sphereInFrustum(center, radius); }
S32 AABBInFrustum(const LLVector3 &center, const LLVector3& radius);
S32 AABBInFrustumNoFarClip(const LLVector3 &center, 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);

View File

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

View File

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

View File

@@ -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 &center, const LLVector3d &size, const T* data)
static void pushCenter(LLVector4a &center, 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 &center,
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

View File

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

View File

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

View 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

View 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();
}

View File

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