FIRE-13814; Octree fixing.

- Do not create octree children that can cause precision problems.
- Error out when trying to put more than 8 children into a parent. That would just overwrite memory.
- Add logging for hte future.
Nicky 2014-05-27 14:46:02 +02:00
parent 1f37b1c487
commit b4e7faee77
8 changed files with 211 additions and 1 deletions

View File

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

View File

@ -32,6 +32,8 @@
#include "llvector4a.h"
#include <vector>
#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<T>* 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;
// <FS:ND> 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 )
// </FS:ND>
{
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<T>(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;

View File

@ -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<LLVolumeTriangle>(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()) { }

View File

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

View File

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

View File

@ -22076,6 +22076,21 @@ Change of this parameter will affect the layout of buttons in notification toast
<integer>1</integer>
</map>
<!-- <FS:Zi> Optionally disable the usage of timesteps - FIRE-3657 -->
<!-- <FS:ND> Create a debyg log for octree insert -->
<key>FSCreateOctreeLog</key>
<map>
<key>Comment</key>
<string>Create a log of octree operation. This can cause huge frame stalls on edit</string>
<key>Persist</key>
<integer>0</integer>
<key>Type</key>
<string>Boolean</string>
<key>Value</key>
<integer>0</integer>
<key>Backup</key>
<integer>0</integer>
</map>
<!-- <FS:ND/> -->
</map>
</llsd>

View File

@ -263,6 +263,8 @@
#include "nd/ndmallocstats.h" // <FS:ND/> collect stats about memory allocations
#include "nd/ndallocstats.h" // <FS:ND/> collect stats about memory allocations
#include "nd/ndoctreelog.h" // <FS:ND/> Octree operation logging.
#include "fsradar.h"
@ -834,6 +836,8 @@ bool LLAppViewer::init()
nd::allocstats::startUp(); // <FS:ND/> start collecting alloc stats
nd::mallocstats::startUp(); // <FS:ND/> start collecting alloc stats
nd::octree::debug::setOctreeLogFilename( gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "octree.log" ) ); // <FS:ND/> Filename to log octree options to.
//
// Start of the application

View File

@ -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);
// <FS:ND> Create a debug log for octree insertions if requested.
static LLCachedControl<bool> debugOctree(gSavedSettings,"FSCreateOctreeLog");
bool _debugOT( debugOctree );
if( _debugOT )
nd::octree::debug::gOctreeDebug += 1;
// </FS:ND>
dst_face.createOctree(1.f);
// <FS:ND> Reset octree log
if( _debugOT )
nd::octree::debug::gOctreeDebug -= 1;
// </FS:ND>
}
}
}