diff --git a/indra/llmath/CMakeLists.txt b/indra/llmath/CMakeLists.txt index 0614fd92ef..a742a8d124 100755 --- a/indra/llmath/CMakeLists.txt +++ b/indra/llmath/CMakeLists.txt @@ -93,6 +93,10 @@ set(llmath_HEADER_FILES xform.h ) +set( llmath_SOURCE_FILES ${llmath_SOURCE_FILES} nd/ndoctreelog.cpp ) +set( llmath_HEADER_FILES ${llmath_HEADER_FILES} nd/ndoctreelog.h ) + + set_source_files_properties(${llmath_HEADER_FILES} PROPERTIES HEADER_FILE_ONLY TRUE) diff --git a/indra/llmath/lloctree.h b/indra/llmath/lloctree.h index e2187ed24c..9552e4a0d8 100755 --- a/indra/llmath/lloctree.h +++ b/indra/llmath/lloctree.h @@ -32,6 +32,8 @@ #include "llvector4a.h" #include +#include "nd/ndoctreelog.h" + #define OCT_ERRS LL_WARNS("OctreeErrors") @@ -120,6 +122,7 @@ public: if ((mOctant == 255) && mParent) { mOctant = ((oct_node*) mParent)->getOctant(mCenter); + ND_OCTREE_LOG << "set octant to " << (U32)mOctant << " mCenter " << mCenter << " mParent->mCenter " << mParent->mCenter << ND_OCTREE_LOG_END; } mElementCount = 0; @@ -319,12 +322,22 @@ public: } LLOctreeNode* parent = getOctParent(); + ND_OCTREE_LOG << "Inserting data, this->getSize " << this->getSize() << " this->getElementCount() " << this->getElementCount() << " this->getChildCount() " << this->getChildCount() << std::endl + << " this->mMin " << this->mMin << " this->mMax " << this->mMax << std::endl + << " data->getPositionGroup().greaterThan(mMax).getGatheredBits() " << (S32)( data->getPositionGroup().greaterThan(mMax).getGatheredBits() & 0x7 ) + << " data->getPositionGroup().lessEqual(mMin).getGatheredBits() " << (S32)(data->getPositionGroup().lessEqual(mMin).getGatheredBits() & 0x7) + << std::endl << " data->getBinRadius() " << data->getBinRadius() << " data->getPositionGroup() " << data->getPositionGroup() << ND_OCTREE_LOG_END; + //is it here? if (isInside(data->getPositionGroup())) { + ND_OCTREE_LOG << "Inserting data, isInside(data->getPositionGroup()) true " << ND_OCTREE_LOG_END; + if (((getElementCount() < gOctreeMaxCapacity || getSize()[0] <= gOctreeMinSize) && contains(data->getBinRadius()) || (data->getBinRadius() > getSize()[0] && parent && parent->getElementCount() >= gOctreeMaxCapacity))) { //it belongs here + ND_OCTREE_LOG << "Inserting data into this" << ND_OCTREE_LOG_END; + mData.push_back(NULL); mData[mElementCount] = data; mElementCount++; @@ -335,11 +348,20 @@ public: } else { + ND_OCTREE_LOG << "Inserting data into children this->getChildCount() " << this->getChildCount() << ND_OCTREE_LOG_END; + //find a child to give it to oct_node* child = NULL; for (U32 i = 0; i < getChildCount(); i++) { child = getChild(i); + + ND_OCTREE_LOG << "child " << i << " child->getSize " << child->getSize() << " child->getElementCount() " << child->getElementCount() << " child->getChildCount() " << child->getChildCount() << std::endl + << " child->mMin " << child->mMin << " child->mMax " << child->mMax << std::endl + << " data->getPositionGroup().greaterThan(child->mMax).getGatheredBits() " << (S32)(data->getPositionGroup().greaterThan(child->mMax).getGatheredBits() & 0x7) + << " data->getPositionGroup().lessEqual(child->mMin).getGatheredBits() " << (S32)(data->getPositionGroup().lessEqual(child->mMin).getGatheredBits() & 0x7) + << std::endl << ND_OCTREE_LOG_END; + if (child->isInside(data->getPositionGroup())) { child->insert(data); @@ -363,8 +385,15 @@ public: S32 lt = val.lessThan(min_diff).getGatheredBits() & 0x7; - if( lt == 0x7 ) + ND_OCTREE_LOG << "Creating a new child new center " << center << " new size " << size << " val " << val << " min_diff " << min_diff << " lt " << lt << ND_OCTREE_LOG_END; + + // Do not create a child if any of x/y/z is under minimum. One of those falling below is enough to get precision errors. + // if( lt == 0x7 ) + if( lt ) + // { + ND_OCTREE_LOG << "Adding to parent and exit" << ND_OCTREE_LOG_END; + mData.push_back(NULL); mData[mElementCount] = data; mElementCount++; @@ -393,6 +422,8 @@ public: } #endif + ND_OCTREE_LOG << "Adding to child" << ND_OCTREE_LOG_END; + llassert(size[0] >= gOctreeMinSize*0.5f); //make the new kid child = new LLOctreeNode(center, size, this); @@ -577,6 +608,10 @@ public: OCT_ERRS <<"Octree node has too many children... why?" << llendl; } #endif + ND_OCTREE_LOG << "addChild octant " << (U32)child->getOctant() << " mChildCount " << mChildCount << ND_OCTREE_LOG_END; + + if( mChildCount >= 8 ) + llerrs << "Octree overrun" << llendl; mChildMap[child->getOctant()] = mChildCount; diff --git a/indra/llmath/llvolume.cpp b/indra/llmath/llvolume.cpp index 64acc2e187..538eacc834 100755 --- a/indra/llmath/llvolume.cpp +++ b/indra/llmath/llvolume.cpp @@ -5373,6 +5373,8 @@ void LLVolumeFace::createOctree(F32 scaler, const LLVector4a& center, const LLVe return; } + ND_OCTREE_LOG << "Creating octree with scale " << scaler << " mNumIndices " << mNumIndices << ND_OCTREE_LOG_END; + mOctree = new LLOctreeRoot(center, size, NULL); new LLVolumeOctreeListener(mOctree); @@ -5417,10 +5419,18 @@ void LLVolumeFace::createOctree(F32 scaler, const LLVector4a& center, const LLVe tri->mRadius = size.getLength3().getF32() * scaler; + ND_OCTREE_LOG << "insertion " << i + << " tri.mV " << *tri->mV[0] << "/" << *tri->mV[1] << "/" << *tri->mV[2] + << " tri.mIndex " << tri->mIndex[0] << "/" << tri->mIndex[1] << "/" << tri->mIndex[2] + << ND_OCTREE_LOG_END; + //insert mOctree->insert(tri); + ND_OCTREE_LOG << "insertion done" << std::endl << ND_OCTREE_LOG_END; } + ND_OCTREE_LOG << "octree created" << std::endl << std::endl << ND_OCTREE_LOG_END; + //remove unneeded octree layers while (!mOctree->balance()) { } diff --git a/indra/llmath/nd/ndoctreelog.cpp b/indra/llmath/nd/ndoctreelog.cpp new file mode 100644 index 0000000000..e26d9977d9 --- /dev/null +++ b/indra/llmath/nd/ndoctreelog.cpp @@ -0,0 +1,76 @@ +/** + * $LicenseInfo:firstyear=2014&license=fsviewerlgpl$ + * Phoenix Firestorm Viewer Source Code + * Copyright (C) 2014, Nicky Dasmijn + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * The Phoenix Firestorm Project, Inc., 1831 Oakwood Drive, Fairmont, Minnesota 56031-3225 USA + * http://www.firestormviewer.org + * $/LicenseInfo$ + */ + +#include +#include "../llmath.h" +#include "ndoctreelog.h" + + +namespace nd +{ + namespace octree + { + namespace debug + { + U32 gOctreeDebug; + std::ofstream *pLogStream; + std::string mOctreeLogFilename; + + void setOctreeLogFilename( std::string const &aFilename ) + { + mOctreeLogFilename = aFilename; + } + + void doOctreeLog( std::string const &aStr ) + { + if( pLogStream ) + { + *pLogStream << aStr; + pLogStream->flush(); + } + } + + void checkOctreeLog() + { + if( !pLogStream && mOctreeLogFilename.size() ) + { + pLogStream = new std::ofstream(); + pLogStream->open( mOctreeLogFilename.c_str(), std::ios::out ); + if( pLogStream->is_open() ) + { + time_t curTime; + time(&curTime); + tm *curTimeUTC = gmtime( &curTime ); + + *pLogStream << "Starting octree log" << asctime( curTimeUTC ) << std::endl; + pLogStream->flush(); + } + else + delete pLogStream; + } + } + } + } +} + diff --git a/indra/llmath/nd/ndoctreelog.h b/indra/llmath/nd/ndoctreelog.h new file mode 100644 index 0000000000..3b35c9b2f7 --- /dev/null +++ b/indra/llmath/nd/ndoctreelog.h @@ -0,0 +1,54 @@ +/** + * $LicenseInfo:firstyear=2014&license=fsviewerlgpl$ + * Phoenix Firestorm Viewer Source Code + * Copyright (C) 2014, Nicky Dasmijn + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * The Phoenix Firestorm Project, Inc., 1831 Oakwood Drive, Fairmont, Minnesota 56031-3225 USA + * http://www.firestormviewer.org + * $/LicenseInfo$ + */ + +#ifndef NDOCTREELOG_H_ +#define NDOCTREELOG_H_ + +#include "stdtypes.h" +#include + +namespace nd +{ + namespace octree + { + namespace debug + { + extern U32 gOctreeDebug; + void doOctreeLog( std::string const &aStr ); + void checkOctreeLog(); + void setOctreeLogFilename( std::string const & ); + } + } +} + +#define ND_OCTREE_LOG { if( nd::octree::debug::gOctreeDebug ){ nd::octree::debug::checkOctreeLog(); std::stringstream strm; strm << std::setprecision(10) +#define ND_OCTREE_LOG_END std::endl; nd::octree::debug::doOctreeLog( strm.str() ); } } + +inline std::ostream& operator<<( std::ostream &strm, const LLVector4a &vc ) +{ + strm << "{" << vc[0] << "/" << vc[1] << "/" << vc[2] << "}"; + return strm; +} + +#endif diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index 7549ebee5f..5ce25ff8ae 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -22076,6 +22076,21 @@ Change of this parameter will affect the layout of buttons in notification toast 1 + + FSCreateOctreeLog + + Comment + Create a log of octree operation. This can cause huge frame stalls on edit + Persist + 0 + Type + Boolean + Value + 0 + Backup + 0 + + diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 5eca50fe65..567adb09d2 100755 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -263,6 +263,8 @@ #include "nd/ndmallocstats.h" // collect stats about memory allocations #include "nd/ndallocstats.h" // collect stats about memory allocations +#include "nd/ndoctreelog.h" // Octree operation logging. + #include "fsradar.h" @@ -834,6 +836,8 @@ bool LLAppViewer::init() nd::allocstats::startUp(); // start collecting alloc stats nd::mallocstats::startUp(); // start collecting alloc stats + nd::octree::debug::setOctreeLogFilename( gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "octree.log" ) ); // Filename to log octree options to. + // // Start of the application diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp index 98afa4ed28..d22d6ffa68 100755 --- a/indra/newview/llvovolume.cpp +++ b/indra/newview/llvovolume.cpp @@ -4146,7 +4146,19 @@ void LLRiggedVolume::update(const LLMeshSkinInfo* skin, LLVOAvatar* avatar, cons size.setSub(dst_face.mExtents[1], dst_face.mExtents[0]); size.splat(size.getLength3().getF32()*0.5f); + // Create a debug log for octree insertions if requested. + static LLCachedControl debugOctree(gSavedSettings,"FSCreateOctreeLog"); + bool _debugOT( debugOctree ); + if( _debugOT ) + nd::octree::debug::gOctreeDebug += 1; + // + dst_face.createOctree(1.f); + + // Reset octree log + if( _debugOT ) + nd::octree::debug::gOctreeDebug -= 1; + // } } }