Skip to content

Commit 1dbfd68

Browse files
committed
Reapply modification to all loaded tiles.
1 parent 20fe18b commit 1dbfd68

File tree

5 files changed

+106
-107
lines changed

5 files changed

+106
-107
lines changed

Cesium3DTilesSelection/include/Cesium3DTilesSelection/GltfModifier.h

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,35 @@ class GltfModifier {
124124
const TilesetMetadata& tilesetMetadata,
125125
const Tile& rootTile);
126126

127+
/**
128+
* @brief Called by {@link Tileset} when the given tile leaves the
129+
* {@link TileLoadState::ContentLoading} state but it was loaded with an
130+
* older {@link GltfModifier} version. The tile will be queued for a call
131+
* to {@link GltfModifier::apply} in a worker thread.
132+
*
133+
* This method is called from the main thread.
134+
*
135+
* @private
136+
*
137+
* @param tile The tile that has just left the
138+
* {@link TileLoadState::ContentLoading} state.
139+
*/
140+
void onOldVersionContentLoadingComplete(const Tile& tile);
141+
142+
/**
143+
* @brief Called by {@link Tileset} when the {@link GltfModifier::apply}
144+
* method has finished running on a previously-loaded tile. The tile will be
145+
* queued to finish its loading in the main thread.
146+
*
147+
* This method is called from the main thread.
148+
*
149+
* @private
150+
*
151+
* @param tile The tile that has just been processed by the
152+
* {@link GltfModifier::apply} method.
153+
*/
154+
void onWorkerThreadApplyComplete(const Tile& tile);
155+
127156
protected:
128157
GltfModifier();
129158
virtual ~GltfModifier();

Cesium3DTilesSelection/src/GltfModifier.cpp

Lines changed: 43 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,10 @@ class GltfModifier::NewVersionLoadRequester : public TileLoadRequester {
1717

1818
void notifyOfTrigger();
1919

20-
private:
21-
void addTilesToQueues();
22-
23-
GltfModifier* _pModifier;
24-
const Tile* _pRootTile;
25-
std::vector<Tile::ConstPointer> _workerThreadQueue;
26-
std::vector<Tile::ConstPointer> _mainThreadQueue;
27-
bool _running;
20+
GltfModifier* pModifier;
21+
const Tile* pRootTile;
22+
std::vector<Tile::ConstPointer> workerThreadQueue;
23+
std::vector<Tile::ConstPointer> mainThreadQueue;
2824
};
2925

3026
GltfModifier::GltfModifier()
@@ -48,6 +44,7 @@ CesiumAsync::Future<void> GltfModifier::onRegister(
4844
TilesetContentManager& contentManager,
4945
const TilesetMetadata& tilesetMetadata,
5046
const Tile& rootTile) {
47+
this->_pNewVersionLoadRequester->pRootTile = &rootTile;
5148
contentManager.registerTileRequester(*this->_pNewVersionLoadRequester);
5249

5350
const TilesetExternals& externals = contentManager.getExternals();
@@ -68,111 +65,68 @@ CesiumAsync::Future<void> GltfModifier::onRegister(
6865
return asyncSystem.createResolvedFuture();
6966
}
7067

71-
GltfModifier::NewVersionLoadRequester::NewVersionLoadRequester(
72-
GltfModifier* pModifier)
73-
: _pModifier(pModifier),
74-
_pRootTile(nullptr),
75-
_workerThreadQueue(),
76-
_mainThreadQueue(),
77-
_running(false) {}
68+
void GltfModifier::onOldVersionContentLoadingComplete(const Tile& tile) {
69+
CESIUM_ASSERT(
70+
tile.getState() == TileLoadState::ContentLoaded ||
71+
tile.getState() == TileLoadState::Failed ||
72+
tile.getState() == TileLoadState::FailedTemporarily);
73+
if (tile.getState() == TileLoadState::ContentLoaded) {
74+
// Tile just transitioned from ContentLoading -> ContentLoaded, but it did
75+
// so based on the load version. Add it to the worker thread queue in order
76+
// to re-run the GltfModifier on it.
77+
this->_pNewVersionLoadRequester->workerThreadQueue.emplace_back(&tile);
78+
}
79+
}
7880

79-
void GltfModifier::NewVersionLoadRequester::notifyOfTrigger() {
80-
this->_running = true;
81-
this->addTilesToQueues();
81+
void GltfModifier::onWorkerThreadApplyComplete(const Tile& tile) {
82+
// GltfModifier::apply just finished, so now we need to do the main-thread
83+
// processing of the new version.
84+
this->_pNewVersionLoadRequester->mainThreadQueue.emplace_back(&tile);
8285
}
8386

84-
void GltfModifier::NewVersionLoadRequester::addTilesToQueues() {
85-
CESIUM_ASSERT(this->_pRootTile != nullptr);
86-
LoadedConstTileEnumerator enumerator(this->_pRootTile);
87+
GltfModifier::NewVersionLoadRequester::NewVersionLoadRequester(
88+
GltfModifier* pModifier_)
89+
: pModifier(pModifier_),
90+
pRootTile(nullptr),
91+
workerThreadQueue(),
92+
mainThreadQueue() {}
93+
94+
void GltfModifier::NewVersionLoadRequester::notifyOfTrigger() {
95+
// Add all already-loaded tiles to this requester worker thread load queue.
96+
// Tiles that are in ContentLoading will be added to this queue when they
97+
// finish.
98+
LoadedConstTileEnumerator enumerator(this->pRootTile);
8799
for (const Tile& tile : enumerator) {
88100
TileLoadState state = tile.getState();
89-
90-
// Tiles that are already being loaded will need to finish loading, _then_
91-
// we'll have to apply the modification. Always add them to the queue.
92-
if (state == TileLoadState::ContentLoading) {
93-
this->_workerThreadQueue.emplace_back(&tile);
94-
}
95-
96-
// Tiles that are already loaded only need to be added to the queue if they
97-
// have a glTF and it is the wrong version.
98-
if (state != TileLoadState::ContentLoaded && state != TileLoadState::Done)
99-
continue;
100-
101-
const TileRenderContent* pRenderContent =
102-
tile.getContent().getRenderContent();
103-
if (!pRenderContent)
104-
continue;
105-
106-
if (pRenderContent->getModel().version ==
107-
this->_pModifier->getCurrentVersion()) {
108-
CESIUM_ASSERT(!pRenderContent->getModifiedModel());
109-
continue;
110-
}
111-
112-
if (pRenderContent->getModifiedModel() &&
113-
pRenderContent->getModifiedModel()->version ==
114-
this->_pModifier->getCurrentVersion()) {
115-
// Worker thread GltfModifier::apply done, need to do main thread loading.
116-
this->_mainThreadQueue.emplace_back(&tile);
117-
} else {
118-
this->_workerThreadQueue.emplace_back(&tile);
101+
if (state == TileLoadState::ContentLoaded || state == TileLoadState::Done) {
102+
this->workerThreadQueue.emplace_back(&tile);
119103
}
120104
}
121105
}
122106

123107
bool GltfModifier::NewVersionLoadRequester::hasMoreTilesToLoadInWorkerThread()
124108
const {
125-
return !this->_workerThreadQueue.empty();
109+
return !this->workerThreadQueue.empty();
126110
}
127111

128112
const Tile*
129113
GltfModifier::NewVersionLoadRequester::getNextTileToLoadInWorkerThread() {
130-
if (!this->_running) {
131-
CESIUM_ASSERT(this->_workerThreadQueue.empty());
132-
return nullptr;
133-
}
134-
135-
CESIUM_ASSERT(!this->_workerThreadQueue.empty());
136-
const Tile* pResult = this->_workerThreadQueue.back().get();
137-
this->_workerThreadQueue.pop_back();
138-
139-
if (this->_workerThreadQueue.empty()) {
140-
this->addTilesToQueues();
141-
142-
// If both queues are still empty, we're done.
143-
if (this->_workerThreadQueue.empty() && this->_mainThreadQueue.empty()) {
144-
this->_running = false;
145-
}
146-
}
147-
114+
CESIUM_ASSERT(!this->workerThreadQueue.empty());
115+
const Tile* pResult = this->workerThreadQueue.back().get();
116+
this->workerThreadQueue.pop_back();
148117
return pResult;
149118
}
150119

151120
bool GltfModifier::NewVersionLoadRequester::hasMoreTilesToLoadInMainThread()
152121
const {
153-
return !this->_mainThreadQueue.empty();
122+
return !this->mainThreadQueue.empty();
154123
}
155124

156125
const Tile*
157126
GltfModifier::NewVersionLoadRequester::getNextTileToLoadInMainThread() {
158-
if (!this->_running) {
159-
CESIUM_ASSERT(this->_mainThreadQueue.empty());
160-
return nullptr;
161-
}
162-
163-
CESIUM_ASSERT(!this->_mainThreadQueue.empty());
164-
const Tile* pResult = this->_mainThreadQueue.back().get();
165-
this->_mainThreadQueue.pop_back();
166-
167-
if (this->_mainThreadQueue.empty()) {
168-
this->addTilesToQueues();
169-
170-
// If both queues are still empty, we're done.
171-
if (this->_workerThreadQueue.empty() && this->_mainThreadQueue.empty()) {
172-
this->_running = false;
173-
}
174-
}
175-
127+
CESIUM_ASSERT(!this->mainThreadQueue.empty());
128+
const Tile* pResult = this->mainThreadQueue.back().get();
129+
this->mainThreadQueue.pop_back();
176130
return pResult;
177131
}
178132

Cesium3DTilesSelection/src/Tile.cpp

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -214,20 +214,20 @@ int64_t Tile::computeByteSize() const noexcept {
214214
return bytes;
215215
}
216216

217-
bool Tile::isRenderable(std::optional<int> modelVersion) const noexcept {
217+
bool Tile::isRenderable(std::optional<int> /* modelVersion */) const noexcept {
218218
if (getState() == TileLoadState::Failed) {
219219
// Explicitly treat failed tiles as "renderable" - we just treat them like
220220
// empty tiles.
221221
return true;
222222
}
223223

224224
if (getState() == TileLoadState::Done) {
225-
auto* renderContent = getContent().getRenderContent();
226-
if (renderContent && modelVersion &&
227-
// compares optional values if both have one:
228-
modelVersion != renderContent->getModel().version) {
229-
return false;
230-
}
225+
// auto* renderContent = getContent().getRenderContent();
226+
// if (renderContent && modelVersion &&
227+
// // compares optional values if both have one:
228+
// modelVersion != renderContent->getModel().version) {
229+
// return false;
230+
// }
231231
// An unconditionally-refined tile is never renderable... UNLESS it has no
232232
// children, in which case waiting longer will be futile.
233233
if (!getUnconditionallyRefine() || this->_children.empty()) {

Cesium3DTilesSelection/src/TilesetContentManager.cpp

Lines changed: 22 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1103,18 +1103,16 @@ TilesetContentManager::~TilesetContentManager() noexcept {
11031103
this->_destructionCompletePromise.resolve();
11041104
}
11051105

1106-
namespace {
1107-
1108-
void reapplyGltfModifier(
1109-
TilesetContentManager& contentManager,
1106+
void TilesetContentManager::reapplyGltfModifier(
11101107
Tile& tile,
11111108
const TilesetOptions& tilesetOptions,
1112-
TileRenderContent* pRenderContent) {
1109+
TileRenderContent* pRenderContent) noexcept {
1110+
this->notifyTileStartLoading(&tile);
11131111
pRenderContent->setGltfModifierState(GltfModifier::State::WorkerRunning);
11141112

11151113
const CesiumGltf::Model& previousModel = pRenderContent->getModel();
11161114

1117-
const TilesetExternals& externals = contentManager.getExternals();
1115+
const TilesetExternals& externals = this->getExternals();
11181116

11191117
// It is safe to capture the TilesetExternals and Model by reference because
11201118
// the TilesetContentManager guarantees both will continue to exist and are
@@ -1178,29 +1176,30 @@ void reapplyGltfModifier(
11781176
tileTransform,
11791177
rendererOptions);
11801178
})
1181-
.thenInMainThread([pTile = Tile::Pointer(&tile)](
1179+
.thenInMainThread([this, pTile = Tile::Pointer(&tile)](
11821180
TileLoadResultAndRenderResources&& pair) {
11831181
pTile->getContent().getRenderContent()->setGltfModifierState(
11841182
GltfModifier::State::WorkerDone);
1183+
this->notifyTileDoneLoading(pTile.get());
11851184
pTile->getContent()
11861185
.getRenderContent()
11871186
->setModifiedModelAndRenderResources(
11881187
std::move(std::get<CesiumGltf::Model>(pair.result.contentKind)),
11891188
pair.pRenderResources);
1189+
this->_externals.pGltfModifier->onWorkerThreadApplyComplete(*pTile);
11901190
})
11911191
.catchInMainThread(
1192-
[pTile = Tile::Pointer(&tile), &externals](std::exception&& e) {
1192+
[this, pTile = Tile::Pointer(&tile), &externals](std::exception&& e) {
11931193
pTile->getContent().getRenderContent()->setGltfModifierState(
11941194
GltfModifier::State::WorkerDone);
1195+
this->notifyTileDoneLoading(pTile.get());
11951196
SPDLOG_LOGGER_ERROR(
11961197
externals.pLogger,
11971198
"An unexpected error occurred when reapplying GltfModifier: {}",
11981199
e.what());
11991200
});
12001201
}
12011202

1202-
} // namespace
1203-
12041203
void TilesetContentManager::loadTileContent(
12051204
Tile& tile,
12061205
const TilesetOptions& tilesetOptions) {
@@ -1217,7 +1216,7 @@ void TilesetContentManager::loadTileContent(
12171216
pRenderContent->getGltfModifierState() == GltfModifier::State::Idle &&
12181217
pRenderContent->getModel().version !=
12191218
_externals.pGltfModifier->getCurrentVersion()) {
1220-
reapplyGltfModifier(*this, tile, tilesetOptions, pRenderContent);
1219+
this->reapplyGltfModifier(tile, tilesetOptions, pRenderContent);
12211220
return;
12221221
}
12231222
// else: we may be in the case related to raster tiles, see just below
@@ -1357,6 +1356,18 @@ void TilesetContentManager::loadTileContent(
13571356
.thenInMainThread([pTile, thiz](TileLoadResultAndRenderResources&& pair) {
13581357
setTileContent(*pTile, std::move(pair.result), pair.pRenderResources);
13591358
thiz->notifyTileDoneLoading(pTile.get());
1359+
1360+
if (thiz->_externals.pGltfModifier) {
1361+
const TileRenderContent* pRenderContent =
1362+
pTile->getContent().getRenderContent();
1363+
CESIUM_ASSERT(!pRenderContent || !pRenderContent->getModifiedModel());
1364+
if (pRenderContent &&
1365+
pRenderContent->getModel().version !=
1366+
thiz->_externals.pGltfModifier->getCurrentVersion()) {
1367+
thiz->_externals.pGltfModifier->onOldVersionContentLoadingComplete(
1368+
*pTile);
1369+
}
1370+
}
13601371
})
13611372
.catchInMainThread([pLogger = this->_externals.pLogger, pTile, thiz](
13621373
std::exception&& e) {

Cesium3DTilesSelection/src/TilesetContentManager.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,11 @@ class TilesetContentManager
204204

205205
void notifyTileUnloading(const Tile* pTile) noexcept;
206206

207+
void reapplyGltfModifier(
208+
Tile& tile,
209+
const TilesetOptions& tilesetOptions,
210+
TileRenderContent* pRenderContent) noexcept;
211+
207212
template <class TilesetContentLoaderType>
208213
void propagateTilesetContentLoaderResult(
209214
TilesetLoadType type,

0 commit comments

Comments
 (0)