FlightGear next
tilecache.cxx
Go to the documentation of this file.
1// TileCache.cxx -- routines to handle scenery tile caching
2//
3// Written by Curtis Olson, started December 2000.
4//
5// Copyright (C) 2000 Curtis L. Olson - http://www.flightgear.org/~curt
6//
7// This program is free software; you can redistribute it and/or
8// modify it under the terms of the GNU General Public License as
9// published by the Free Software Foundation; either version 2 of the
10// License, or (at your option) any later version.
11//
12// This program is distributed in the hope that it will be useful, but
13// WITHOUT ANY WARRANTY; without even the implied warranty of
14// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15// General Public License for more details.
16//
17// You should have received a copy of the GNU General Public License
18// along with this program; if not, write to the Free Software
19// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20//
21// $Id$
22
23#ifdef HAVE_CONFIG_H
24# include <config.h>
25#endif
26
27#include <simgear/bucket/newbucket.hxx>
28#include <simgear/debug/logstream.hxx>
29#include <simgear/misc/sg_path.hxx>
30
31#include "tileentry.hxx"
32#include "tilecache.hxx"
33
35 max_cache_size(100), current_time(0.0)
36{
37 tile_cache.clear();
38}
39
40
42{
43 tile_map_iterator it = tile_cache.begin();
44 for (; it != tile_cache.end(); ++it) {
45 TileEntry* tile = it->second;
47 delete tile;
48 }
49}
50
51
52// Free a tile cache entry
53void TileCache::entry_free( long tile_index ) {
54 SG_LOG( SG_TERRAIN, SG_DEBUG, "FREEING CACHE ENTRY = " << tile_index );
55 TileEntry *tile = tile_cache[tile_index];
57 tile_cache.erase( tile_index );
58 delete tile;
59}
60
61
62// Initialize the tile cache subsystem
63void TileCache::init( void ) {
64 SG_LOG( SG_TERRAIN, SG_INFO, "Initializing the tile cache." );
65
66 SG_LOG( SG_TERRAIN, SG_INFO, " max cache size = "
67 << max_cache_size );
68 SG_LOG( SG_TERRAIN, SG_INFO, " current cache size = "
69 << tile_cache.size() );
70
72
73 SG_LOG( SG_TERRAIN, SG_INFO, " done with init()" );
74}
75
76
77// Search for the specified "bucket" in the cache
78bool TileCache::exists_stg( const SGBucket& b ) const {
79 long tile_index = b.gen_index();
80 const_tile_map_iterator it = tile_cache.find( tile_index );
81
82 return ( it != tile_cache.end() );
83}
84
85bool TileCache::exists_vpb( const SGBucket& b ) const {
86 // VPB tiles are stored with negative index to avoid clash with STG index
87 long tile_index = - b.gen_vpb_index();
88 const_tile_map_iterator it = tile_cache.find( tile_index );
89
90 return ( it != tile_cache.end() );
91}
92
93
94// Return the index of a tile to be dropped from the cache, return -1 if
95// nothing available to be removed.
97 long min_index = -1;
98 double min_time = DBL_MAX;
99 float priority = FLT_MAX;
100
101 tile_map_iterator current = tile_cache.begin();
102 tile_map_iterator end = tile_cache.end();
103
104 for ( ; current != end; ++current ) {
105 long index = current->first;
106 TileEntry *e = current->second;
107 if (( !e->is_current_view() )&&
108 ( e->is_expired(current_time) ))
109 {
110 if (e->is_expired(current_time - 1.0)&&
111 !e->is_loaded())
112 {
113 /* Immediately drop "empty" tiles which are no longer used/requested, and were last requested > 1 second ago...
114 * Allow a 1 second timeout since an empty tiles may just be loaded...
115 */
116 SG_LOG( SG_TERRAIN, SG_DEBUG, " dropping an unused and empty tile");
117 min_index = index;
118 break;
119 }
120 if (( e->get_time_expired() < min_time )||
121 (( e->get_time_expired() == min_time)&&
122 ( priority > e->get_priority())))
123 {
124 // drop oldest tile with lowest priority
125 min_time = e->get_time_expired();
126 priority = e->get_priority();
127 min_index = index;
128 }
129 }
130 }
131
132 SG_LOG( SG_TERRAIN, SG_DEBUG, " index = " << min_index );
133 SG_LOG( SG_TERRAIN, SG_DEBUG, " min_time = " << min_time );
134
135 return min_index;
136}
137
139{
140 const_tile_map_iterator current = tile_cache.begin();
141 const_tile_map_iterator end = tile_cache.end();
142
143 for ( ; current != end; ++current ) {
144 TileEntry *e = current->second;
145 if (!e->is_current_view() && e->is_expired(current_time))
146 {
147 return current->first;
148 }
149 }
150
151 return -1; // no expired tile found
152}
153
154
155// Clear all flags indicating tiles belonging to the current view
157{
158 tile_map_iterator current = tile_cache.begin();
159 tile_map_iterator end = tile_cache.end();
160
161 for ( ; current != end; ++current ) {
162 TileEntry *e = current->second;
163 if (e->is_current_view())
164 {
165 // update expiry time for tiles belonging to most recent position
166 e->update_time_expired( current_time );
167 e->set_current_view( false );
168 }
169 }
170}
171
172// Clear a cache entry, note that the cache only holds pointers
173// and this does not free the object which is pointed to.
174void TileCache::clear_entry( long tile_index ) {
175 tile_cache.erase( tile_index );
176}
177
178
179// Clear all completely loaded tiles (ignores partially loaded tiles)
181 std::vector<long> indexList;
182 tile_map_iterator current = tile_cache.begin();
183 tile_map_iterator end = tile_cache.end();
184
185 for ( ; current != end; ++current ) {
186 long index = current->first;
187 TileEntry *e = current->second;
188 if ( e->is_loaded() ) {
189 e->tile_bucket.make_bad();
190 // entry_free modifies tile_cache, so store index and call entry_free() later;
191 indexList.push_back( index);
192 }
193 }
194 for (unsigned int it = 0; it < indexList.size(); it++) {
195 entry_free( indexList[ it]);
196 }
197}
198
203 // register tile in the cache
204 long tile_index = e->get_tile_bucket().gen_index();
205 tile_cache[tile_index] = e;
206 e->update_time_expired(current_time);
207
208 return true;
209}
210
215 // register tile in the cache
216 long tile_index = - e->get_tile_bucket().gen_vpb_index();
217 tile_cache[tile_index] = e;
218 e->update_time_expired(current_time);
219
220 return true;
221}
222
223
224// update tile's priority and expiry time according to current request
225void TileCache::request_tile(TileEntry* t,float priority,bool current_view,double request_time)
226{
227 if ((!current_view)&&(request_time<=0.0))
228 return;
229
230 // update priority when higher - or old request has expired
231 if ((t->is_expired(current_time))||
232 (priority > t->get_priority()))
233 {
234 t->set_priority( priority );
235 }
236
237 if (current_view)
238 {
239 t->update_time_expired( current_time + request_time );
240 t->set_current_view( true );
241 }
242 else
243 {
244 t->update_time_expired( current_time+request_time );
245 }
246}
247
248// Return a pointer to the specified tile cache entry
249STGTileEntry* TileCache::get_stg_tile( const SGBucket& b ) const {
250
251 const_tile_map_iterator it = std::find_if(tile_cache.begin(), tile_cache.end(),
252 [b](auto &t) {
253 return ((b.gen_index() == t.first) && (t.second->getExtension() == TileEntry::Extension::STG));
254 });
255 if ( it != tile_cache.end() ) {
256 return dynamic_cast<STGTileEntry*>(it->second);
257 } else {
258 return NULL;
259 }
260}
261
262// Return a pointer to the specified tile cache entry
263VPBTileEntry* TileCache::get_vpb_tile( const SGBucket& b ) const {
264 const_tile_map_iterator it = std::find_if(tile_cache.begin(), tile_cache.end(),
265 [b](auto &t) {
266 // Negative indices are used for the VPB tiles.
267 return (( - b.gen_vpb_index() == t.first) && (t.second->getExtension() == TileEntry::Extension::VPB));
268 });
269 if ( it != tile_cache.end() ) {
270 return dynamic_cast<VPBTileEntry*>(it->second);
271 } else {
272 return NULL;
273 }
274}
tile_map::const_iterator const_tile_map_iterator
Definition tilecache.hxx:37
STGTileEntry * get_stg_tile(const SGBucket &b) const
void request_tile(TileEntry *t, float priority, bool current_view, double requesttime)
tile_map_iterator end()
Definition tilecache.hxx:55
tile_map::iterator tile_map_iterator
Definition tilecache.hxx:36
void clear_current_view()
void init(void)
Definition tilecache.cxx:63
long get_first_expired_tile() const
bool exists_stg(const SGBucket &b) const
Definition tilecache.cxx:78
void clear_entry(long cache_entry)
bool exists_vpb(const SGBucket &b) const
Definition tilecache.cxx:85
void clear_cache()
long get_drop_tile()
Definition tilecache.cxx:96
VPBTileEntry * get_vpb_tile(const SGBucket &b) const
bool insert_tile(STGTileEntry *e)
Create a new tile and enqueue it for loading.
A class to encapsulate everything we need to know about a scenery tile.
Definition tileentry.hxx:53
void set_priority(float priority)
double get_time_expired() const
bool is_expired(double current_time) const
Return false if the tile entry is still needed, otherwise return true indicating that the tile is no ...
float get_priority() const
bool is_current_view() const
const SGBucket & get_tile_bucket() const
Return the "bucket" for this tile.
void set_current_view(bool current_view)
bool is_loaded() const
Return true if the tile entry is loaded, otherwise return false indicating that the loading thread is...
void removeFromSceneGraph()
disconnect terrain mesh and ground lighting nodes from scene graph for this tile.
void update_time_expired(double time_expired)
SGBucket tile_bucket
Definition tileentry.hxx:57