1 /**************************************************************************\
2  * Copyright (c) Kongsberg Oil & Gas Technologies AS
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are
7  * met:
8  *
9  * Redistributions of source code must retain the above copyright notice,
10  * this list of conditions and the following disclaimer.
11  *
12  * Redistributions in binary form must reproduce the above copyright
13  * notice, this list of conditions and the following disclaimer in the
14  * documentation and/or other materials provided with the distribution.
15  *
16  * Neither the name of the copyright holder nor the names of its
17  * contributors may be used to endorse or promote products derived from
18  * this software without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24  * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 \**************************************************************************/
32 
33 /*!
34   \class SoGLCacheList include/Inventor/caches/SoGLCacheList.h
35   \brief The SoGLCacheList class is used to store and manage OpenGL caches.
36 
37   \ingroup caches
38 */
39 
40 #include <Inventor/caches/SoGLCacheList.h>
41 
42 #ifdef HAVE_CONFIG_H
43 #include <config.h>
44 #endif // HAVE_CONFIG_H
45 
46 #include <Inventor/C/tidbits.h>
47 #include <Inventor/actions/SoGLRenderAction.h>
48 #include <Inventor/caches/SoGLRenderCache.h>
49 #include <Inventor/elements/SoCacheElement.h>
50 #include <Inventor/elements/SoGLCacheContextElement.h>
51 #include <Inventor/elements/SoGLLazyElement.h>
52 #include <Inventor/elements/SoShapeStyleElement.h>
53 #include <Inventor/errors/SoDebugError.h>
54 #include <Inventor/misc/SoState.h>
55 #include <Inventor/misc/SoContextHandler.h>
56 #include <Inventor/system/gl.h>
57 
58 #include "tidbitsp.h"
59 #include "glue/glp.h"
60 #include "rendering/SoGL.h"
61 
62 // *************************************************************************
63 
64 // SGI Inventor uses an LRU/MRU strategy or something here. We're not
65 // quite sure we should support multiple caches per SoSeparator
66 // though. After all, there is some overhead in cheching for valid
67 // caches etc. If a situation occurs where multiple caches would help
68 // the performance, the user should probably redesign the scene graph
69 // and enable caching further down the scene graph instead. We will
70 // store at least one cache per cache context to support rendering in
71 // multiple contexts though.
72 
73 static int COIN_AUTO_CACHING = -1;
74 static int COIN_SMART_CACHING = -1;
75 
76 // *************************************************************************
77 
78 class SoGLCacheListP {
79 public:
80   SbList <SoGLRenderCache *> itemlist;
81   int numcaches;
82   SoGLRenderCache * opencache;
83   SbBool savedinvalid;
84   int autocachebits;
85   int numused;
86   int numdiscarded;
87   SbBool needclose;
88   SoElement * invalidelement;
89   int numframesok;
90   int numshapes;
91 
92   //
93   // Callback from SoContextHandler
94   //
contextCleanup(uint32_t context,void * closure)95   static void contextCleanup(uint32_t context, void * closure) {
96     SoGLCacheListP * thisp = static_cast<SoGLCacheListP *>(closure);
97 
98     int i = 0;
99     int n = thisp->itemlist.getLength();
100     while (i < n) {
101       if (thisp->itemlist[i]->getCacheContext() == static_cast<int>(context)) {
102         thisp->itemlist[i]->unref();
103         thisp->itemlist.remove(i);
104         n--;
105       }
106       else i++;
107     }
108   }
109 };
110 
111 #define PRIVATE(obj) ((obj)->pimpl)
112 
113 // *************************************************************************
114 
115 /*!
116   Constructor.
117 */
SoGLCacheList(int numcaches)118 SoGLCacheList::SoGLCacheList(int numcaches)
119 {
120   PRIVATE(this) = new SoGLCacheListP;
121   PRIVATE(this)->numcaches = numcaches;
122   PRIVATE(this)->opencache = NULL;
123   PRIVATE(this)->autocachebits = 0;
124   PRIVATE(this)->numused = 0;
125   PRIVATE(this)->numdiscarded = 0;
126   PRIVATE(this)->needclose = FALSE;
127   PRIVATE(this)->invalidelement = NULL;
128   PRIVATE(this)->numframesok = 0;
129   PRIVATE(this)->numshapes = 0;
130 
131   // auto caching must be enabled using an environment variable
132   if (COIN_AUTO_CACHING < 0) {
133     const char * env = coin_getenv("COIN_AUTO_CACHING");
134     if (env) COIN_AUTO_CACHING = atoi(env);
135     else COIN_AUTO_CACHING = 1;
136   }
137   if (COIN_SMART_CACHING < 0) {
138     const char * env = coin_getenv("COIN_SMART_CACHING");
139     if (env) COIN_SMART_CACHING = atoi(env);
140     else COIN_SMART_CACHING = 0;
141   }
142 
143   SoContextHandler::addContextDestructionCallback(SoGLCacheListP::contextCleanup, PRIVATE(this));
144 
145 #if COIN_DEBUG
146   if (coin_debug_caching_level() > 0) {
147     SoDebugError::postInfo("SoGLCacheList::SoGLCacheList",
148                            "Cache list created: %p", this);
149   }
150 #endif // debug
151 }
152 
153 /*!
154   Destructor. Frees remaining caches.
155 */
~SoGLCacheList()156 SoGLCacheList::~SoGLCacheList()
157 {
158 #if COIN_DEBUG
159   if (coin_debug_caching_level() > 0) {
160     SoDebugError::postInfo("SoGLCacheList::~SoGLCacheList",
161                            "Cache list destructed: %p", this);
162   }
163 #endif // debug
164 
165   SoContextHandler::removeContextDestructionCallback(SoGLCacheListP::contextCleanup, PRIVATE(this));
166   const int n = PRIVATE(this)->itemlist.getLength();
167   for (int i = 0; i < n; i++) {
168     PRIVATE(this)->itemlist[i]->unref();
169   }
170   delete PRIVATE(this);
171 }
172 
173 /*!
174   Test for valid cache and execute. Returns TRUE if a valid cache
175   could be found, FALSE otherwise. Note that when a valid cache is
176   found, it is executed before returning from this method.
177 */
178 SbBool
call(SoGLRenderAction * action)179 SoGLCacheList::call(SoGLRenderAction * action)
180 {
181   // do a quick return if there are no caches in the list
182   int n = PRIVATE(this)->itemlist.getLength();
183   if (n == 0) return FALSE;
184 
185   int i;
186   SoState * state = action->getState();
187   int context = SoGLCacheContextElement::get(state);
188 
189   for (i = 0; i < n; i++) {
190     SoGLRenderCache * cache = PRIVATE(this)->itemlist[i];
191     if (cache->getCacheContext() == context) {
192       if (cache->isValid(state) &&
193           SoGLLazyElement::preCacheCall(state, cache->getPreLazyState())) {
194         cache->ref();
195         // move cache to the end of the list. The MRU cache will be at
196         // the end of the list, and the LRU will be the first
197         // item. This makes it easy to choose a cache to destroy when
198         // the maximum number of caches is exceeded.
199         PRIVATE(this)->itemlist.remove(i);
200         PRIVATE(this)->itemlist.append(cache);
201         // update lazy GL state before calling cache
202         SoGLLazyElement::getInstance(state)->send(state, SoLazyElement::ALL_MASK);
203         cache->call(state);
204         SoGLLazyElement::postCacheCall(state, cache->getPostLazyState());
205         cache->unref(state);
206         PRIVATE(this)->numused++;
207 
208 #if COIN_DEBUG
209         // The GL error test is default disabled for this optimized
210         // path.  If you get a GL error report somewhere else, enable
211         // this code by setting the environment variable
212         // COIN_GLERROR_DEBUGGING to "1" to see if the error comes
213         // only after invoking a GL renderlist.
214         //
215         // We've seen this happen, which is peculiar -- as the same
216         // OpenGL commands are sent when _building_ a cache. This
217         // makes it likely that such problems are due to faulty GL
218         // drivers.
219         //
220         // If this happens, try to set IV_SEPARATOR_MAX_CACHES=0 to
221         // check if the GL error is still present even when not using
222         // GL displaylists.
223 
224         static SbBool chkglerr = sogl_glerror_debugging();
225         if (chkglerr) {
226           GLenum err = glGetError();
227           if (err != GL_NO_ERROR) {
228             SoDebugError::post("SoGLCacheList::call",
229                                "An OpenGL error (%s) was detected after a "
230                                "renderlist invocation. This shouldn't happen, "
231                                "low-level debugging is needed.",
232                                coin_glerror_string(err));
233           }
234         }
235 
236         // For reference, below follows an example case we've had
237         // reported. The iv-file of a NURBS surface is compiled to a
238         // displaylist and then later rendered -- at which point the
239         // GL error occurs (at least on Linux NVidia driver 1.4.0
240         // v41.92, with a GeForce2 MX/MX 400 card, and GLU 1.3):
241         //
242         // -----8<---- [snip] ------------------8<---- [snip] -------------
243         // #Inventor V2.1 ascii
244         //
245         //  Separator {
246         //   # renderCaching OFF
247         //
248         //   Coordinate3 {
249         //      point [ 903.23315 -292.8786 -261.79764,
250         //       908.05878 -287.45178 -264.75046,
251         //       932.02802 -260.18256 -279.56335,
252         //       978.21088 -204.28212 -309.72232,
253         //       1038.9332 -123.09545 -352.78091,
254         //       1099.2452 -32.638832 -398.98602,
255         //       1155.6702 60.612404 -445.20407,
256         //       1208.1346 156.64369 -490.58151,
257         //       1255.5405 256.13852 -533.99921,
258         //       1298.7241 358.22876 -575.7113,
259         //       1338.1451 462.37573 -615.54578,
260         //       1374.2526 568.28442 -653.367,
261         //       1407.7961 675.52026 -689.0874,
262         //       1439.4993 783.82806 -722.55426,
263         //       1470.3623 892.81433 -753.58435,
264         //       1501.3269 1002.2544 -781.97571,
265         //       1533.0552 1112.0437 -807.32019,
266         //       1566.5748 1221.74 -829.26929,
267         //       1600.4281 1323.8329 -846.22614,
268         //       1634.6821 1417.2887 -858.5614,
269         //       1669.7595 1503.1974 -866.97583,
270         //       1708.3434 1587.351 -872.23059,
271         //       1743.2072 1656.661 -873.22693,
272         //       1770.4005 1706.436 -873.10114,
273         //       1780.8302 1732.8519 -873.11292,
274         //       1785.8423 1747.6866 -873.11188,
275         //       1788.0009 1755.2577 -873.11206,
276         //       1789.9299 1762.1315 -873.11212,
277         //       1790.619 1764.5847 -873.11212,
278         //       1791.3671 1767.2466 -873.11212,
279         //       1132.113 -331.08054 100.19,
280         //       1135.6515 -324.95352 97.25296,
281         //       1153.1808 -294.24207 82.499771,
282         //       1186.6023 -232.0327 52.220581,
283         //       1229.5189 -143.28535 8.486125,
284         //       1271.3019 -46.2309 -39.506714,
285         //       1309.7157 52.397884 -88.602188,
286         //       1344.9164 152.72209 -138.05904,
287         //       1375.7001 255.2583 -186.31833,
288         //       1403.3052 359.10748 -234.12572,
289         //       1428.4164 463.79761 -281.39886,
290         //       1451.5635 569.12341 -328.00269,
291         //       1473.4384 674.72479 -373.77682,
292         //       1494.7687 780.4386 -418.52753,
293         //       1516.4795 886.00763 -462.00479,
294         //       1539.5337 991.31763 -503.91452,
295         //       1565.03 1096.2451 -543.82581,
296         //       1594.3169 1200.59 -581.33673,
297         //       1626.2183 1297.343 -613.68463,
298         //       1660.5347 1385.8333 -640.45953,
299         //       1696.7892 1468.0754 -662.0108,
300         //       1736.037 1549.4417 -680.32446,
301         //       1772.6567 1617.9526 -690.63373,
302         //       1801.2168 1667.5009 -696.81317,
303         //       1813.1285 1694.1454 -699.78467,
304         //       1818.9022 1709.0796 -701.36713,
305         //       1821.4705 1716.6644 -702.13947,
306         //       1823.7567 1723.4873 -702.80975,
307         //       1824.947 1726.8236 -703.06512,
308         //       1826.005 1729.8676 -703.3371,
309         //       1669.9569 -134.57997 685.43207,
310         //       1670.6903 -127.96127 682.6673,
311         //       1674.222 -94.879944 668.75208,
312         //       1679.8473 -28.921362 639.92487,
313         //       1684.1995 62.855659 597.63171,
314         //       1685.0945 160.19362 549.54291,
315         //       1682.697 256.28564 498.31042,
316         //       1677.2521 351.04462 443.96701,
317         //       1668.3485 445.28925 388.77441,
318         //       1657.3577 537.88531 330.87088,
319         //       1645.3646 628.60516 269.94531,
320         //       1633.4319 717.65143 206.03265,
321         //       1622.6926 805.24896 139.51292,
322         //       1614.3499 891.79755 70.902924,
323         //       1609.6595 977.73431 1.0185061,
324         //       1609.9548 1063.6471 -68.94474,
325         //       1616.9481 1150.0125 -137.41048,
326         //       1632.2463 1237.3811 -202.65694,
327         //       1655.1542 1320.0626 -258.95587,
328         //       1684.144 1398.2058 -303.29956,
329         //       1717.3192 1471.9259 -339.8316,
330         //       1754.276 1544.7949 -373.89639,
331         //       1790.1226 1608.4249 -392.34088,
332         //       1818.5092 1652.6719 -406.02744,
333         //       1831.3823 1676.9386 -411.69763,
334         //       1837.6758 1690.8813 -414.05777,
335         //       1840.4863 1697.9987 -415.05069,
336         //       1842.9985 1704.1809 -416.19083,
337         //       1844.6373 1707.9203 -417.28,
338         //       1845.9977 1710.9867 -418.20154,
339         //       2069.9097 242.0858 906.90302,
340         //       2069.2424 248.42937 904.83679,
341         //       2065.7732 280.12646 894.45093,
342         //       2057.533 343.20288 873.18823,
343         //       2042.7882 430.5639 842.27533,
344         //       2023.3832 522.88196 807.67621,
345         //       2000.5902 613.83093 771.46381,
346         //       1974.8794 703.67169 734.07739,
347         //       1945.7719 792.84912 697.26788,
348         //       1914.0753 880.31677 659.28027,
349         //       1880.3435 965.80292 619.60999,
350         //       1845.2063 1049.0941 577.67804,
351         //       1809.3909 1130.0742 532.95233,
352         //       1773.8319 1208.6254 484.89426,
353         //       1739.6515 1284.7078 432.93884,
354         //       1708.3459 1358.2207 376.54547,
355         //       1682.0516 1428.9958 315.14639,
356         //       1663.5428 1496.6219 248.10159,
357         //       1656.6949 1556.2395 180.31561,
358         //       1661.3206 1607.5529 113.77404,
359         //       1676.8506 1652.9681 53.936939,
360         //       1704.0085 1694.6982 -3.7455604,
361         //       1735.9509 1727.7632 -47.178341,
362         //       1761.9692 1748.0847 -74.126205,
363         //       1775.2965 1759.4961 -87.802773,
364         //       1782.5793 1767.0847 -95.980415,
365         //       1785.7794 1771.2867 -100.05127,
366         //       1788.3989 1774.8469 -103.15611,
367         //       1789.7174 1776.8969 -104.41734,
368         //       1790.9209 1778.8102 -105.47821,
369         //       2222.7271 411.91647 967.50342,
370         //       2221.5823 418.09232 965.73175,
371         //       2215.7292 448.95306 956.83862,
372         //       2202.7493 510.36282 938.77655,
373         //       2181.4448 595.32751 912.65607,
374         //       2154.9297 685.08112 883.66913,
375         //       2124.8262 773.51117 853.56708,
376         //       2091.6328 861.00134 822.78912,
377         //       2054.9531 947.84894 792.92444,
378         //       2015.2894 1033.0553 762.18048,
379         //       1972.9683 1116.3486 729.94928,
380         //       1928.47 1197.3641 695.45129,
381         //       1882.3811 1275.8629 657.84155,
382         //       1835.5389 1351.5306 616.25537,
383         //       1789.0238 1424.126 569.69537,
384         //       1744.4063 1493.2378 517.13385,
385         //       1703.903 1558.3778 457.39859,
386         //       1670.7245 1618.5844 389.28601,
387         //       1650.7424 1669.1328 317.68442,
388         //       1644.5143 1709.2839 244.88469,
389         //       1652.0626 1742.5808 179.06244,
390         //       1674.8881 1770.8495 115.97897,
391         //       1705.0859 1789.989 67.866989,
392         //       1729.8898 1799.4652 38.898201,
393         //       1743.2585 1804.8577 23.995186,
394         //       1750.9772 1809.3849 14.711536,
395         //       1754.3555 1812.1666 9.9977341,
396         //       1757.0004 1814.4926 6.5047188,
397         //       1758.0509 1815.6334 5.3017998,
398         //       1759.1072 1816.9659 4.2506523 ]
399         //   }
400         //   NurbsSurface {
401         //      numUControlPoints 30
402         //      numVControlPoints 5
403         //      uKnotVector [ 0, 0, 0, 0,
404         //       21.313433, 106.60825, 213.3829, 320.27795,
405         //       427.2619, 534.72577, 642.35693, 749.87128,
406         //       857.28058, 964.53094, 1071.6017, 1178.4491,
407         //       1285.0381, 1391.3175, 1497.1958, 1602.6195,
408         //       1707.5751, 1791.2139, 1873.9054, 1956.2173,
409         //       2037.5988, 2079.2507, 2100.7368, 2111.6772,
410         //       2121.9106, 2122.1035, 2129.9102, 2129.9102,
411         //       2129.9102, 2129.9102 ]
412         //      vKnotVector [ 0, 0, 0, 0,
413         //       871.44604, 1419.9783, 1419.9783, 1419.9783,
414         //       1419.9783 ]
415         //   }
416         // }
417         // -----8<---- [snip] ------------------8<---- [snip] -------------
418         //
419         // UPDATE: the above now works without errors on my Linux dev
420         // machine with NVidia v 61.11 drivers. 20050309 mortene.
421 
422 #endif // COIN_DEBUG
423 
424         return TRUE;
425       }
426     }
427   }
428 #if COIN_DEBUG
429   if (coin_debug_caching_level() > 0) {
430     SoDebugError::postInfo("SoGLCacheList::call",
431                            "no valid cache found for %p. Node has %d caches",
432                            this, n);
433     for (i = 0; i < n; i++) {
434       SoGLRenderCache * cache = PRIVATE(this)->itemlist[i];
435       if (cache->getCacheContext() == context) {
436         SoDebugError::postInfo("SoGLCacheList::call",
437                                "cache %d isValid()? %s", i, cache->isValid(state) ? "TRUE" : "FALSE");
438         if (!cache->isValid(state)) {
439           const SoElement * elem = cache->getInvalidElement(state);
440           if (elem) {
441             SoDebugError::postInfo("SoGLCacheList::call",
442                                    "cache: %p, invalid element: %s", this,
443                                    elem->getTypeId().getName().getString());
444           }
445         }
446       }
447     }
448   }
449 #endif // debug
450   return FALSE;
451 }
452 
453 /*!
454   Start recording a new cache. Remember to call close() when you've
455   finished recording the cache.
456 
457   \sa close()
458 */
459 void
open(SoGLRenderAction * action,SbBool autocache)460 SoGLCacheList::open(SoGLRenderAction * action, SbBool autocache)
461 {
462   // needclose is used to quickly return in close()
463   if (PRIVATE(this)->numcaches == 0 || (autocache && COIN_AUTO_CACHING == 0)) {
464     PRIVATE(this)->needclose = FALSE;
465     return;
466   }
467 
468   PRIVATE(this)->needclose = TRUE;
469 
470   assert(PRIVATE(this)->opencache == NULL);
471   SoState * state = action->getState();
472 
473   // will be restored in close()
474   PRIVATE(this)->savedinvalid = SoCacheElement::setInvalid(FALSE);
475 
476   if (SoCacheElement::anyOpen(state)) return;
477 
478   SbBool shouldcreate = FALSE;
479   if (!autocache) {
480     if (PRIVATE(this)->numframesok >= 1) shouldcreate = TRUE;
481   }
482   else {
483     if (PRIVATE(this)->numframesok >= 2 &&
484         (PRIVATE(this)->autocachebits == SoGLCacheContextElement::DO_AUTO_CACHE)) {
485 
486       if (COIN_SMART_CACHING) {
487         if (PRIVATE(this)->numshapes < 2) {
488           if (PRIVATE(this)->numframesok >= 5) shouldcreate = TRUE;
489         }
490         else if (PRIVATE(this)->numshapes < 5) {
491           if (PRIVATE(this)->numframesok >= 4) shouldcreate = TRUE;
492         }
493         else if (PRIVATE(this)->numshapes < 10) {
494           if (PRIVATE(this)->numframesok >= 3) shouldcreate = TRUE;
495         }
496         else if (PRIVATE(this)->numshapes > 1000) {
497           if (PRIVATE(this)->numframesok >= 4) shouldcreate = TRUE;
498         }
499         else if (PRIVATE(this)->numshapes > 100) {
500           if (PRIVATE(this)->numframesok >= 3) shouldcreate = TRUE;
501         }
502         else {
503           shouldcreate = TRUE;
504         }
505       }
506       else {
507         shouldcreate = TRUE;
508       }
509 #if COIN_DEBUG
510       if (coin_debug_caching_level() > 0 && PRIVATE(this)->numframesok >= 2) {
511         SoDebugError::postInfo("SoGLCacheList::open",
512                                "consider cache create: %p. numframesok: %d, numused: %d, numdiscarded: %d",
513                                this, PRIVATE(this)->numframesok, PRIVATE(this)->numused, PRIVATE(this)->numdiscarded);
514       }
515 #endif // debug
516 
517     }
518   }
519 
520   if (shouldcreate && autocache) {
521     // determine if we really should create a new cache, based on numused and numdiscarded
522     double docreate = static_cast<double>(PRIVATE(this)->numframesok + PRIVATE(this)->numused);
523     double dontcreate = (PRIVATE(this)->numdiscarded);
524 
525     dontcreate *= dontcreate;
526     // we used to be more conservative here, and use dontcreate^4 to avoid
527     // recreating caches too often. However, display lists are much faster with
528     // current drivers than they used to be so we're a bit more aggressive now.
529     if (dontcreate >= docreate) shouldcreate = FALSE;
530   }
531 
532   if (shouldcreate) {
533     if (PRIVATE(this)->itemlist.getLength() >= PRIVATE(this)->numcaches) {
534       // the cache at position 0 will be the LRU cache. Remove it.
535       SoGLRenderCache * cache = PRIVATE(this)->itemlist[0];
536       cache->unref(state);
537       PRIVATE(this)->itemlist.remove(0);
538       PRIVATE(this)->numdiscarded++;
539     }
540     PRIVATE(this)->opencache = new SoGLRenderCache(state);
541     PRIVATE(this)->opencache->ref();
542     SoCacheElement::set(state, PRIVATE(this)->opencache);
543     SoGLLazyElement::beginCaching(state, PRIVATE(this)->opencache->getPreLazyState(),
544                                   PRIVATE(this)->opencache->getPostLazyState());
545     PRIVATE(this)->opencache->open(state);
546 
547     // force a dependency on the transparecy type
548     // FIXME: consider adding a new element for storing the
549     // transparency type.  The dependency tracking on the transparency
550     // type would then work automatically. pederb, 2005-02-18
551     (void) SoShapeStyleElement::get(state);
552 
553 #if COIN_DEBUG // debug
554     if (coin_debug_caching_level() > 0) {
555       SoDebugError::postInfo("SoGLCacheList::open",
556                              "trying to create cache: %p", this);
557     }
558 #endif // debug
559   }
560   PRIVATE(this)->autocachebits = SoGLCacheContextElement::resetAutoCacheBits(state);
561   PRIVATE(this)->numshapes = 0;
562 }
563 
564 /*!
565   Finish recording the currently open cache.
566   \sa open()
567  */
568 void
close(SoGLRenderAction * action)569 SoGLCacheList::close(SoGLRenderAction * action)
570 {
571   if (!PRIVATE(this)->needclose) return;
572 
573   SoState * state = action->getState();
574 
575   // close open cache before accepting it or throwing it away
576   if (PRIVATE(this)->opencache) {
577     PRIVATE(this)->opencache->close();
578     SoGLLazyElement::endCaching(state);
579   }
580   if (SoCacheElement::setInvalid(PRIVATE(this)->savedinvalid)) {
581     // notify parent caches
582     SoCacheElement::setInvalid(TRUE);
583     PRIVATE(this)->numframesok = 0;
584     // just throw away the open cache, it's invalid
585     if (PRIVATE(this)->opencache) {
586       PRIVATE(this)->opencache->unref();
587       PRIVATE(this)->opencache = NULL;
588       PRIVATE(this)->numdiscarded += 1;
589 
590 #if COIN_DEBUG
591       if (coin_debug_caching_level() > 0) {
592         SoDebugError::postInfo("SoGLCacheList::close",
593                                "failed to create cache: %p", this);
594       }
595 #endif // debug
596     }
597   }
598   else {
599     PRIVATE(this)->numframesok++;
600   }
601 
602   // open cache is ok, add it to the cache list
603   if (PRIVATE(this)->opencache) {
604 #if COIN_DEBUG
605     if (coin_debug_caching_level() > 0) {
606       SoDebugError::postInfo("SoGLCacheList::close",
607                              "new cache created: %p", this);
608     }
609 #endif // debug
610     PRIVATE(this)->itemlist.append(PRIVATE(this)->opencache);
611     PRIVATE(this)->opencache = NULL;
612   }
613 
614   PRIVATE(this)->numshapes = SoGLCacheContextElement::getNumShapes(state);
615   int bits = SoGLCacheContextElement::resetAutoCacheBits(state);
616   SoGLCacheContextElement::setAutoCacheBits(state, bits|PRIVATE(this)->autocachebits);
617   PRIVATE(this)->autocachebits = bits;
618 }
619 
620 /*!
621   Invalidate all caches in this instance. Should be called
622   from the notify() method of nodes doing caching.
623 */
624 void
invalidateAll(void)625 SoGLCacheList::invalidateAll(void)
626 {
627   int n = PRIVATE(this)->itemlist.getLength();
628 #if COIN_DEBUG
629   if (n && coin_debug_caching_level() > 1) {
630     SoDebugError::postInfo("SoGLCacheList::invalidateAll",
631                            "invalidate all: %p (num caches = %d)", this, n);
632   }
633 #endif // debug
634 
635   for (int i = 0; i < n; i++) {
636     PRIVATE(this)->itemlist[i]->unref();
637   }
638   PRIVATE(this)->itemlist.truncate(0);
639   PRIVATE(this)->numdiscarded += n;
640   PRIVATE(this)->numframesok = 0;
641 }
642 
643 #undef PRIVATE
644