Merge lp:~stellarium/stellarium/gz_landscapePreload into lp:stellarium
- gz_landscapePreload
- Merge into trunk
Proposed by
gzotti
Status: | Merged |
---|---|
Merged at revision: | 9107 |
Proposed branch: | lp:~stellarium/stellarium/gz_landscapePreload |
Merge into: | lp:stellarium |
Diff against target: |
724 lines (+230/-61) 6 files modified
src/core/StelTexture.hpp (+4/-1) src/core/StelTextureMgr.hpp (+1/-1) src/core/modules/Landscape.cpp (+66/-36) src/core/modules/Landscape.hpp (+17/-0) src/core/modules/LandscapeMgr.cpp (+100/-16) src/core/modules/LandscapeMgr.hpp (+42/-7) |
To merge this branch: | bzr merge lp:~stellarium/stellarium/gz_landscapePreload |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Alexander Wolf | Approve | ||
Review via email:
|
Commit message
Allow caching for landscapes, including preloading and some other manipulation via scripting.
Description of the change
This branch adds caching for the landscapes, mostly useful for the multi-gigabyte GPUs of today, but (hopefully) not disturbing for older systems. Big landscapes take several seconds to load. Switching rapidly between several landscapes becomes much easier with this. It is also possible to pre-load or delete from the cache via scripting.
Cache size can be configured in config.ini.
To post a comment you must log in.
Revision history for this message
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Alexander Wolf (alexwolf) : | # |
review:
Approve
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'src/core/StelTexture.hpp' |
2 | --- src/core/StelTexture.hpp 2016-11-28 16:01:23 +0000 |
3 | +++ src/core/StelTexture.hpp 2017-01-19 22:30:07 +0000 |
4 | @@ -91,6 +91,9 @@ |
5 | //! Return whether the image is currently being loaded |
6 | bool isLoading() const {return (loader || networkReply) && !canBind();} |
7 | |
8 | + //! Return texture memory size |
9 | + unsigned int getGlSize() const {return glSize;} |
10 | + |
11 | signals: |
12 | //! Emitted when the texture is ready to be bind(), i.e. when downloaded, imageLoading and glLoading is over |
13 | //! or when an error occured and the texture will never be available |
14 | @@ -171,7 +174,7 @@ |
15 | GLsizei height; //! Texture image height |
16 | |
17 | //! Size in GL memory |
18 | - int glSize; |
19 | + unsigned int glSize; |
20 | }; |
21 | |
22 | |
23 | |
24 | === modified file 'src/core/StelTextureMgr.hpp' |
25 | --- src/core/StelTextureMgr.hpp 2016-11-21 21:04:36 +0000 |
26 | +++ src/core/StelTextureMgr.hpp 2017-01-19 22:30:07 +0000 |
27 | @@ -61,7 +61,7 @@ |
28 | //! Must be called after the creation of the GLContext. |
29 | void init(); |
30 | |
31 | - int glMemoryUsage; |
32 | + unsigned int glMemoryUsage; |
33 | }; |
34 | |
35 | |
36 | |
37 | === modified file 'src/core/modules/Landscape.cpp' |
38 | --- src/core/modules/Landscape.cpp 2017-01-08 16:39:11 +0000 |
39 | +++ src/core/modules/Landscape.cpp 2017-01-19 22:30:07 +0000 |
40 | @@ -2,6 +2,7 @@ |
41 | * Stellarium |
42 | * Copyright (C) 2003 Fabien Chereau |
43 | * Copyright (C) 2011 Bogdan Marinov |
44 | + * Copyright (C) 2014-17 Georg Zotti |
45 | * |
46 | * This program is free software; you can redistribute it and/or |
47 | * modify it under the terms of the GNU General Public License |
48 | @@ -37,6 +38,7 @@ |
49 | |
50 | Landscape::Landscape(float _radius) |
51 | : radius(_radius) |
52 | + , id("uninitialized") |
53 | , minBrightness(-1.) |
54 | , landscapeBrightness(1.) |
55 | , lightScapeBrightness(0.) |
56 | @@ -63,6 +65,7 @@ |
57 | // Load attributes common to all landscapes |
58 | void Landscape::loadCommon(const QSettings& landscapeIni, const QString& landscapeId) |
59 | { |
60 | + id = landscapeId; |
61 | name = landscapeIni.value("landscape/name").toString(); |
62 | author = landscapeIni.value("landscape/author").toString(); |
63 | description = landscapeIni.value("landscape/description").toString(); |
64 | @@ -284,13 +287,14 @@ |
65 | { |
66 | QString line=in.readLine(); |
67 | |
68 | - // TODO: Read entries, construct vectors, put in list. |
69 | - if (line.startsWith('#')) |
70 | + // Skip comments and all-empty lines (space allowed and ignored) |
71 | + if (line.startsWith('#') || line.trimmed().isEmpty() ) |
72 | continue; |
73 | + // Read entries, construct vectors, put in list. |
74 | QStringList parts=line.split('|'); |
75 | if (parts.count() != 5) |
76 | { |
77 | - qWarning() << "Invalid line in landscape" << descFileName << ":" << line; |
78 | + qWarning() << "Invalid line in landscape gazetteer" << descFileName << ":" << line; |
79 | continue; |
80 | } |
81 | LandscapeLabel newLabel; |
82 | @@ -359,6 +363,7 @@ |
83 | , drawGroundFirst(0) |
84 | , tanMode(false) |
85 | , calibrated(false) |
86 | + , memorySize(sizeof(LandscapeOldStyle)) // start with just the known entries. |
87 | {} |
88 | |
89 | LandscapeOldStyle::~LandscapeOldStyle() |
90 | @@ -391,7 +396,7 @@ |
91 | { |
92 | qWarning() << "Landscape type mismatch for landscape " << landscapeId |
93 | << ", expected old_style, found " << type << ". No landscape in use."; |
94 | - validLandscape = 0; |
95 | + validLandscape = false; |
96 | return; |
97 | } |
98 | |
99 | @@ -421,6 +426,7 @@ |
100 | if ( (!horizonPolygon) && calibrated ) { // for uncalibrated landscapes the texture is currently never queried, so no need to store. |
101 | QImage *image = new QImage(texturePath); |
102 | sidesImages.append(image); // indices identical to those in sideTexs |
103 | + memorySize+=image->byteCount(); |
104 | } |
105 | // Also allow light textures. The light textures must cover the same geometry as the sides. It is allowed that not all or even any light textures are present! |
106 | textureKey = QString("landscape/light%1").arg(i); |
107 | @@ -429,6 +435,8 @@ |
108 | { |
109 | const QString lightTexturePath = getTexturePath(textureName, landscapeId); |
110 | sideTexs[nbSideTexs+i] = StelApp::getInstance().getTextureManager().createTexture(lightTexturePath); |
111 | + if(sideTexs[nbSideTexs+i]) |
112 | + memorySize+=sideTexs[nbSideTexs+i].data()->getGlSize(); |
113 | } |
114 | else |
115 | sideTexs[nbSideTexs+i].clear(); |
116 | @@ -471,28 +479,14 @@ |
117 | QString groundTexName = landscapeIni.value("landscape/groundtex").toString(); |
118 | QString groundTexPath = getTexturePath(groundTexName, landscapeId); |
119 | groundTex = StelApp::getInstance().getTextureManager().createTexture(groundTexPath, StelTexture::StelTextureParams(true)); |
120 | - // GZ 2013/11: I don't see any use of this: |
121 | -// QString description = landscapeIni.value("landscape/ground").toString(); |
122 | -// //sscanf(description.toLocal8Bit(),"groundtex:%f:%f:%f:%f",&a,&b,&c,&d); |
123 | -// QStringList parameters = description.split(':'); |
124 | -// groundTexCoord.tex = groundTex; |
125 | -// groundTexCoord.texCoords[0] = parameters.at(1).toFloat(); |
126 | -// groundTexCoord.texCoords[1] = parameters.at(2).toFloat(); |
127 | -// groundTexCoord.texCoords[2] = parameters.at(3).toFloat(); |
128 | -// groundTexCoord.texCoords[3] = parameters.at(4).toFloat(); |
129 | + if (groundTex) |
130 | + memorySize+=groundTex.data()->getGlSize(); |
131 | |
132 | QString fogTexName = landscapeIni.value("landscape/fogtex").toString(); |
133 | QString fogTexPath = getTexturePath(fogTexName, landscapeId); |
134 | fogTex = StelApp::getInstance().getTextureManager().createTexture(fogTexPath, StelTexture::StelTextureParams(true, GL_LINEAR, GL_REPEAT)); |
135 | - // GZ 2013/11: I don't see any use of this: |
136 | -// QString description = landscapeIni.value("landscape/fog").toString(); |
137 | -// //sscanf(description.toLocal8Bit(),"fogtex:%f:%f:%f:%f",&a,&b,&c,&d); |
138 | -// QStringList parameters = description.split(':'); |
139 | -// fogTexCoord.tex = fogTex; |
140 | -// fogTexCoord.texCoords[0] = parameters.at(1).toFloat(); |
141 | -// fogTexCoord.texCoords[1] = parameters.at(2).toFloat(); |
142 | -// fogTexCoord.texCoords[2] = parameters.at(3).toFloat(); |
143 | -// fogTexCoord.texCoords[3] = parameters.at(4).toFloat(); |
144 | + if (fogTex) |
145 | + memorySize+=fogTex.data()->getGlSize(); |
146 | |
147 | // Precompute the vertex arrays for ground display |
148 | // Make slices_per_side=(3<<K) so that the innermost polygon of the fandisk becomes a triangle: |
149 | @@ -520,9 +514,9 @@ |
150 | // GZ: the original code for vertical placement makes unfortunately no sense. There are many approximately-fitted landscapes, though. |
151 | // I added a switch "calibrated" for the ini file. If true, it works as this landscape apparently was originally intended, |
152 | // if false (or missing) it uses the original code. |
153 | - // So I corrected the texture coordinates so that decorAltAngle is the total vertical angle, decorAngleShift the lower angle, |
154 | + // I corrected the texture coordinates so that decorAltAngle is the total vertical angle, decorAngleShift the lower angle, |
155 | // and the texture in between is correctly stretched. |
156 | - // I located an undocumented switch tan_mode, maybe tan_mode=true means cylindrical panorama projection. |
157 | + // I located an undocumented switch tan_mode, maybe tan_mode=true means cylindrical panorama projection instead of equirectangular. |
158 | // Since V0.13, calibrated&&tanMode also works! |
159 | // In calibrated && !tan_mode, the vertical position is computed correctly, so that quads off the horizon are larger. |
160 | // in calibrated && tan_mode, d_z can become a constant because the texture is already predistorted in cylindrical projection. |
161 | @@ -619,6 +613,7 @@ |
162 | } |
163 | } |
164 | } |
165 | + //qDebug() << "OldStyleLandscape" << landscapeId << "loaded, mem size:" << memorySize; |
166 | } |
167 | |
168 | void LandscapeOldStyle::draw(StelCore* core) |
169 | @@ -836,17 +831,18 @@ |
170 | if(type != "polygonal") |
171 | { |
172 | qWarning() << "Landscape type mismatch for landscape "<< landscapeId << ", expected polygonal, found " << type << ". No landscape in use.\n"; |
173 | - validLandscape = 0; |
174 | + validLandscape = false; |
175 | return; |
176 | } |
177 | if (horizonPolygon.isNull()) |
178 | { |
179 | qWarning() << "Landscape " << landscapeId << " does not declare a valid polygonal_horizon_list. No landscape in use.\n"; |
180 | - validLandscape = 0; |
181 | + validLandscape = false; |
182 | return; |
183 | } |
184 | groundColor=StelUtils::strToVec3f( landscapeIni.value("landscape/ground_color", "0,0,0" ).toString() ); |
185 | - validLandscape = 1; // assume ok... |
186 | + validLandscape = true; // assume ok... |
187 | + //qDebug() << "PolygonalLandscape" << landscapeId << "loaded, mem size:" << getMemorySize(); |
188 | } |
189 | |
190 | void LandscapePolygonal::draw(StelCore* core) |
191 | @@ -891,8 +887,12 @@ |
192 | |
193 | LandscapeFisheye::LandscapeFisheye(float _radius) |
194 | : Landscape(_radius) |
195 | + , mapTex(StelTextureSP()) |
196 | + , mapTexFog(StelTextureSP()) |
197 | + , mapTexIllum(StelTextureSP()) |
198 | , mapImage(NULL) |
199 | , texFov(360.) |
200 | + , memorySize(0) |
201 | {} |
202 | |
203 | LandscapeFisheye::~LandscapeFisheye() |
204 | @@ -909,7 +909,7 @@ |
205 | if(type != "fisheye") |
206 | { |
207 | qWarning() << "Landscape type mismatch for landscape "<< landscapeId << ", expected fisheye, found " << type << ". No landscape in use.\n"; |
208 | - validLandscape = 0; |
209 | + validLandscape = false; |
210 | return; |
211 | } |
212 | create(name, |
213 | @@ -918,25 +918,38 @@ |
214 | getTexturePath(landscapeIni.value("landscape/maptex_fog").toString(), landscapeId), |
215 | getTexturePath(landscapeIni.value("landscape/maptex_illum").toString(), landscapeId), |
216 | landscapeIni.value("landscape/angle_rotatez", 0.f).toFloat()); |
217 | + //qDebug() << "FisheyeLandscape" << landscapeId << "loaded, mem size:" << memorySize; |
218 | } |
219 | |
220 | |
221 | void LandscapeFisheye::create(const QString _name, float _texturefov, const QString& _maptex, const QString &_maptexFog, const QString& _maptexIllum, const float _angleRotateZ) |
222 | { |
223 | // qDebug() << _name << " " << _fullpath << " " << _maptex << " " << _texturefov; |
224 | - validLandscape = 1; // assume ok... |
225 | + validLandscape = true; // assume ok... |
226 | name = _name; |
227 | texFov = _texturefov*M_PI/180.f; |
228 | angleRotateZ = _angleRotateZ*M_PI/180.f; |
229 | + |
230 | if (!horizonPolygon) |
231 | + { |
232 | mapImage = new QImage(_maptex); |
233 | + memorySize+=mapImage->byteCount(); |
234 | + } |
235 | mapTex = StelApp::getInstance().getTextureManager().createTexture(_maptex, StelTexture::StelTextureParams(true)); |
236 | + memorySize+=mapTex.data()->getGlSize(); |
237 | |
238 | - if (_maptexIllum.length()) |
239 | + if (_maptexIllum.length() && (!_maptexIllum.endsWith("/"))) |
240 | + { |
241 | mapTexIllum = StelApp::getInstance().getTextureManager().createTexture(_maptexIllum, StelTexture::StelTextureParams(true)); |
242 | - if (_maptexFog.length()) |
243 | + if (mapTexIllum) |
244 | + memorySize+=mapTexIllum.data()->getGlSize(); |
245 | + } |
246 | + if (_maptexFog.length() && (!_maptexFog.endsWith("/"))) |
247 | + { |
248 | mapTexFog = StelApp::getInstance().getTextureManager().createTexture(_maptexFog, StelTexture::StelTextureParams(true)); |
249 | - |
250 | + if (mapTexFog) |
251 | + memorySize+=mapTexFog.data()->getGlSize(); |
252 | + } |
253 | } |
254 | |
255 | |
256 | @@ -1025,6 +1038,9 @@ |
257 | |
258 | LandscapeSpherical::LandscapeSpherical(float _radius) |
259 | : Landscape(_radius) |
260 | + , mapTex(StelTextureSP()) |
261 | + , mapTexFog(StelTextureSP()) |
262 | + , mapTexIllum(StelTextureSP()) |
263 | , mapTexTop(0.) |
264 | , mapTexBottom(0.) |
265 | , fogTexTop(0.) |
266 | @@ -1032,6 +1048,7 @@ |
267 | , illumTexTop(0.) |
268 | , illumTexBottom(0.) |
269 | , mapImage(NULL) |
270 | + , memorySize(sizeof(LandscapeSpherical)) |
271 | {} |
272 | |
273 | LandscapeSpherical::~LandscapeSpherical() |
274 | @@ -1054,7 +1071,7 @@ |
275 | qWarning() << "Landscape type mismatch for landscape "<< landscapeId |
276 | << ", expected spherical, found " << type |
277 | << ". No landscape in use.\n"; |
278 | - validLandscape = 0; |
279 | + validLandscape = false; |
280 | return; |
281 | } |
282 | |
283 | @@ -1069,6 +1086,7 @@ |
284 | landscapeIni.value("landscape/maptex_fog_bottom" , -90.f).toFloat(), |
285 | landscapeIni.value("landscape/maptex_illum_top" , 90.f).toFloat(), |
286 | landscapeIni.value("landscape/maptex_illum_bottom", -90.f).toFloat()); |
287 | + //qDebug() << "SphericalLandscape" << landscapeId << "loaded, mem size:" << memorySize; |
288 | } |
289 | |
290 | |
291 | @@ -1079,7 +1097,7 @@ |
292 | const float _illumTexTop, const float _illumTexBottom) |
293 | { |
294 | //qDebug() << "LandscapeSpherical::create():"<< _name << " : " << _maptex << " : " << _maptexFog << " : " << _maptexIllum << " : " << _angleRotateZ; |
295 | - validLandscape = 1; // assume ok... |
296 | + validLandscape = true; // assume ok... |
297 | name = _name; |
298 | angleRotateZ = _angleRotateZ *M_PI/180.f; // Defined in ini --> internal prg value |
299 | mapTexTop = (90.f-_mapTexTop) *M_PI/180.f; // top 90 --> 0 |
300 | @@ -1089,13 +1107,25 @@ |
301 | illumTexTop = (90.f-_illumTexTop) *M_PI/180.f; |
302 | illumTexBottom= (90.f-_illumTexBottom)*M_PI/180.f; |
303 | if (!horizonPolygon) |
304 | + { |
305 | mapImage = new QImage(_maptex); |
306 | + memorySize+=mapImage->byteCount(); |
307 | + } |
308 | mapTex = StelApp::getInstance().getTextureManager().createTexture(_maptex, StelTexture::StelTextureParams(true)); |
309 | + memorySize+=mapTex.data()->getGlSize(); |
310 | |
311 | - if (_maptexIllum.length()) |
312 | + if (_maptexIllum.length() && (!_maptexIllum.endsWith("/"))) |
313 | + { |
314 | mapTexIllum = StelApp::getInstance().getTextureManager().createTexture(_maptexIllum, StelTexture::StelTextureParams(true)); |
315 | - if (_maptexFog.length()) |
316 | + if (mapTexIllum) |
317 | + memorySize+=mapTexIllum.data()->getGlSize(); |
318 | + } |
319 | + if (_maptexFog.length() && (!_maptexFog.endsWith("/"))) |
320 | + { |
321 | mapTexFog = StelApp::getInstance().getTextureManager().createTexture(_maptexFog, StelTexture::StelTextureParams(true)); |
322 | + if (mapTexFog) |
323 | + memorySize+=mapTexFog.data()->getGlSize(); |
324 | + } |
325 | } |
326 | |
327 | void LandscapeSpherical::draw(StelCore* core) |
328 | |
329 | === modified file 'src/core/modules/Landscape.hpp' |
330 | --- src/core/modules/Landscape.hpp 2016-05-22 21:14:58 +0000 |
331 | +++ src/core/modules/Landscape.hpp 2017-01-19 22:30:07 +0000 |
332 | @@ -75,6 +75,13 @@ |
333 | //! @param landscapeIni A reference to an existing QSettings object which describes the landscape |
334 | //! @param landscapeId The name of the directory for the landscape files (e.g. "ocean") |
335 | virtual void load(const QSettings& landscapeIni, const QString& landscapeId) = 0; |
336 | + |
337 | + //! Return approximate memory footprint in bytes (required for cache cost estimate in LandscapeMgr) |
338 | + //! The returned value is only approximate, content of QStrings and other small containers like the horizon polygon are not put in in detail. |
339 | + //! However, texture image sizes must be computed in subclasses. |
340 | + //! The value returned is a sum of RAM and texture memory requirements. |
341 | + virtual unsigned int getMemorySize() const {return sizeof(Landscape);} |
342 | + |
343 | virtual void draw(StelCore* core) = 0; |
344 | void update(double deltaTime) |
345 | { |
346 | @@ -124,6 +131,8 @@ |
347 | QString getAuthorName() const {return author;} |
348 | //! Get landscape description |
349 | QString getDescription() const {return description;} |
350 | + //! Get landscape id. This is the landscape directory name, used for cache handling. |
351 | + QString getId() const {return id;} |
352 | |
353 | //! Return the associated location (may be empty!) |
354 | const StelLocation& getLocation() const {return location;} |
355 | @@ -202,6 +211,7 @@ |
356 | QString name; //! Read from landscape.ini:[landscape]name |
357 | QString author; //! Read from landscape.ini:[landscape]author |
358 | QString description; //! Read from landscape.ini:[landscape]description |
359 | + QString id; //! Set during load. Required for consistent caching. |
360 | |
361 | float minBrightness; //! Read from landscape.ini:[landscape]minimal_brightness. Allows minimum visibility that cannot be underpowered. |
362 | float landscapeBrightness; //! brightness [0..1] to draw the landscape. Computed by the LandscapeMgr. |
363 | @@ -259,6 +269,7 @@ |
364 | LandscapeOldStyle(float radius = 2.f); |
365 | virtual ~LandscapeOldStyle(); |
366 | virtual void load(const QSettings& landscapeIni, const QString& landscapeId); |
367 | + virtual unsigned int getMemorySize() const {return memorySize;} |
368 | virtual void draw(StelCore* core); |
369 | //void create(bool _fullpath, QMap<QString, QString> param); // still not implemented |
370 | virtual float getOpacity(Vec3d azalt) const; |
371 | @@ -302,6 +313,7 @@ |
372 | }; |
373 | |
374 | QList<LOSSide> precomputedSides; |
375 | + unsigned int memorySize; |
376 | }; |
377 | |
378 | ///////////////////////////////////////////////////////// |
379 | @@ -319,6 +331,7 @@ |
380 | LandscapePolygonal(float radius = 1.f); |
381 | virtual ~LandscapePolygonal(); |
382 | virtual void load(const QSettings& landscapeIni, const QString& landscapeId); |
383 | + virtual unsigned int getMemorySize() const {return sizeof(LandscapePolygonal);} |
384 | virtual void draw(StelCore* core); |
385 | virtual float getOpacity(Vec3d azalt) const; |
386 | private: |
387 | @@ -338,6 +351,7 @@ |
388 | LandscapeFisheye(float radius = 1.f); |
389 | virtual ~LandscapeFisheye(); |
390 | virtual void load(const QSettings& landscapeIni, const QString& landscapeId); |
391 | + virtual unsigned int getMemorySize() const {return memorySize;} |
392 | virtual void draw(StelCore* core); |
393 | //! Sample landscape texture for transparency/opacity. May be used for visibility, sunrise etc. |
394 | //! @param azalt normalized direction in alt-az frame |
395 | @@ -360,6 +374,7 @@ |
396 | QImage *mapImage; //!< The same image as mapTex, but stored in-mem for sampling. |
397 | |
398 | float texFov; |
399 | + unsigned int memorySize; |
400 | }; |
401 | |
402 | ////////////////////////////////////////////////////////////////////////// |
403 | @@ -378,6 +393,7 @@ |
404 | LandscapeSpherical(float radius = 1.f); |
405 | virtual ~LandscapeSpherical(); |
406 | virtual void load(const QSettings& landscapeIni, const QString& landscapeId); |
407 | + virtual unsigned int getMemorySize() const {return memorySize;} |
408 | virtual void draw(StelCore* core); |
409 | //! Sample landscape texture for transparency/opacity. May be used for visibility, sunrise etc. |
410 | //! @param azalt normalized direction in alt-az frame |
411 | @@ -414,6 +430,7 @@ |
412 | float illumTexTop; //!< zenithal top angle of the illumination texture, radians |
413 | float illumTexBottom; //!< zenithal bottom angle of the illumination texture, radians |
414 | QImage *mapImage; //!< The same image as mapTex, but stored in-mem for opacity sampling. |
415 | + unsigned int memorySize; //!< holds an approximate value of memory consumption (for cache cost estimate) |
416 | }; |
417 | |
418 | #endif // _LANDSCAPE_HPP_ |
419 | |
420 | === modified file 'src/core/modules/LandscapeMgr.cpp' |
421 | --- src/core/modules/LandscapeMgr.cpp 2017-01-08 16:39:11 +0000 |
422 | +++ src/core/modules/LandscapeMgr.cpp 2017-01-19 22:30:07 +0000 |
423 | @@ -142,7 +142,8 @@ |
424 | |
425 | |
426 | LandscapeMgr::LandscapeMgr() |
427 | - : atmosphere(NULL) |
428 | + : StelModule() |
429 | + , atmosphere(NULL) |
430 | , cardinalsPoints(NULL) |
431 | , landscape(NULL) |
432 | , oldLandscape(NULL) |
433 | @@ -154,7 +155,7 @@ |
434 | , flagLandscapeSetsMinimalBrightness(false) |
435 | , flagAtmosphereAutoEnabling(false) |
436 | { |
437 | - setObjectName("LandscapeMgr"); |
438 | + setObjectName("LandscapeMgr"); // should be done by StelModule's constructor. |
439 | |
440 | //Note: The first entry in the list is used as the default 'default landscape' in removeLandscape(). |
441 | packagedLandscapeIDs = (QStringList() << "guereins"); |
442 | @@ -165,6 +166,7 @@ |
443 | packagedLandscapeIDs << directories.fileName(); |
444 | } |
445 | packagedLandscapeIDs.removeDuplicates(); |
446 | + landscapeCache.clear(); |
447 | } |
448 | |
449 | LandscapeMgr::~LandscapeMgr() |
450 | @@ -178,6 +180,8 @@ |
451 | } |
452 | delete landscape; |
453 | landscape = NULL; |
454 | + qDebug() << "LandscapeMgr: Clearing cache of" << landscapeCache.size() << "landscapes totalling about " << landscapeCache.totalCost() << "MB."; |
455 | + landscapeCache.clear(); // deletes all objects within. |
456 | } |
457 | |
458 | /************************************************************************* |
459 | @@ -198,6 +202,7 @@ |
460 | void LandscapeMgr::update(double deltaTime) |
461 | { |
462 | atmosphere->update(deltaTime); |
463 | + |
464 | if (oldLandscape) |
465 | { |
466 | // This is only when transitioning to newly loaded landscape. We must draw the old one until the new one is faded in completely. |
467 | @@ -208,7 +213,10 @@ |
468 | |
469 | if (oldLandscape->getEffectiveLandFadeValue()< 0.01f) |
470 | { |
471 | - delete oldLandscape; |
472 | + // new logic: try to put old landscape to cache. |
473 | + //qDebug() << "LandscapeMgr::update: moving oldLandscape " << oldLandscape->getId() << "to Cache. Cost:" << oldLandscape->getMemorySize()/(1024*1024)+1; |
474 | + landscapeCache.insert(oldLandscape->getId(), oldLandscape, oldLandscape->getMemorySize()/(1024*1024)+1); |
475 | + //qDebug() << "--> LandscapeMgr::update(): cache now contains " << landscapeCache.size() << "landscapes totalling about " << landscapeCache.totalCost() << "MB."; |
476 | oldLandscape=NULL; |
477 | } |
478 | } |
479 | @@ -368,8 +376,10 @@ |
480 | QSettings* conf = StelApp::getInstance().getSettings(); |
481 | Q_ASSERT(conf); |
482 | |
483 | + landscapeCache.setMaxCost(conf->value("landscape/cache_size_mb", 100).toInt()); |
484 | + qDebug() << "LandscapeMgr: initialized Cache for" << landscapeCache.maxCost() << "MB."; |
485 | + |
486 | atmosphere = new Atmosphere(); |
487 | - landscape = new LandscapeOldStyle(); |
488 | defaultLandscapeID = conf->value("init_location/landscape_name").toString(); |
489 | setCurrentLandscapeID(defaultLandscapeID); |
490 | setFlagLandscape(conf->value("landscape/flag_landscape", conf->value("landscape/flag_ground", true).toBool()).toBool()); |
491 | @@ -421,13 +431,39 @@ |
492 | if(id==currentLandscapeID) |
493 | return false; |
494 | |
495 | - // We want to lookup the landscape ID (dir) from the name. |
496 | - Landscape* newLandscape = createFromFile(StelFileMgr::findFile("landscapes/" + id + "/landscape.ini"), id); |
497 | - |
498 | - if (!newLandscape) |
499 | - { |
500 | - qWarning() << "ERROR while loading landscape " << "landscapes/" + id + "/landscape.ini"; |
501 | - return false; |
502 | + Landscape* newLandscape; |
503 | + |
504 | + // There is a slight chance that we switch back to oldLandscape while oldLandscape is still fading away. |
505 | + // in this case it is not yet stored in cache, but obviously available. So we just swap places. |
506 | + if (oldLandscape && oldLandscape->getId()==id) |
507 | + { |
508 | + newLandscape=oldLandscape; |
509 | + } |
510 | + else |
511 | + { |
512 | + // We want to lookup the landscape ID (dir) from the name. |
513 | + newLandscape= landscapeCache.take(id); |
514 | + |
515 | + if (newLandscape) |
516 | + { |
517 | +#ifndef NDEBUG |
518 | + qDebug() << "LandscapeMgr::setCurrentLandscapeID():: taken " << id << "from cache..."; |
519 | + qDebug() << ".-->LandscapeMgr::setCurrentLandscapeID(): cache contains " << landscapeCache.size() << "landscapes totalling about " << landscapeCache.totalCost() << "MB."; |
520 | +#endif |
521 | + } |
522 | + else |
523 | + { |
524 | +#ifndef NDEBUG |
525 | + qDebug() << "LandscapeMgr::setCurrentLandscapeID: Loading from file:" << id ; |
526 | +#endif |
527 | + newLandscape = createFromFile(StelFileMgr::findFile("landscapes/" + id + "/landscape.ini"), id); |
528 | + } |
529 | + |
530 | + if (!newLandscape) |
531 | + { |
532 | + qWarning() << "ERROR while loading landscape " << "landscapes/" + id + "/landscape.ini"; |
533 | + return false; |
534 | + } |
535 | } |
536 | |
537 | // Keep current landscape for a while, while new landscape fades in! |
538 | @@ -439,15 +475,23 @@ |
539 | newLandscape->setFlagShowFog(landscape->getFlagShowFog()); |
540 | newLandscape->setFlagShowIllumination(landscape->getFlagShowIllumination()); |
541 | newLandscape->setFlagShowLabels(landscape->getFlagShowLabels()); |
542 | - //in case we already fade out one old landscape (if switching too rapidly): the old one has to go immediately. |
543 | - if (oldLandscape) |
544 | - delete oldLandscape; |
545 | + |
546 | + // If we have an oldLandscape that is not just swapped back, put that into cache. |
547 | + if (oldLandscape && oldLandscape!=newLandscape) |
548 | + { |
549 | +#ifndef NDEBUG |
550 | + qDebug() << "LandscapeMgr::setCurrent: moving oldLandscape " << oldLandscape->getId() << "to Cache. Cost:" << oldLandscape->getMemorySize()/(1024*1024)+1; |
551 | +#endif |
552 | + landscapeCache.insert(oldLandscape->getId(), oldLandscape, oldLandscape->getMemorySize()/(1024*1024)+1); |
553 | +#ifndef NDEBUG |
554 | + qDebug() << "-->LandscapeMgr::setCurrentLandscapeId(): cache contains " << landscapeCache.size() << "landscapes totalling about " << landscapeCache.totalCost() << "MB."; |
555 | +#endif |
556 | + } |
557 | oldLandscape = landscape; // keep old while transitioning! |
558 | } |
559 | landscape=newLandscape; |
560 | currentLandscapeID = id; |
561 | |
562 | - |
563 | if (getFlagLandscapeSetsLocation() && landscape->hasLocation()) |
564 | { |
565 | StelCore *core = StelApp::getInstance().getCore(); |
566 | @@ -508,6 +552,46 @@ |
567 | } |
568 | } |
569 | |
570 | +// Load a landscape into cache. |
571 | +// @param id the ID of a landscape |
572 | +// @param replace true if existing landscape entry should be replaced (useful during development to reload after edit) |
573 | +// @return false if landscape could not be found, or existed already and replace was false. |
574 | +bool LandscapeMgr::precacheLandscape(const QString& id, const bool replace) |
575 | +{ |
576 | + if (landscapeCache.contains(id) && (!replace)) |
577 | + return false; |
578 | + |
579 | + Landscape* newLandscape = createFromFile(StelFileMgr::findFile("landscapes/" + id + "/landscape.ini"), id); |
580 | + if (!newLandscape) |
581 | + { |
582 | + qWarning() << "ERROR while preloading landscape " << "landscapes/" + id + "/landscape.ini"; |
583 | + return false; |
584 | + } |
585 | + |
586 | + bool res=landscapeCache.insert(id, newLandscape, newLandscape->getMemorySize()/(1024*1024)+1); |
587 | +#ifndef NDEBUG |
588 | + if (res) |
589 | + { |
590 | + qDebug() << "LandscapeMgr::precacheLandscape(): Successfully added landscape with ID " << id << "to cache"; |
591 | + } |
592 | + qDebug() << "LandscapeMgr::precacheLandscape(): cache contains " << landscapeCache.size() << "landscapes totalling about " << landscapeCache.totalCost() << "MB."; |
593 | +#endif |
594 | + return res; |
595 | +} |
596 | + |
597 | +// Remove a landscape from the cache of loaded landscapes. |
598 | +// @param id the ID of a landscape |
599 | +// @return false if landscape could not be found |
600 | +bool LandscapeMgr::removeCachedLandscape(const QString& id) |
601 | +{ |
602 | + bool res= landscapeCache.remove(id); |
603 | +#ifndef NDEBUG |
604 | + qDebug() << "LandscapeMgr::removeCachedLandscape(): cache contains " << landscapeCache.size() << "landscapes totalling about " << landscapeCache.totalCost() << "MB."; |
605 | +#endif |
606 | + return res; |
607 | +} |
608 | + |
609 | + |
610 | // Change the default landscape to the landscape with the ID specified. |
611 | bool LandscapeMgr::setDefaultLandscapeID(const QString& id) |
612 | { |
613 | @@ -878,7 +962,7 @@ |
614 | } |
615 | |
616 | /**************************************************************************** |
617 | - get a map of landscape name (from landscape.ini name field) to ID (dir name) |
618 | + get a map of landscape names (from landscape.ini name field) to ID (dir name) |
619 | ****************************************************************************/ |
620 | QMap<QString,QString> LandscapeMgr::getNameToDirMap() const |
621 | { |
622 | |
623 | === modified file 'src/core/modules/LandscapeMgr.hpp' |
624 | --- src/core/modules/LandscapeMgr.hpp 2016-12-18 06:38:55 +0000 |
625 | +++ src/core/modules/LandscapeMgr.hpp 2017-01-19 22:30:07 +0000 |
626 | @@ -28,6 +28,7 @@ |
627 | |
628 | #include <QMap> |
629 | #include <QStringList> |
630 | +#include <QCache> |
631 | |
632 | class Atmosphere; |
633 | class Cardinals; |
634 | @@ -41,7 +42,7 @@ |
635 | //! \note |
636 | //! The Bortle scale index setting was removed from this class, because it was duplicated |
637 | //! from StelSkyDrawer, complicating code that changes it. |
638 | -//! It is now only in StelSkyDrawer and can be accessed with |
639 | +//! It is now only in StelSkyDrawer and can be accessed |
640 | //! with \link StelSkyDrawer::getBortleScaleIndex getBortleScaleIndex \endlink |
641 | //! and \link StelSkyDrawer::setBortleScaleIndex setBortleScaleIndex \endlink. |
642 | //! Slots setAtmosphereBortleLightPollution and getAtmosphereBortleLightPollution |
643 | @@ -141,9 +142,10 @@ |
644 | /////////////////////////////////////////////////////////////////////////// |
645 | // Methods specific to the landscape manager |
646 | |
647 | - //! Load a landscape based on a hash of parameters mirroring the landscape.ini |
648 | - //! file and make it the current landscape. |
649 | - bool loadLandscape(QMap<QString, QString>& param); |
650 | + // Load a landscape based on a hash of parameters mirroring the landscape.ini |
651 | + // file and make it the current landscape. |
652 | + // GZ: This was declared, but not implemented(?) |
653 | + //bool loadLandscape(QMap<QString, QString>& param); |
654 | |
655 | //! Create a new landscape from the files which describe it. |
656 | //! Reads a landscape.ini file which is passed as the first parameter, determines |
657 | @@ -177,7 +179,7 @@ |
658 | //! this value explicitly to freeze it during image export. To unfreeze, call this again with any negative value. |
659 | void setAtmosphereAverageLuminance(const float overrideLuminance); |
660 | |
661 | - //! Return a map of landscape name to landscape ID (directory name). |
662 | + //! Return a map of landscape names to landscape IDs (directory names). |
663 | QMap<QString,QString> getNameToDirMap() const; |
664 | |
665 | //! Retrieve a list of the names of all the available landscapes in |
666 | @@ -212,6 +214,31 @@ |
667 | //! @param changeLocationDuration the duration of the transition animation |
668 | bool setCurrentLandscapeName(const QString& name, const double changeLocationDuration = 1.0); |
669 | |
670 | + //! Preload a landscape into cache. |
671 | + //! @param id the ID of a landscape |
672 | + //! @param replace true if existing landscape entry should be replaced (useful during development to reload after edit) |
673 | + //! @return false if landscape could not be found, or if it already existed in cache and replace was false. |
674 | + bool precacheLandscape(const QString& id, const bool replace=true); |
675 | + //! Remove a landscape from the cache of landscapes. |
676 | + //! @param id the ID of a landscape |
677 | + //! @return false if landscape could not be found |
678 | + bool removeCachedLandscape(const QString& id); |
679 | + //! Set size of the landscape cache, in MB. |
680 | + //! Default size is 100MB, or configured as [landscape/cache_size_mb] from config.ini. |
681 | + //! The landscape sizes returned in Landscape::getMemorySize() are only approximate, but include image and texture sizes. |
682 | + //! A big landscape may well take 150MB or more. |
683 | + //! On a 32bit system, keep this rather small. On 64bit with 16GB RAM and no other tasks, 4GB is no problem. |
684 | + //! Modern GPUs may have 4 or even 8GB of dedicated texture memory. Most of this may be filled with landscape textures. |
685 | + //! Example: a museum installation with 20 large (16384x2048) old_stype landscapes can require up to 3.5GB. Allow 4GB cache, |
686 | + //! and the system will never have to load a landscape during the show when all have been preloaded. |
687 | + void setCacheSize(int mb) { landscapeCache.setMaxCost(mb);} |
688 | + //! Retrieve total size of cache (MB). |
689 | + int getCacheSize() const {return landscapeCache.maxCost();} |
690 | + //! Retrieve sum of currently used memory in cache (MB, approximate) |
691 | + int getCacheFilledSize() const {return landscapeCache.totalCost();} |
692 | + //! Return number of landscapes already in the cache. |
693 | + int getCacheCount() const {return landscapeCache.count();} |
694 | + |
695 | //! Get the current landscape object. |
696 | Landscape* getCurrentLandscape() const { return landscape; } |
697 | |
698 | @@ -505,16 +532,24 @@ |
699 | //! Indicate auto-enable atmosphere for planets with atmospheres in location window |
700 | bool flagAtmosphereAutoEnabling; |
701 | |
702 | - // The ID of the currently loaded landscape |
703 | + //! The ID of the currently loaded landscape |
704 | QString currentLandscapeID; |
705 | |
706 | - // The ID of the default landscape |
707 | + //! The ID of the default landscape |
708 | QString defaultLandscapeID; |
709 | |
710 | //! List of the IDs of the landscapes packaged by default with Stellarium. |
711 | //! (So that they can't be removed.) |
712 | QStringList packagedLandscapeIDs; |
713 | |
714 | + //! QCache of landscapes kept in memory for faster access, esp. when frequently switching between several big landscapes. |
715 | + //! Example: a 16384-size old_style landscape takes about 10 seconds to load. Kept in cache, it is back instantly. |
716 | + //! Of course, this requires lots of RAM and GPU texture memory, but in the age of 64bit CPUs and 4GB and more GPU |
717 | + //! texture memory, it is no problem to keep even 20 or more landscapes. |
718 | + //! This is esp. useful in a context of automated setup (museum show or such) where a list of landscapes is preloaded |
719 | + //! at system start (e.g. in the startup.ssc script) and then retrieved while script is running. |
720 | + //! The key is just the LandscapeID. |
721 | + QCache<QString,Landscape> landscapeCache; |
722 | }; |
723 | |
724 | #endif // _LANDSCAPEMGR_HPP_ |