Home || Architecture || Video Search || Visual Search || Scripts || Applications || Important Messages || OGL || Src

ImageCache.h

Go to the documentation of this file.
00001 // ImageCache should no longer be used
00002 //#ifndef MediaTable_ImageCache_h
00003 #ifdef I_REALLY_WANT_TO_USE_IMAGECACHE
00004 #define MediaTable_ImageCache_h
00005 
00006 #include "OglGui/OglImageCache.h"
00007 
00008 #include "TableDataSource.h"
00009 #include "Visualization/RgbOglImage.h"
00010 
00011 #ifdef USE_BOOST_THREADPOOL
00012 
00013 // use this version for boost v. 34 (as on UvA FC8)
00014 //#include "threadpool23/threadpool.hpp"
00015 // use this version for boost >= 37 (as on other machines)
00016 #include "threadpool25/threadpool.hpp"
00017 
00018 #endif
00019 
00020 
00021 namespace Impala {
00022 namespace Application {
00023 namespace MediaTable {
00024 
00025 
00026 // RvB: BRAINSTORM!!
00027 //      Als we een interface meegeven met een member functie:
00028 //      OGLIMAGE* GetImageByID( String, id)
00029 //      en niet meer een source meegeven. Dan zou dit een meer algemene
00030 //      OGLIMAGE cache kunnen zijn. Preload moet er dan ook uit, maar
00031 //      kan makkelijk aan de app kant worden geimplementeerd
00032 
00033 
00034 /* A short note on how ImageCache and TableViewCache objects relate:
00035 
00036  Specifications:
00037   - there shall be only one application wide instance of an OGLIMAGE
00038     for a specified image
00039   - there may be more than one view associated with that OGLIMAGE
00040   - those views may also be cached
00041 
00042  Implementation:
00043 
00044  There is only one ImageCache instance, which handles a cached set of OGLIMAGEs
00045 
00046  For each Window where Views are needed there is one TableViewCache.
00047 
00048  TableViewCache: a cache of views with associated (refcounted) OGLIMAGE objects
00049  TableViewCache retrieves new OGLIMAGEs by asking ImageCache, which will get
00050  the image from cache if possible, or load and cache it if it's not there.
00051 
00052  ImageCache therefore keeps it's own (refcounted) set of OGLIMAGEs, which it
00053  will deref only when the cache is full.
00054 
00055  ImageCache::mCacheSize MUST BE larger than those of the largest TableViewCache.
00056 
00057  The idea is that, if a window wants to draw a specific view for an OGLIMAGE
00058  already displayed in another window, the OGLIMAGE does not get loaded twice.
00059 
00060  If a specific window scrolls trough it's own views, then those will be cached
00061  locally before it needs to revert to the global ImageCache cache.
00062 
00063  Eventually we might want to remove TableViewCache, or at least the
00064  caching bit in there
00065 
00066  Ork
00067 */
00068 
00069 class ImageCache
00070 {
00071 public:
00072     typedef Impala::Core::Array::Array2dVec3UInt8   Array2dVec3UInt8;
00073     typedef std::pair<int, OGLIMAGE*>               ImageWithID;
00074 
00075     static void InitializeCache(TableDataSource *source, int size)
00076     {
00077         if (sInstance)
00078         {
00079             ILOG_WARN("ImageCache already initialized. Skipping.");
00080             return;
00081         }
00082         sInstance = new ImageCache(source, size);
00083     }
00084 
00085     static ImageCache* GetInstance()
00086     {
00087         if (!sInstance)
00088         {
00089             ILOG_ERROR("You forgot to initialize ImageCache with a source.");
00090             return 0;
00091         }
00092         return sInstance;
00093     }
00094 
00095     // RvB: Not being used
00096     OGLIMAGE* GetImage(int id, String column)
00097     {
00098         OGLIMAGE *i = GetImageFromCache(id, column);
00099         if (!i)
00100             i = LoadImage(id, column);
00101         return i;
00102     }
00103 
00104     OGLIMAGE* GetImageFromCache(int id, String column)
00105     {
00106         /* todo:
00107         currently images are cached by row, assumption is only one image
00108         per row, we should also cache-verify the column.
00109         */
00110         for (int i=0; i<mImages.size(); i++)
00111         {
00112             if (id == mImages[i]->first) {
00113                 //ILOG_DEBUG("cache hit: " << id);
00114                 UpdateLRU(i);
00115                 return mImages[i]->second;
00116             }
00117         }
00118         return 0;
00119     }
00120 
00121 #ifndef USE_BOOST_THREADPOOL
00122     OGLIMAGE* LoadImage(int id, String column)
00123     {
00124         // image not in cache, load and place in cache:
00125         // ILOG_DEBUG("cache miss: retrieving " << id << "...");
00126         Array2dVec3UInt8* ar = mSource->GetImageDataByID(column, id);
00127         if (ar == 0)
00128             return 0;
00129 
00130         ImageWithID *p = GetLeastUsedImageFromCache();
00131         if (p->second)
00132         {
00133             ReleaseOglImage(p->second);
00134             ILOG_DEBUG("Refcount for least used image now " <<
00135                        p->second->refCount);
00136         }
00137         else
00138             ILOG_DEBUG("Cache not yet grown to max size, growing...");
00139 
00140         p->second = Visualization::RgbOglImage::OglImage(ar);
00141         p->first = id;
00142         return p->second;
00143     }
00144 #else
00145     OGLIMAGE* LoadImage(int id, String column)
00146     {
00147         // image not in cache, create a new dummy OGLIMAGE and place
00148         // this in the cache, and start a worker thread to load the
00149         // actual image, which will flip the changed bit on the OGLIMAGE
00150         // so OGL redraws it.
00151 
00152         // ILOG_DEBUG("cache miss: retrieving " << id << "...");
00153 
00154         ImageWithID *p = GetLeastUsedImageFromCache();
00155         if (p->second)
00156         {
00157             ReleaseOglImage(p->second);
00158             ILOG_DEBUG("Refcount for least used image now " <<
00159                        p->second->refCount);
00160         }
00161         else
00162             ILOG_DEBUG("Cache not yet grown to max size, growing...");
00163 
00164         p->second = Visualization::RgbOglImage::OglImage(mEmptyArray);
00165         p->first = id;
00166 
00167         // initialize and launch thread:
00168         // note: todo - upgrade this to use a threadpool instead of firing
00169         //       a new thread for every image.
00170         OglImageLoader loader(mSource, column, id, p->second);
00171         //boost::thread work(loader);
00172         mThreadPool->schedule(loader);
00173 
00174         mActiveTasks = true;
00175 
00176         return p->second;
00177     }
00178 #endif
00179 
00180 #ifndef USE_BOOST_THREADPOOL
00181     bool
00182     IsLoadingImages()
00183     {
00184         return false;
00185     }
00186 #else
00187     bool
00188     IsLoadingImages()
00189     {
00190         if (!mActiveTasks)
00191             return false;
00192 
00193         ILOG_DEBUG("TP check: Size " << mThreadPool->size() << " Active tasks " << mThreadPool->active() << " Pending tasks " << mThreadPool->pending());
00194 
00195         if (mThreadPool->active() == 0)
00196             mActiveTasks = false;
00197 
00198         return true;
00199     }
00200 #endif
00201 
00202 
00203     int GetImageCacheMaxSize()
00204     {
00205         return mCacheSize;
00206     }
00207 
00208     // speedup function which might be nice for demos:
00209     void PreloadCache()
00210     {
00211         // only works if there is one image column in the DataSource
00212         int preload = mCacheSize;
00213         if (mSource->GetTotalRows() < mCacheSize)
00214             preload = mSource->GetTotalRows();
00215         ILOG_INFO("Preloading " << preload << " images...");
00216         for (int i=0; i<preload; i++)
00217         {
00218             if (i%100==0)
00219                 ILOG_DEBUG("Preloading image " << i << " of " << preload);
00220             LoadImage(i, "");
00221         }
00222     }
00223 
00224 private:
00225     ImageCache(TableDataSource* source, int size) // constructor: private
00226     {
00227         Init(source, size);
00228     }
00229 
00230     ImageCache(ImageCache const&){};             // copy constructor: private
00231     ImageCache& operator=(ImageCache const&){};  // assignment operator: private
00232 
00233     ImageWithID* GetLeastUsedImageFromCache()
00234     {
00235         int item = mLRU.front();
00236         UpdateLRU(item);
00237         return mImages[item];
00238     }
00239 
00240     void UpdateLRU(int index)
00241     {
00242         mLRU.remove(index);
00243         mLRU.push_back(index);
00244     }
00245 
00246     void Init(TableDataSource* source, int size)
00247     {
00248         mCacheSize = size;
00249         ILOG_DEBUG("Initializing image cache for "<< mCacheSize <<" OGLIMAGEs");
00250 
00251 #ifdef USE_BOOST_THREADPOOL
00252         mEmptyArray = Core::Array::ArrayCreate<Core::Array::Array2dVec3UInt8>(0, 0, 0, 0);
00253         // Initialize threadpool with single thread
00254         mThreadPool = new boost::threadpool::pool(1);
00255         if(source->MultiThreadImageCacheSupported)
00256                 mThreadPool->size_controller().resize(8);
00257         mActiveTasks = false;
00258 #endif
00259 
00260         mSource = source;
00261 
00262         for (int i=0; i<mCacheSize; i++)
00263         {
00264             mImages.push_back(new ImageWithID(-1, 0));
00265             mLRU.push_back(i);
00266         }
00267     }
00268 
00269 #ifdef USE_BOOST_THREADPOOL
00270     class OglImageLoader {
00271         public:
00272             OglImageLoader(TableDataSource *s, std::string column, int row, OGLIMAGE *result)
00273             {
00274                 mSource = s;
00275                 mColumn = column;
00276                 mRow = row;
00277                 mImage = result;
00278             }
00279 
00280         void operator()() {
00281             ILOG_DEBUG("Worker thread retrieving " << mColumn << "x" << mRow);
00282             LoadImage();
00283         }
00284 
00285         int LoadImage()
00286         {
00287             Array2dVec3UInt8* ar = mSource->GetImageDataByID(mColumn, mRow);
00288             if (ar == 0)
00289                 return 0;
00290 
00291             // delay loop for testing:
00292 /*            boost::xtime xt;
00293             boost::xtime_get(&xt, boost::TIME_UTC);
00294             xt.nsec += 250 * 100000 * 4;
00295             boost::thread::sleep(xt);
00296 */
00297 
00298             mImage->imageHandle = ar;
00299             mImage->h = ar->CH();
00300             mImage->w = ar->CW();
00301             mImage->changed = 1;
00302             ILOG_DEBUG("Loaded image " << mColumn << "x" << mRow << " as " << mImage->w << "x" << mImage->h <<" pixels in " << mImage);
00303 
00304             return 1;
00305         }
00306 
00307         private:
00308         TableDataSource *mSource;
00309         std::string      mColumn;
00310         int              mRow;
00311         OGLIMAGE*        mImage;
00312     };
00313 #endif
00314 
00315 
00316     int                         mCacheSize;
00317 
00318     std::list<int>              mLRU;
00319     std::vector<ImageWithID*>   mImages;
00320     TableDataSource*            mSource;
00321 
00322     static ImageCache*          sInstance;
00323 
00324 #ifdef USE_BOOST_THREADPOOL
00325     Core::Array::Array2dVec3UInt8* mEmptyArray;
00326     boost::threadpool::pool     *mThreadPool;
00327     bool                         mActiveTasks;
00328 #endif
00329 
00330     ILOG_VAR_DEC;
00331 };
00332 
00333 ImageCache* ImageCache::sInstance = 0;
00334 
00335 ILOG_VAR_INIT(ImageCache, Application.MediaTable);
00336 
00337 } // namespace MediaTable
00338 } // namespace Application
00339 } // namespace Impala
00340 #endif // ImageCache_h

Generated on Fri Mar 19 09:30:31 2010 for ImpalaSrc by  doxygen 1.5.1