00001 /*======================================================================= 00002 *** THE CONTENT OF THIS WORK IS PROPRIETARY TO FEI S.A.S, (FEI S.A.S.), *** 00003 *** AND IS DISTRIBUTED UNDER A LICENSE AGREEMENT. *** 00004 *** *** 00005 *** REPRODUCTION, DISCLOSURE, OR USE, IN WHOLE OR IN PART, OTHER THAN AS *** 00006 *** SPECIFIED IN THE LICENSE ARE NOT TO BE UNDERTAKEN EXCEPT WITH PRIOR *** 00007 *** WRITTEN AUTHORIZATION OF FEI S.A.S. *** 00008 *** *** 00009 *** RESTRICTED RIGHTS LEGEND *** 00010 *** USE, DUPLICATION, OR DISCLOSURE BY THE GOVERNMENT OF THE CONTENT OF THIS *** 00011 *** WORK OR RELATED DOCUMENTATION IS SUBJECT TO RESTRICTIONS AS SET FORTH IN *** 00012 *** SUBPARAGRAPH (C)(1) OF THE COMMERCIAL COMPUTER SOFTWARE RESTRICTED RIGHT *** 00013 *** CLAUSE AT FAR 52.227-19 OR SUBPARAGRAPH (C)(1)(II) OF THE RIGHTS IN *** 00014 *** TECHNICAL DATA AND COMPUTER SOFTWARE CLAUSE AT DFARS 52.227-7013. *** 00015 *** *** 00016 *** COPYRIGHT (C) 1996-2014 BY FEI S.A.S, *** 00017 *** BORDEAUX, FRANCE *** 00018 *** ALL RIGHTS RESERVED *** 00019 **=======================================================================*/ 00020 /*======================================================================= 00021 ** Author : mmh * (MMM yyyy) 00022 **=======================================================================*/ 00023 00024 #ifndef _SO_CONTEXTED_OBJECT_CACHE_LIST_H_ 00025 #define _SO_CONTEXTED_OBJECT_CACHE_LIST_H_ 00026 00028 // 00029 // SoContextedObjectCacheList 00030 // This class has some similarities to SoGLCacheList, which manages render 00031 // caches (OpenGL display lists), but is significantly different because: 00032 // 00033 // 1) Texture caches (OpenGL texture objects) only depend on the OpenGL render 00034 // context (identified by cachectxSharedId in Inventor) and texture quality. 00035 // Render caches depend on a large number of traversal state elements 00036 // (including cachectxSharedId). In fact SoGLCacheList is able to maintain 00037 // multiple render caches (with different attribute settings) for the same 00038 // cachectxSharedId. For texture caches we do not need this complexity, so 00039 // we only maintain a single texture cache for each cachectxSharedId. 00040 // 00041 // 2) Texture nodes already have a slightly complicated relationship with the 00042 // SoGLTextureImageElement, where the element creates the texture object, 00043 // but the node stores the address of the object for later re-use. 00044 // SoGLCacheList, on the other hand, is relatively self-contained. It is 00045 // responsible for creating, using and destroying render caches and looks 00046 // more like a "black box" to Separator (etc) nodes. SoContextedObjectCacheList is 00047 // more of a "helper" class that does some bookkeeping for the client node. 00048 // It will generally be safer and more efficient for the client node to 00049 // lock its own mutex, but we have provided an optional internal mutex. 00050 // 00051 // 3) Texture caches are used in a different way than render caches. A "call" 00052 // of a render cache (glCallList) is a somewhat atomic operation. We must 00053 // ensure the display list continues to exist until glCallList returns, 00054 // but after that it could be destroyed. A texture cache is put into the 00055 // traversal state and must continue to exist until its TextureImageElement 00056 // is popped off the stack. We don't know what other geometry the texture 00057 // might apply to. To ensure this happens safely with multiple threads we 00058 // modified TextureImageElement to ref and unref the texture object. 00059 // 00060 // The number of texture caches that are required depends on the number of 00061 // graphics pipes that the application will use. However, it specifically 00062 // depends on the number of different cachectxSharedIds. So if all the pipes 00063 // can share texture objects, they can (and should) all use the same 00064 // cachectxSharedId, and only one texture cache is required. If the pipes 00065 // cannot share texture objects (eg. on SGI hardware), then they should each 00066 // use a different cachectxSharedId and the number of texture caches should be 00067 // equal to or greater than the number of pipes. The number of caches can be 00068 // set for both render and texture caches using SoDB::setNumRenderCaches. 00069 // 00070 // There are two cases that should account for 99% of the usage: 00071 // 00072 // Case 1: Classic single pipe Open Inventor program 00073 // 00074 // The effective behavior in this case should be the same as before. 00075 // Typically the program will only have one cachectxSharedId value (even 00076 // if it uses multiple Open Inventor windows), so only one texture cache 00077 // is needed. If the texture quality changes, the texture node will create 00078 // a new texture object and call setCache, but the cachectxSharedId will be 00079 // the same so the existing entry will be re-used. 00080 // 00081 // Case 2: Multi-pipe Open Inventor program 00082 // 00083 // Typically each pipe will have a different cachectxSharedId, but once 00084 // the pipes are set up, the cachectxSharedIds will remain the same until 00085 // the program exits. There are should be as many texture caches as 00086 // there are pipes and each cachectxSharedId will have its own cache (and 00087 // its own texture object). If the texture quality changes, the texture 00088 // node will create a new texture object and call setCache in each render 00089 // thread, but the cachectxSharedId is the same for each thread, so the 00090 // existing entry will be re-used. 00091 // 00092 // In the unlikely, but possible, case that there are more cachectxSharedId 00093 // values than there are texture caches, the SoContextedObjectCacheList will choose 00094 // an existing cache entry to "clobber". This is based on a useCount to 00095 // encourage clobbering the least used cache entry. However it is likely 00096 // that in this case the cache list will be "thrashing", clobbering and 00097 // re-using the same cache entry over and over. This is not good, but no 00098 // worse than the behavior in the 3.0 (and older) code. :-) 00099 // 00101 00102 #include <Inventor/SbBasic.h> 00103 #include <Inventor/helpers/SbGlContextHelper.h> 00104 #include <Inventor/caches/SoBaseContextCache.h> 00105 00106 class SoState; 00107 class SoDeviceContext; 00108 // Base class that implements the common cache functions. 00109 00110 00111 { 00112 private: 00113 SoBaseContextedObjectCacheList(int numCaches = 1, bool sharable = true, SbBool useMutex = FALSE); 00118 typedef struct 00119 { 00120 void* texObj; 00121 SoDeviceContextSharedGroup* contextSharedGroup; 00122 float quality; 00123 uint64_t lastUse; 00124 } SoGLTexCacheEntry; 00125 00126 void *getCache( SoState *state, float quality ); 00127 void *getCache( SoDeviceContext* ctx, float quality ); 00128 00129 void setCache( int sharedGroup, void *texObj, 00130 float quality, SoState *state = NULL ); 00131 00132 void setCache( int sharedGroup, void *texObj, 00133 float quality, SoState *state, void*& oldTexObj ); 00134 public: 00135 // Specifies that all texture caches are invalid. 00136 // This method would be called, for example, if the texture quality 00137 // or the wrap/repeat setting changes. Because there is a single 00138 // texture cache for each context id, the change invalidates all 00139 // the caches. 00140 // 00141 // NOTE: All texObj's will be unref'd. A valid SoState* should be 00142 // passed if possible so texObjs can be destroyed immediately. 00143 void invalidateAll( SoState *state = NULL ) const; 00144 00145 // Specifies that all texture caches are invalid for a specific context. 00146 // This method would be called, for example, if the texture quality 00147 // or the wrap/repeat setting changes. Because there is a single 00148 // texture cache for each context id, the change invalidates all 00149 // the caches. 00150 // 00151 // NOTE: All texObj's will be unref'd. A valid SoState* should be 00152 // passed if possible so texObjs can be destroyed immediately. 00153 bool invalidateContext( SoDeviceContextSharedGroup* ctx); 00154 00155 private: 00156 // Get the cache for the specified context id. 00157 // Returns NULL if there is no cache for the specified context id. 00158 // If there is a cache, the current texObj may be NULL. 00159 // 00160 // NOTE: This method does not ref or unref the texObj. 00161 // It does increment the useCount if a cache was found. 00162 SoGLTexCacheEntry *getCache( SoState *state); 00163 00164 private: 00165 00172 virtual void release(SoDeviceContextSharedGroup *ctx); 00173 00174 private: 00175 00177 virtual ~SoBaseContextedObjectCacheList(); 00178 00184 virtual bool notifyDelete() const; 00185 00187 virtual void refObject(void *obj) const = 0; 00188 virtual void unrefObject(void *obj) const = 0; 00189 00190 private: 00191 00192 SoGLTexCacheEntry* m_cacheList; 00193 int m_numCaches; 00194 SbThreadMutex* m_mutex; 00195 00197 bool m_sharable; 00198 00199 static int s_debugFlag; 00200 }; 00201 00202 template <typename TContextedObject> 00203 00204 { 00205 public: 00206 // Constructor. 00207 // Takes the maximum number of caches to build and an 00208 // optional flag specifying to use internal mutex. 00209 // It is more efficient, and safer, for the client code 00210 // to lock its own mutex. 00211 SoContextedObjectCacheList(int numCaches = 1, bool sharable = true, SbBool useMutex = FALSE) 00212 : SoBaseContextedObjectCacheList(numCaches, sharable, useMutex) 00213 { 00214 } 00215 00216 // Get the texture object for the specified context id and quality. 00217 // 00218 // Returns NULL if there is no cache for the specified context id. 00219 // Even if there is a cache, the current texObj may be NULL. 00220 // 00221 // NOTE: This method does not ref or unref the texObj. 00222 // It does increment the useCount if a cache was found. 00223 TContextedObject *getCache( SoState *state, float quality ) 00224 { 00225 return static_cast<TContextedObject*>(SoBaseContextedObjectCacheList::getCache(state, quality)); 00226 } 00227 00228 TContextedObject *getCache( SoDeviceContext* ctx, float quality ) 00229 { 00230 return static_cast<TContextedObject*>(SoBaseContextedObjectCacheList::getCache(ctx, quality)); 00231 } 00232 00233 // Get a texture object for the specified context id. 00234 // Returns false if there is no cache for the specified context id. 00235 // If there is a cache, the current texObj may be NULL. 00236 // 00237 // NOTE: This method does not ref or unref the texObj. 00238 // It does increment the useCount if a cache was found. 00239 bool getCache( SoState *state, TContextedObject*& texObj) 00240 { 00241 texObj = NULL; 00242 SoGLTexCacheEntry *entry = SoBaseContextedObjectCacheList::getCache(state); 00243 if (entry == NULL) 00244 return false; 00245 texObj = static_cast<TContextedObject*>(entry->texObj); 00246 return true; 00247 } 00248 00249 // Set the values in the cache for the specified context id. 00250 // If there is a cache for this context id, its values are modified. 00251 // Else if there is an unused cache entry, it becomes the cache for 00252 // this context id and its values are modified. Else the least 00253 // used cache entry (lowest useCount) is chosen and becomes the 00254 // cache for this context id. 00255 // 00256 // NOTE: The specified texObj will be ref'd and the current texObj 00257 // in the cache entry (if any) will be unref'd. A valid 00258 // SoState* should be passed if possible so texObjs can be 00259 // destroyed immediately (more efficient). 00260 void setCache( int sharedGroup, TContextedObject *texObj, 00261 float quality, SoState *state = NULL ) 00262 { 00263 SoBaseContextedObjectCacheList::setCache(sharedGroup, texObj, quality, state); 00264 } 00265 00266 void setCache( int sharedGroup, TContextedObject *texObj, 00267 float quality, SoState *state, TContextedObject*& oldTexObj ) 00268 { 00269 void* oldObj; 00270 SoBaseContextedObjectCacheList::setCache(sharedGroup, texObj, quality, state, oldObj); 00271 oldTexObj = static_cast<TContextedObject*>(oldObj); 00272 } 00273 00274 private: 00275 00277 virtual ~SoContextedObjectCacheList() { invalidateAll(); } 00278 00279 virtual void refObject(void *obj) const 00280 { 00281 if (obj) 00282 static_cast<TContextedObject*>(obj)->ref(); 00283 } 00284 00285 virtual void unrefObject(void *obj) const 00286 { 00287 if (obj) 00288 static_cast<TContextedObject*>(obj)->unref(); 00289 } 00290 }; 00291 #endif //_SO_CONTEXTED_OBJECT_CACHE_LIST_H_ 00292 00293 00294