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