Remove _tilesStillNotUnloadedCount, rename _doNotUnloadCount, review comments

This commit is contained in:
Ashley Rogers 2025-02-24 15:30:27 -05:00
parent 598f49f92e
commit 81e5311e05
5 changed files with 103 additions and 125 deletions

View File

@ -25,8 +25,9 @@
namespace Cesium3DTilesSelection {
class TilesetContentLoader;
#define CESIUM_DEBUG_TILE_UNLOADING 1
#ifdef CESIUM_DEBUG_TILE_UNLOADING
class TileDoNotUnloadCountTracker {
class TileDoNotUnloadSubtreeCountTracker {
private:
struct Entry {
std::string reason;
@ -523,7 +524,7 @@ public:
* This function is not supposed to be called by clients.
*/
int32_t getDoNotUnloadCount() const noexcept {
return this->_doNotUnloadCount;
return this->_doNotUnloadSubtreeCount;
}
/**
@ -532,7 +533,7 @@ public:
*
* This function is not supposed to be called by clients.
*/
void incrementDoNotUnloadCount(const char* reason) noexcept;
void incrementDoNotUnloadSubtreeCount(const char* reason) noexcept;
/**
* @brief Decrements the internal count denoting that the tile and its
@ -540,39 +541,28 @@ public:
*
* This function is not supposed to be called by clients.
*/
void decrementDoNotUnloadCount(const char* reason) noexcept;
void decrementDoNotUnloadSubtreeCount(const char* reason) noexcept;
/**
* @brief Marks this tile as having content that has not yet been unloaded,
* preventing a parent external tileset from cleaning up. This count will be
* propagated to any ancestors.
* @brief Increments the internal count denoting that the tile and its
* ancestors should not be unloaded starting with this tile's parent.
*
* This function is not supposed to be called by clients.
*/
void incrementTilesStillNotUnloadedCount() noexcept;
void incrementDoNotUnloadSubtreeCountOnParent(const char* reason) noexcept;
/**
* @brief Unmarks this tile as having content that has not yet been unloaded,
* allowing a parent external tileset to clean up. This count will be
* propagated to any ancestors.
* @brief Decrements the internal count denoting that the tile and its
* ancestors should not be unloaded starting with this tile's parent.
*
* This function is not supposed to be called by clients.
*/
void decrementTilesStillNotUnloadedCount() noexcept;
/**
* @brief Obtains the number of tiles at or below this tile (that is, the tile
* itself and its children) that still have content that has not yet been
* unloaded, preventing a parent external tileset from cleaning up.
*/
int32_t getTilesStillNotUnloadedCount() const noexcept {
return this->_tilesStillNotUnloadedCount;
}
void decrementDoNotUnloadSubtreeCountOnParent(const char* reason) noexcept;
private:
void incrementDoNotUnloadCount(const std::string& reason) noexcept;
void incrementDoNotUnloadSubtreeCount(const std::string& reason) noexcept;
void decrementDoNotUnloadCount(const std::string& reason) noexcept;
void decrementDoNotUnloadSubtreeCount(const std::string& reason) noexcept;
struct TileConstructorImpl {};
template <
@ -638,9 +628,7 @@ private:
// Number of existing claims on this tile preventing it and its parent
// external tileset (if any) from being unloaded from the tree.
int32_t _doNotUnloadCount = 0;
int32_t _tilesStillNotUnloadedCount = 0;
int32_t _doNotUnloadSubtreeCount = 0;
friend class TilesetContentManager;
friend class MockTilesetContentManagerTestFixture;

View File

@ -27,22 +27,25 @@ using namespace std::string_literals;
namespace Cesium3DTilesSelection {
#ifdef CESIUM_DEBUG_TILE_UNLOADING
std::unordered_map<std::string, std::vector<TileDoNotUnloadCountTracker::Entry>>
TileDoNotUnloadCountTracker::_entries;
std::unordered_map<
std::string,
std::vector<TileDoNotUnloadSubtreeCountTracker::Entry>>
TileDoNotUnloadSubtreeCountTracker::_entries;
void TileDoNotUnloadCountTracker::addEntry(
void TileDoNotUnloadSubtreeCountTracker::addEntry(
uint64_t id,
bool increment,
const std::string& reason,
int32_t newCount) {
const std::string idString = fmt::format("{:x}", id);
const auto foundIt = TileDoNotUnloadCountTracker::_entries.find(idString);
if (foundIt != TileDoNotUnloadCountTracker::_entries.end()) {
const auto foundIt =
TileDoNotUnloadSubtreeCountTracker::_entries.find(idString);
if (foundIt != TileDoNotUnloadSubtreeCountTracker::_entries.end()) {
foundIt->second.push_back(Entry{reason, increment, newCount});
} else {
std::vector<Entry> entries{Entry{reason, increment, newCount}};
TileDoNotUnloadCountTracker::_entries.insert(
TileDoNotUnloadSubtreeCountTracker::_entries.insert(
{idString, std::move(entries)});
}
}
@ -92,7 +95,7 @@ Tile::Tile(
_mightHaveLatentChildren{true} {
if (_loadState != TileLoadState::Unloaded && !_content.isUnknownContent() &&
!_content.isEmptyContent()) {
incrementTilesStillNotUnloadedCount();
incrementDoNotUnloadSubtreeCountOnParent("Tile constructor");
}
}
@ -111,8 +114,7 @@ Tile::Tile(Tile&& rhs) noexcept
_content(std::move(rhs._content)),
_pLoader{rhs._pLoader},
_loadState{rhs._loadState},
_mightHaveLatentChildren{rhs._mightHaveLatentChildren},
_tilesStillNotUnloadedCount{rhs._tilesStillNotUnloadedCount} {
_mightHaveLatentChildren{rhs._mightHaveLatentChildren} {
// since children of rhs will have the parent pointed to rhs,
// we will reparent them to this tile as rhs will be destroyed after this
for (Tile& tile : this->_children) {
@ -144,11 +146,10 @@ Tile& Tile::operator=(Tile&& rhs) noexcept {
this->_pLoader = rhs._pLoader;
this->_loadState = rhs._loadState;
this->_mightHaveLatentChildren = rhs._mightHaveLatentChildren;
this->_tilesStillNotUnloadedCount = rhs._tilesStillNotUnloadedCount;
// We deliberately do *not* copy the _doNotUnloadCount of rhs here.
// This is because the _doNotUnloadCount is a count of instances of the
// *pointer* to the tile, denoting the number of active pointers that would
// be invalidated if the Tile were to be deleted. Because the memory
// We deliberately do *not* copy the _doNotUnloadSubtreeCount of rhs here.
// This is because the _doNotUnloadSubtreeCount is a count of instances of
// the *pointer* to the tile, denoting the number of active pointers that
// would be invalidated if the Tile were to be deleted. Because the memory
// location of the tile will have changed as a result of the move operation,
// the new Tile object will not have any pointers referencing it, so copying
// over the count would be incorrect and could result in a Tile not being
@ -163,19 +164,9 @@ void Tile::createChildTiles(std::vector<Tile>&& children) {
throw std::runtime_error("Children already created.");
}
int32_t prevLoadedContentsCount = this->_tilesStillNotUnloadedCount;
this->_children = std::move(children);
for (Tile& tile : this->_children) {
tile.setParent(this);
this->_tilesStillNotUnloadedCount += tile._tilesStillNotUnloadedCount;
}
// Propagate new loaded contents count up the chain
Tile* pParent = this->_pParent;
while (pParent != nullptr) {
pParent->_tilesStillNotUnloadedCount -= prevLoadedContentsCount;
pParent->_tilesStillNotUnloadedCount += this->_tilesStillNotUnloadedCount;
pParent = pParent->_pParent;
}
}
@ -295,80 +286,80 @@ void Tile::setMightHaveLatentChildren(bool mightHaveLatentChildren) noexcept {
}
void Tile::clearChildren() noexcept {
CESIUM_ASSERT(this->_doNotUnloadCount == 0);
CESIUM_ASSERT(this->_doNotUnloadSubtreeCount == 0);
this->_children.clear();
}
void Tile::incrementDoNotUnloadCount(
void Tile::incrementDoNotUnloadSubtreeCount(
[[maybe_unused]] const char* reason) noexcept {
#ifdef CESIUM_DEBUG_TILE_UNLOADING
const std::string reasonStr = fmt::format(
"Initiator ID: {:x}, {}",
reinterpret_cast<uint64_t>(this),
reason);
this->incrementDoNotUnloadCount(reasonStr);
this->incrementDoNotUnloadSubtreeCount(reasonStr);
#else
this->incrementDoNotUnloadCount(std::string());
this->incrementDoNotUnloadSubtreeCount(std::string());
#endif
}
void Tile::decrementDoNotUnloadCount(
void Tile::decrementDoNotUnloadSubtreeCount(
[[maybe_unused]] const char* reason) noexcept {
#ifdef CESIUM_DEBUG_TILE_UNLOADING
const std::string reasonStr = fmt::format(
"Initiator ID: {:x}, {}",
reinterpret_cast<uint64_t>(this),
reason);
this->decrementDoNotUnloadCount(reasonStr);
this->decrementDoNotUnloadSubtreeCount(reasonStr);
#else
this->decrementDoNotUnloadCount(std::string());
this->decrementDoNotUnloadSubtreeCount(std::string());
#endif
}
void Tile::incrementDoNotUnloadCount(
void Tile::incrementDoNotUnloadSubtreeCountOnParent(
const char* reason) noexcept {
if (this->getParent() != nullptr) {
this->getParent()->incrementDoNotUnloadSubtreeCount(reason);
}
}
void Tile::decrementDoNotUnloadSubtreeCountOnParent(
const char* reason) noexcept {
if (this->getParent() != nullptr) {
this->getParent()->decrementDoNotUnloadSubtreeCount(reason);
}
}
void Tile::incrementDoNotUnloadSubtreeCount(
[[maybe_unused]] const std::string& reason) noexcept {
++this->_doNotUnloadCount;
Tile* pTile = this;
while (pTile != nullptr) {
++pTile->_doNotUnloadSubtreeCount;
#ifdef CESIUM_DEBUG_TILE_UNLOADING
TileDoNotUnloadCountTracker::addEntry(
reinterpret_cast<uint64_t>(this),
true,
std::string(reason),
this->_doNotUnloadCount);
TileDoNotUnloadSubtreeCountTracker::addEntry(
reinterpret_cast<uint64_t>(pTile),
true,
std::string(reason),
pTile->_doNotUnloadSubtreeCount);
#endif
if (this->getParent() != nullptr) {
this->getParent()->incrementDoNotUnloadCount(reason);
pTile = pTile->getParent();
}
}
void Tile::decrementDoNotUnloadCount(
void Tile::decrementDoNotUnloadSubtreeCount(
[[maybe_unused]] const std::string& reason) noexcept {
CESIUM_ASSERT(this->_doNotUnloadCount > 0);
--this->_doNotUnloadCount;
CESIUM_ASSERT(this->_doNotUnloadSubtreeCount > 0);
Tile* pTile = this;
while (pTile != nullptr) {
--pTile->_doNotUnloadSubtreeCount;
#ifdef CESIUM_DEBUG_TILE_UNLOADING
TileDoNotUnloadCountTracker::addEntry(
reinterpret_cast<uint64_t>(this),
false,
std::string(reason),
this->_doNotUnloadCount);
TileDoNotUnloadSubtreeCountTracker::addEntry(
reinterpret_cast<uint64_t>(pTile),
false,
std::string(reason),
pTile->_doNotUnloadSubtreeCount);
#endif
if (this->getParent() != nullptr) {
this->getParent()->decrementDoNotUnloadCount(reason);
}
}
void Tile::incrementTilesStillNotUnloadedCount() noexcept {
CESIUM_ASSERT(this->_tilesStillNotUnloadedCount >= 0);
this->_tilesStillNotUnloadedCount++;
if (this->getParent() != nullptr) {
this->getParent()->incrementTilesStillNotUnloadedCount();
}
}
void Tile::decrementTilesStillNotUnloadedCount() noexcept {
CESIUM_ASSERT(this->_tilesStillNotUnloadedCount > 0);
--this->_tilesStillNotUnloadedCount;
if (this->getParent() != nullptr) {
this->getParent()->decrementTilesStillNotUnloadedCount();
pTile = pTile->getParent();
}
}

View File

@ -252,7 +252,7 @@ void Tileset::_updateLodTransitions(
// This tile is done fading out and was immediately kicked from the
// cache.
tileIt = result.tilesFadingOut.erase(tileIt);
(*tileIt)->decrementDoNotUnloadCount(
(*tileIt)->decrementDoNotUnloadSubtreeCount(
"Tileset::_updateLodTransitions done fading out");
continue;
}
@ -265,7 +265,7 @@ void Tileset::_updateLodTransitions(
// This tile will already be on the render list.
pRenderContent->setLodTransitionFadePercentage(0.0f);
tileIt = result.tilesFadingOut.erase(tileIt);
(*tileIt)->decrementDoNotUnloadCount(
(*tileIt)->decrementDoNotUnloadSubtreeCount(
"Tileset::_updateLodTransitions in render list");
continue;
}
@ -278,7 +278,7 @@ void Tileset::_updateLodTransitions(
// last frame.
pRenderContent->setLodTransitionFadePercentage(0.0f);
tileIt = result.tilesFadingOut.erase(tileIt);
(*tileIt)->decrementDoNotUnloadCount(
(*tileIt)->decrementDoNotUnloadSubtreeCount(
"Tileset::_updateLodTransitions done fading out");
continue;
}
@ -330,7 +330,7 @@ Tileset::updateViewOffline(const std::vector<ViewState>& frustums) {
}
for (Tile* pTile : this->_updateResult.tilesFadingOut) {
pTile->decrementDoNotUnloadCount(
pTile->decrementDoNotUnloadSubtreeCount(
"Tileset::updateViewOffline clear tilesFadingOut");
}
@ -346,7 +346,7 @@ Tileset::updateViewOffline(const std::vector<ViewState>& frustums) {
if (pRenderContent) {
pRenderContent->setLodTransitionFadePercentage(1.0f);
this->_updateResult.tilesFadingOut.insert(tile);
tile->incrementDoNotUnloadCount(
tile->incrementDoNotUnloadSubtreeCount(
"Tileset::updateViewOffline start fading out");
}
}
@ -382,7 +382,7 @@ Tileset::updateView(const std::vector<ViewState>& frustums, float deltaTime) {
if (!_options.enableLodTransitionPeriod) {
for (Tile* pTile : this->_updateResult.tilesFadingOut) {
pTile->decrementDoNotUnloadCount(
pTile->decrementDoNotUnloadSubtreeCount(
"Tileset::updateView clear tilesFadingOut");
}
result.tilesFadingOut.clear();
@ -647,7 +647,7 @@ void markTileNonRendered(
(lastResult == TileSelectionState::Result::Refined &&
tile.getRefine() == TileRefine::Add)) {
result.tilesFadingOut.insert(&tile);
tile.incrementDoNotUnloadCount("markTileNonRendered fading out");
tile.incrementDoNotUnloadSubtreeCount("markTileNonRendered fading out");
TileRenderContent* pRenderContent = tile.getContent().getRenderContent();
if (pRenderContent) {
pRenderContent->setLodTransitionFadePercentage(0.0f);
@ -1650,7 +1650,6 @@ void Tileset::_clearChildrenRecursively(Tile* pTile) noexcept {
}
CESIUM_ASSERT(child.getState() == TileLoadState::Unloaded);
CESIUM_ASSERT(child.getDoNotUnloadCount() == 0);
CESIUM_ASSERT(child.getTilesStillNotUnloadedCount() == 0);
CESIUM_ASSERT(child.getContent().isUnknownContent());
this->_loadedTiles.remove(child);
_clearChildrenRecursively(&child);
@ -1714,12 +1713,8 @@ void Tileset::_unloadCachedTiles(double timeBudget) noexcept {
}
if (!tilesNeedingChildrenCleared.empty()) {
// Because we iterated over the tiles list backwards, the
// `tilesNeedingChildrenCleared` vector is in order from bottom to top of
// the tree.
for (Tile* pTileToClear : tilesNeedingChildrenCleared) {
CESIUM_ASSERT(pTileToClear->getDoNotUnloadCount() == 0);
CESIUM_ASSERT(pTileToClear->getTilesStillNotUnloadedCount() == 0);
_clearChildrenRecursively(pTileToClear);
}
}

View File

@ -1037,7 +1037,7 @@ void TilesetContentManager::loadTileContent(
}
}
tile.incrementDoNotUnloadCount(
tile.incrementDoNotUnloadSubtreeCount(
"TilesetContentManager::loadTileContent begin");
// map raster overlay to tile
@ -1111,14 +1111,14 @@ void TilesetContentManager::loadTileContent(
})
.thenInMainThread([&tile, thiz](TileLoadResultAndRenderResources&& pair) {
setTileContent(tile, std::move(pair.result), pair.pRenderResources);
tile.decrementDoNotUnloadCount(
tile.decrementDoNotUnloadSubtreeCount(
"TilesetContentManager::loadTileContent done loading");
thiz->notifyTileDoneLoading(&tile);
})
.catchInMainThread([pLogger = this->_externals.pLogger, &tile, thiz](
std::exception&& e) {
tile.decrementDoNotUnloadCount(
tile.decrementDoNotUnloadSubtreeCount(
"TilesetContentManager::loadTileContent error while loading");
thiz->notifyTileDoneLoading(&tile);
SPDLOG_LOGGER_ERROR(
@ -1218,15 +1218,15 @@ UnloadTileContentResult TilesetContentManager::unloadTileContent(Tile& tile) {
// Tile with external content that still has references to its pointer or to
// its children's pointers - we can't unload.
// We also, of course, don't want to unload the root tile.
if (tile.getParent() == nullptr || tile.getDoNotUnloadCount() > 0 ||
tile.getTilesStillNotUnloadedCount() > 1) {
if (tile.getParent() == nullptr || tile.getDoNotUnloadCount() > 0) {
return UnloadTileContentResult::Keep;
}
notifyTileUnloading(&tile);
content.setContentKind(TileUnknownContent{});
tile.setState(TileLoadState::Unloaded);
tile.decrementTilesStillNotUnloadedCount();
tile.decrementDoNotUnloadSubtreeCountOnParent(
"TilesetContentManager::unloadTileContent unload external content");
return UnloadTileContentResult::RemoveAndClearChildren;
}
@ -1268,7 +1268,8 @@ UnloadTileContentResult TilesetContentManager::unloadTileContent(Tile& tile) {
// If we make it this far, the tile's content will be fully unloaded.
notifyTileUnloading(&tile);
if (!content.isUnknownContent()) {
tile.decrementTilesStillNotUnloadedCount();
tile.decrementDoNotUnloadSubtreeCountOnParent(
"TilesetContentManager::unloadTileContent unload render content");
}
content.setContentKind(TileUnknownContent{});
tile.setState(TileLoadState::Unloaded);
@ -1457,7 +1458,8 @@ void TilesetContentManager::setTileContent(
if (!tile.getContent().isUnknownContent() &&
!tile.getContent().isEmptyContent()) {
tile.incrementTilesStillNotUnloadedCount();
tile.incrementDoNotUnloadSubtreeCountOnParent(
"TilesetContentManager::setTileContent");
}
if (result.tileInitializer) {

View File

@ -111,18 +111,20 @@ TilesetHeightQuery::TilesetHeightQuery(
Cesium3DTilesSelection::TilesetHeightQuery::~TilesetHeightQuery() {
for (Tile* pTile : candidateTiles) {
pTile->decrementDoNotUnloadCount(
pTile->decrementDoNotUnloadSubtreeCount(
"TilesetHeightQuery::~TilesetHeightQuery destructing candidateTiles");
}
for (Tile* pTile : additiveCandidateTiles) {
pTile->decrementDoNotUnloadCount("TilesetHeightQuery::~TilesetHeightQuery "
"destructing additiveCandidateTiles");
pTile->decrementDoNotUnloadSubtreeCount(
"TilesetHeightQuery::~TilesetHeightQuery "
"destructing additiveCandidateTiles");
}
for (Tile* pTile : previousCandidateTiles) {
pTile->decrementDoNotUnloadCount("TilesetHeightQuery::~TilesetHeightQuery "
"destructing previousCandidateTiles");
pTile->decrementDoNotUnloadSubtreeCount(
"TilesetHeightQuery::~TilesetHeightQuery "
"destructing previousCandidateTiles");
}
}
@ -199,12 +201,12 @@ void TilesetHeightQuery::findCandidateTiles(
this->ray,
this->inputPosition,
this->ellipsoid)) {
pTile->incrementDoNotUnloadCount(
pTile->incrementDoNotUnloadSubtreeCount(
"TilesetHeightQuery::findCandidateTiles add to candidateTiles");
this->candidateTiles.push_back(pTile);
}
} else {
pTile->incrementDoNotUnloadCount(
pTile->incrementDoNotUnloadSubtreeCount(
"TilesetHeightQuery::findCandidateTiles add to candidateTiles");
this->candidateTiles.push_back(pTile);
}
@ -220,13 +222,13 @@ void TilesetHeightQuery::findCandidateTiles(
this->ray,
this->inputPosition,
this->ellipsoid)) {
pTile->incrementDoNotUnloadCount(
pTile->incrementDoNotUnloadSubtreeCount(
"TilesetHeightQuery::findCandidateTiles add to "
"additiveCandidateTiles");
this->additiveCandidateTiles.push_back(pTile);
}
} else {
pTile->incrementDoNotUnloadCount(
pTile->incrementDoNotUnloadSubtreeCount(
"TilesetHeightQuery::findCandidateTiles add to "
"additiveCandidateTiles");
this->additiveCandidateTiles.push_back(pTile);
@ -281,7 +283,7 @@ void TilesetHeightQuery::findCandidateTiles(
// Decrement doNotUnloadCount for tiles currently in the queue, as the queue
// will be overwritten after this.
for (Tile* pTile : heightQueryLoadQueue) {
pTile->decrementDoNotUnloadCount(
pTile->decrementDoNotUnloadSubtreeCount(
"TilesetHeightRequest::processHeightRequests clear from "
"heightQueryLoadQueue");
}
@ -290,7 +292,7 @@ void TilesetHeightQuery::findCandidateTiles(
// Track the pointers in the load queue in doNotUnloadCount
for (Tile* pTile : heightQueryLoadQueue) {
pTile->incrementDoNotUnloadCount(
pTile->incrementDoNotUnloadSubtreeCount(
"TilesetHeightRequest::processHeightRequests assign to "
"heightQueryLoadQueue");
}
@ -362,7 +364,7 @@ bool TilesetHeightRequest::tryCompleteHeightRequest(
std::swap(query.candidateTiles, query.previousCandidateTiles);
for (Tile* pTile : query.candidateTiles) {
pTile->decrementDoNotUnloadCount(
pTile->decrementDoNotUnloadSubtreeCount(
"TilesetHeightRequest::tryCompleteHeightRequest clear "
"candidateTiles");
}
@ -379,7 +381,7 @@ bool TilesetHeightRequest::tryCompleteHeightRequest(
markTileVisited(loadedTiles, pCandidate);
// Check again next frame to see if this tile has children.
pCandidate->incrementDoNotUnloadCount(
pCandidate->incrementDoNotUnloadSubtreeCount(
"TilesetHeightRequest::tryCompleteHeightRequest add to "
"candidateTiles");
query.candidateTiles.emplace_back(pCandidate);