@@ -51,6 +51,21 @@ static float screenSpaceError( QgsChunkNode *node, const QgsChunkedEntity::Scene
51
51
return sse;
52
52
}
53
53
54
+
55
+ static bool hasAnyActiveChildren ( QgsChunkNode *node, QList<QgsChunkNode *> &activeNodes )
56
+ {
57
+ for ( int i = 0 ; i < node->childCount (); ++i )
58
+ {
59
+ QgsChunkNode *child = node->children ()[i];
60
+ if ( child->entity () && activeNodes.contains ( child ) )
61
+ return true ;
62
+ if ( hasAnyActiveChildren ( child, activeNodes ) )
63
+ return true ;
64
+ }
65
+ return false ;
66
+ }
67
+
68
+
54
69
QgsChunkedEntity::QgsChunkedEntity ( float tau, QgsChunkLoaderFactory *loaderFactory, bool ownsFactory, int primitiveBudget, Qt3DCore::QNode *parent )
55
70
: Qgs3DMapSceneEntity( parent )
56
71
, mTau( tau )
@@ -111,6 +126,7 @@ QgsChunkedEntity::~QgsChunkedEntity()
111
126
}
112
127
}
113
128
129
+
114
130
void QgsChunkedEntity::handleSceneUpdate ( const SceneState &state )
115
131
{
116
132
if ( !mIsValid )
@@ -173,20 +189,13 @@ void QgsChunkedEntity::handleSceneUpdate( const SceneState &state )
173
189
#endif
174
190
}
175
191
176
- double usedGpuMemory = QgsChunkedEntity::calculateEntityGpuMemorySize ( this );
177
-
178
- // unload those that are over the limit for replacement
179
- // TODO: what to do when our cache is too small and nodes are being constantly evicted + loaded again
180
- while ( usedGpuMemory > mGpuMemoryLimit )
181
- {
182
- QgsChunkListEntry *entry = mReplacementQueue ->takeLast ();
183
- usedGpuMemory -= QgsChunkedEntity::calculateEntityGpuMemorySize ( entry->chunk ->entity () );
184
- mActiveNodes .removeOne ( entry->chunk );
185
- entry->chunk ->unloadChunk (); // also deletes the entry
192
+ // if this entity's loaded nodes are using more GPU memory than allowed,
193
+ // let's try to unload those that are not needed right now
186
194
#ifdef QGISDEBUG
187
- ++unloaded;
195
+ unloaded = unloadNodes ();
196
+ #else
197
+ unloadNodes ();
188
198
#endif
189
- }
190
199
191
200
if ( mBboxesEntity )
192
201
{
@@ -214,6 +223,51 @@ void QgsChunkedEntity::handleSceneUpdate( const SceneState &state )
214
223
.arg ( t.elapsed () ), 2 );
215
224
}
216
225
226
+
227
+ int QgsChunkedEntity::unloadNodes ()
228
+ {
229
+ double usedGpuMemory = QgsChunkedEntity::calculateEntityGpuMemorySize ( this );
230
+ if ( usedGpuMemory <= mGpuMemoryLimit )
231
+ return 0 ;
232
+
233
+ QgsDebugMsgLevel ( QStringLiteral ( " Going to unload nodes to free GPU memory (used: %1 MB, limit: %2 MB)" ).arg ( usedGpuMemory ).arg ( mGpuMemoryLimit ), 2 );
234
+
235
+ int unloaded = 0 ;
236
+
237
+ // unload nodes starting from the back of the queue with currently loaded
238
+ // nodes - i.e. those that have been least recently used
239
+ QgsChunkListEntry *entry = mReplacementQueue ->last ();
240
+ while ( entry && usedGpuMemory > mGpuMemoryLimit )
241
+ {
242
+ // not all nodes are safe to unload: we do not want to unload nodes
243
+ // that are currently active, or have their descendants active or their
244
+ // siblings or their descendants are active (because in the next scene
245
+ // update, these would be very likely loaded again, making the unload worthless)
246
+ if ( entry->chunk ->parent () && !hasAnyActiveChildren ( entry->chunk ->parent (), mActiveNodes ) )
247
+ {
248
+ QgsChunkListEntry *entryPrev = entry->prev ;
249
+ mReplacementQueue ->takeEntry ( entry );
250
+ usedGpuMemory -= QgsChunkedEntity::calculateEntityGpuMemorySize ( entry->chunk ->entity () );
251
+ mActiveNodes .removeOne ( entry->chunk );
252
+ entry->chunk ->unloadChunk (); // also deletes the entry
253
+ ++unloaded;
254
+ entry = entryPrev;
255
+ }
256
+ else
257
+ {
258
+ entry = entry->prev ;
259
+ }
260
+ }
261
+
262
+ if ( usedGpuMemory > mGpuMemoryLimit )
263
+ {
264
+ QgsDebugMsgLevel ( QStringLiteral ( " Unable to unload enough nodes to free GPU memory (used: %1 MB, limit: %2 MB)" ).arg ( usedGpuMemory ).arg ( mGpuMemoryLimit ), 2 );
265
+ }
266
+
267
+ return unloaded;
268
+ }
269
+
270
+
217
271
QgsRange<float > QgsChunkedEntity::getNearFarPlaneRange ( const QMatrix4x4 &viewMatrix ) const
218
272
{
219
273
QList<QgsChunkNode *> activeEntityNodes = activeNodes ();
0 commit comments