Skip to content

Commit

Permalink
reworked SceneCache to fix corruption reference to cached data (#2786)
Browse files Browse the repository at this point in the history
* reworked SceneCache to fix corruption reference to cached data

* reworked logic SceneCache
  • Loading branch information
ABSitf authored Jun 4, 2024
1 parent 331d84e commit a915986
Show file tree
Hide file tree
Showing 4 changed files with 50 additions and 115 deletions.
2 changes: 1 addition & 1 deletion source/MRViewer/MRRibbonSceneObjectsListDrawer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ void RibbonSceneObjectsListDrawer::drawSceneContextMenu_( const std::vector<std:
auto selectedMask = ribbonMenu_->calcSelectedTypesMask( selected );
ImGui::PushStyleVar( ImGuiStyleVar_CellPadding, ImGui::GetStyle().WindowPadding );
[[maybe_unused]] bool wasChanged = false, wasAction = false;
const auto selectedVisualObjs = SceneCache::getAllObjects<VisualObject, ObjectSelectivityType::Selected>();
const auto& selectedVisualObjs = SceneCache::getAllObjects<VisualObject, ObjectSelectivityType::Selected>();
if ( selectedVisualObjs.empty() )
{
wasChanged |= ribbonMenu_->drawGeneralOptions( selected );
Expand Down
46 changes: 1 addition & 45 deletions source/MRViewer/MRSceneCache.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,23 +9,7 @@ namespace MR

void SceneCache::invalidateAll()
{
instance_().allObjectDepths_.reset();
for ( auto& data : instance_().cachedData_ )
data.reset();
}

const std::vector<int>& SceneCache::getAllObjectsDepth()
{
const int templateParamsUniqueId = TypeMap::getId<Object, ObjectSelectivityType::Selectable>();
if ( templateParamsUniqueId + 1 > instance_().cachedData_.size() )
instance_().cachedData_.push_back( CachedStoredType() );
if ( !instance_().cachedData_[templateParamsUniqueId] )
{
auto data = updateAllObjectsWithDepth_();
instance_().cachedData_[templateParamsUniqueId] = std::move( data.first );
instance_().allObjectDepths_ = std::move( data.second );
}
return *instance_().allObjectDepths_;
instance_().cachedData_.clear();
}

MR::SceneCache& SceneCache::instance_()
Expand All @@ -34,32 +18,4 @@ MR::SceneCache& SceneCache::instance_()
return sceneCahce;
}

std::pair<SceneCache::StoredType, std::vector<int>> SceneCache::updateAllObjectsWithDepth_()
{
std::vector<int> vecDepth;
std::vector<std::shared_ptr<Object>> vecObjs;
std::function<void( std::shared_ptr<Object>, int )> checkFn;
checkFn = [&] ( std::shared_ptr<Object> obj, int depth )
{
if ( !obj || obj->isAncillary() )
return;
vecDepth.push_back( depth );
vecObjs.push_back( obj );
for ( const auto& child : obj->children() )
checkFn( child, depth + 1 );
};
for ( const auto& child : SceneRoot::get().children() )
checkFn( child, 0 );

return { std::move( vecObjs ), std::move( vecDepth ) };
}

//////////////////////////////////////////////////////////////////////////

MR::SceneCache::TypeMap& SceneCache::TypeMap::instance_()
{
static TypeMap instance;
return instance;
}

}
92 changes: 28 additions & 64 deletions source/MRViewer/MRSceneCache.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
#include "MRMesh/MRObjectsAccess.h"
#include "MRMesh/MRSceneRoot.h"
#include "exports.h"
#include <optional>
#include <unordered_map>

namespace MR
{
Expand All @@ -16,82 +16,46 @@ class MRVIEWER_CLASS SceneCache
// call it in the beginning each frame
MRVIEWER_API static void invalidateAll();

// same as getAllObjectsInTree<ObjectType>( &SceneRoot::get(), SelectivityType ) but use cached data
template <typename ObjectType>
using ObjectList = std::vector<std::shared_ptr<ObjectType>>;
// analog getAllObjectsInTree<ObjectType>( &SceneRoot::get(), SelectivityType ) but use cached data
// reference copy is valid until invalidateAll() is called
template <typename ObjectType, ObjectSelectivityType SelectivityType>
static const std::vector<std::shared_ptr<ObjectType>>& getAllObjects();
static const ObjectList<ObjectType>& getAllObjects();

// get all selectable object depths
// metadata for drawing scene objects list
MRVIEWER_API static const std::vector<int>& getAllObjectsDepth();
private:
MRVIEWER_API static SceneCache& instance_();
SceneCache() {};
SceneCache() = default;

using StoredType = std::vector<std::shared_ptr<Object>>;
using CachedStoredType = std::optional<StoredType>;
MRVIEWER_API static std::pair<StoredType, std::vector<int>> updateAllObjectsWithDepth_();

std::vector<CachedStoredType> cachedData_;
std::optional<std::vector<int>> allObjectDepths_;

// Helper class to convert template params to unique numbers
class MRVIEWER_CLASS TypeMap
struct BasicVectorHolder
{
public:
template <typename ObjectType, ObjectSelectivityType SelectivityType>
static int getId()
{
static int myId = instance_().idCounter_++;
return myId;
}

private:
MRVIEWER_API static TypeMap& instance_();

int idCounter_ = 0;
BasicVectorHolder() = default;
BasicVectorHolder( const BasicVectorHolder& ) = default;
BasicVectorHolder( BasicVectorHolder&& ) = default;
virtual ~BasicVectorHolder() = default;
};
template <typename ObjectType, ObjectSelectivityType SelectivityType>
struct VectorHolder : BasicVectorHolder
{
ObjectList<ObjectType> value;
};
std::unordered_map<std::type_index, std::shared_ptr<BasicVectorHolder>> cachedData_;
};

#ifdef __GNUC__
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wstrict-aliasing"
#endif
template <typename ObjectType, ObjectSelectivityType SelectivityType>
const std::vector<std::shared_ptr<ObjectType>>& SceneCache::getAllObjects()
const SceneCache::ObjectList<ObjectType>& SceneCache::getAllObjects()
{
using SpecificDataType = std::vector<std::shared_ptr<ObjectType>>;
const int templateParamsUniqueId = TypeMap::getId<ObjectType, SelectivityType>();
if ( templateParamsUniqueId + 1 > instance_().cachedData_.size() )
instance_().cachedData_.push_back( CachedStoredType() );
if ( !instance_().cachedData_[templateParamsUniqueId] )
using ResultType = VectorHolder<ObjectType, SelectivityType>;
const auto typeIndex = std::type_index( typeid( ResultType ) );
auto& cachedData = instance_().cachedData_;
if ( !cachedData.contains( typeIndex ) || !cachedData[typeIndex] )
{
std::optional<SpecificDataType> specificData = getAllObjectsInTree<ObjectType>( &SceneRoot::get(), SelectivityType );
std::optional<StoredType> storedData = *reinterpret_cast< std::optional<StoredType>* >( &specificData );
instance_().cachedData_[templateParamsUniqueId] = storedData;
ResultType newData;
newData.value = getAllObjectsInTree<ObjectType>( &SceneRoot::get(), SelectivityType );
std::shared_ptr<ResultType> newDataPtr = std::make_shared<ResultType>( std::move( newData ) );
cachedData[typeIndex] = std::dynamic_pointer_cast<BasicVectorHolder>( newDataPtr );
}
const SpecificDataType& resData = **reinterpret_cast< std::optional<SpecificDataType>* >( &instance_().cachedData_[templateParamsUniqueId] );
return resData;
return std::dynamic_pointer_cast< ResultType >( cachedData[typeIndex] )->value;
}
#ifdef __GNUC__
#pragma GCC diagnostic pop
#endif

// specialization getAllObjects to getAllObjects<Object, ObjectSelectivityType::Selectable>
// also calc allObjectDepths_
template <>
inline const std::vector<std::shared_ptr<Object>>& SceneCache::getAllObjects<Object, ObjectSelectivityType::Selectable>()
{
const int templateParamsUniqueId = TypeMap::getId<Object, ObjectSelectivityType::Selectable>();
if ( templateParamsUniqueId + 1 > instance_().cachedData_.size() )
instance_().cachedData_.push_back( CachedStoredType() );
if ( !instance_().cachedData_[templateParamsUniqueId] )
{
auto data = updateAllObjectsWithDepth_();
instance_().cachedData_[templateParamsUniqueId] = std::move( data.first );
instance_().allObjectDepths_ = std::move( data.second );
}
return *instance_().cachedData_[templateParamsUniqueId];
}


}
25 changes: 20 additions & 5 deletions source/MRViewer/MRSceneObjectsListDrawer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,22 @@ void SceneObjectsListDrawer::allowSceneReorder( bool allow )
void SceneObjectsListDrawer::drawObjectsList_()
{
const auto& all = SceneCache::getAllObjects<Object, ObjectSelectivityType::Selectable>();
const auto& depth = SceneCache::getAllObjectsDepth();
std::vector<int> depths( all.size(), -1 );
auto getDepth = [&] ( int i )
{
if ( depths[i] == -1 )
{
const Object* obj = all[i].get();
int depth = 0;
while ( obj->parent() && obj->parent() != SceneRoot::getSharedPtr().get() )
{
obj = obj->parent();
++depth;
}
depths[i] = depth;
}
return depths[i];
};

int curentDepth = 0;
std::stack<std::shared_ptr<Object>> objDepthStack;
Expand Down Expand Up @@ -201,11 +216,11 @@ void SceneObjectsListDrawer::drawObjectsList_()
for ( int i = 0; i < all.size(); ++i )
{
const bool isLast = i == int( all.size() ) - 1;
const int nextDepth = isLast ? 0 : depth[i + 1];
const int nextDepth = isLast ? 0 : getDepth( i + 1 );
// skip child elements after collapsed header
if ( collapsedHeaderDepth >= 0 )
{
if ( depth[i] > collapsedHeaderDepth )
if ( getDepth( i ) > collapsedHeaderDepth)
{
if ( curentDepth > nextDepth )
{
Expand All @@ -224,13 +239,13 @@ void SceneObjectsListDrawer::drawObjectsList_()
}

auto& object = *all[i];
if ( curentDepth < depth[i] )
if ( curentDepth < getDepth( i ) )
{
ImGui::Indent();
if ( i > 0 )
objDepthStack.push( all[i - 1] );
++curentDepth;
assert( curentDepth == depth[i] );
assert( curentDepth == getDepth( i ) );
}

{
Expand Down

0 comments on commit a915986

Please sign in to comment.