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-2020 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 00109 template <typename TContextedObject> 00110 SoContextedObjectCacheList : public SoBaseContextCache 00111 { 00112 public: 00113 // Constructor. 00114 // Takes the maximum number of caches to build and an 00115 // optional flag specifying to use internal mutex. 00116 // It is more efficient, and safer, for the client code 00117 // to lock its own mutex. 00118 SoContextedObjectCacheList(int numCaches = 1, bool sharable = true, SbBool useMutex = FALSE); 00119 00124 typedef struct 00125 { 00126 TContextedObject* texObj; 00127 SoDeviceContextSharedGroup* contextSharedGroup; 00128 float quality; 00129 uint64_t lastUse; 00130 } SoGLTexCacheEntry; 00131 00132 // Get the texture object for the specified context id and quality. 00133 // 00134 // Returns NULL if there is no cache for the specified context id. 00135 // Even if there is a cache, the current texObj may be NULL. 00136 // 00137 // NOTE: This method does not ref or unref the texObj. 00138 // It does increment the useCount if a cache was found. 00139 TContextedObject *getCache( SoState *state, float quality ); 00140 TContextedObject *getCache( SoDeviceContext* ctx, float quality ); 00141 00142 // Set the values in the cache for the specified context id. 00143 // If there is a cache for this context id, its values are modified. 00144 // Else if there is an unused cache entry, it becomes the cache for 00145 // this context id and its values are modified. Else the least 00146 // used cache entry (lowest useCount) is chosen and becomes the 00147 // cache for this context id. 00148 // 00149 // NOTE: The specified texObj will be ref'd and the current texObj 00150 // in the cache entry (if any) will be unref'd. A valid 00151 // SoState* should be passed if possible so texObjs can be 00152 // destroyed immediately (more efficient). 00153 void setCache( int sharedGroup, TContextedObject *texObj, 00154 float quality, SoState *state = NULL ); 00155 00156 void setCache( int sharedGroup, TContextedObject *texObj, 00157 float quality, SoState *state, TContextedObject*& oldTexObj ); 00158 00159 // Specifies that all texture caches are invalid. 00160 // This method would be called, for example, if the texture quality 00161 // or the wrap/repeat setting changes. Because there is a single 00162 // texture cache for each context id, the change invalidates all 00163 // the caches. 00164 // 00165 // NOTE: All texObj's will be unref'd. A valid SoState* should be 00166 // passed if possible so texObjs can be destroyed immediately. 00167 void invalidateAll( SoState *state = NULL ) const; 00168 00169 // Specifies that all texture caches are invalid for a specific context. 00170 // This method would be called, for example, if the texture quality 00171 // or the wrap/repeat setting changes. Because there is a single 00172 // texture cache for each context id, the change invalidates all 00173 // the caches. 00174 // 00175 // NOTE: All texObj's will be unref'd. A valid SoState* should be 00176 // passed if possible so texObjs can be destroyed immediately. 00177 bool invalidateContext( SoDeviceContextSharedGroup* ctx); 00178 00179 00180 private: 00181 00182 // Get the cache for the specified context id. 00183 // Returns NULL if there is no cache for the specified context id. 00184 // If there is a cache, the current texObj may be NULL. 00185 // 00186 // NOTE: This method does not ref or unref the texObj. 00187 // It does increment the useCount if a cache was found. 00188 SoGLTexCacheEntry *getCache( SoState *state); 00189 00190 00197 virtual void release(SoDeviceContextSharedGroup *ctx); 00198 00199 private: 00200 00202 virtual ~SoContextedObjectCacheList(); 00203 00209 virtual bool notifyDelete() const; 00210 00211 private: 00212 00213 SoGLTexCacheEntry* m_cacheList; 00214 int m_numCaches; 00215 SbThreadMutex* m_mutex; 00216 00218 bool m_sharable; 00219 00220 static int s_debugFlag; 00221 }; 00222 00223 #endif //_SO_CONTEXTED_OBJECT_CACHE_LIST_H_ 00224 00225 00226