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 SoCacheElement Inventor/elements/SoCacheElement.h
35 \brief The SoCacheElement class stores and manages the open caches.
36
37 \ingroup elements
38 */
39
40 // *************************************************************************
41
42 #include <Inventor/elements/SoCacheElement.h>
43
44 #include <cassert>
45 #include <cstdlib>
46
47 #include <Inventor/caches/SoCache.h>
48 #include <Inventor/errors/SoDebugError.h>
49 #include <Inventor/misc/SoState.h>
50
51 #ifdef HAVE_CONFIG_H
52 #include "config.h"
53 #endif // HAVE_CONFIG_H
54
55 #ifdef COIN_THREADSAFE
56 #include <Inventor/threads/SbTypedStorage.h>
57 #endif // COIN_THREADSAFE
58
59 #include "tidbitsp.h"
60 #include "SbBasicP.h"
61 #include "coindefs.h"
62
63 // *************************************************************************
64
65 SbBool SoCacheElement::invalidated = FALSE;
66
67 // *************************************************************************
68
69 #ifdef COIN_THREADSAFE
70
71 static SbTypedStorage <SbBool*> * invalidated_storage = NULL;
72
73 static void
cacheelement_cleanup(void)74 cacheelement_cleanup(void)
75 {
76 delete invalidated_storage;
77 }
78
79 #endif // COIN_THREADSAFE
80
81 // *************************************************************************
82
83 SO_ELEMENT_SOURCE(SoCacheElement);
84
85 // *************************************************************************
86
87 // Doc in superclass.
88 void
initClass(void)89 SoCacheElement::initClass(void)
90 {
91 SO_ELEMENT_INIT_CLASS(SoCacheElement, inherited);
92 SoCacheElement::invalidated = FALSE;
93
94 #ifdef COIN_THREADSAFE
95 invalidated_storage = new SbTypedStorage <SbBool*> (sizeof(SbBool));
96 *(invalidated_storage->get()) = FALSE;
97 coin_atexit((coin_atexit_f*) cacheelement_cleanup, CC_ATEXIT_NORMAL);
98 #endif // COIN_THREADSAFE
99 }
100
101 /*!
102 The destructor.
103 */
104
~SoCacheElement(void)105 SoCacheElement::~SoCacheElement(void)
106 {
107 }
108
109 // Doc in superclass.
110 void
init(SoState * state)111 SoCacheElement::init(SoState * state)
112 {
113 inherited::init(state);
114 this->cache = NULL;
115 }
116
117 // *************************************************************************
118
119 // Documented in superclass. Overridden to initialize element.
120 void
push(SoState * state)121 SoCacheElement::push(SoState * state)
122 {
123 inherited::push(state);
124 this->cache = NULL;
125 }
126
127 // Documented in superclass. Overridden to unref the cache, since the
128 // cache is ref'ed in set().
129 void
pop(SoState * state,const SoElement * prevTopElement)130 SoCacheElement::pop(SoState * state, const SoElement * prevTopElement)
131 {
132 SoCacheElement * prev =
133 const_cast<SoCacheElement *>
134 ( coin_assert_cast<const SoCacheElement *>(
135 prevTopElement
136 )
137 );
138 if (prev->cache) {
139 prev->cache->unref();
140 prev->cache = NULL;
141 }
142 inherited::pop(state, prevTopElement);
143 if (!this->anyOpen(state)) state->setCacheOpen(FALSE);
144 }
145
146
147 /*!
148 Sets the current cache. The cache is ref'ed before returning.
149 */
150 void
set(SoState * const state,SoCache * const cache)151 SoCacheElement::set(SoState * const state, SoCache * const cache)
152 {
153 SoCacheElement * elem = coin_assert_cast<SoCacheElement *>
154 (
155 SoElement::getElement(state, classStackIndex)
156 );
157
158 if (elem) {
159 if (elem->cache) elem->cache->unref();
160 elem->cache = cache;
161 if (elem->cache) {
162 elem->cache->ref();
163 state->setCacheOpen(TRUE);
164 }
165 }
166 }
167
168 /*!
169 This method returns the cache, or NULL if there is no cache.
170 */
171
172 SoCache *
getCache(void) const173 SoCacheElement::getCache(void) const
174 {
175 return this->cache;
176 }
177
178 /*!
179 This method returns TRUE if a cache is currently open.
180 */
181
182 SbBool
anyOpen(SoState * const state)183 SoCacheElement::anyOpen(SoState * const state)
184 {
185 const SoCacheElement * elem = coin_assert_cast<const SoCacheElement *>
186 (
187 state->getElementNoPush(classStackIndex)
188 );
189 while (elem) {
190 if (elem->cache) return TRUE;
191 elem = coin_safe_cast<const SoCacheElement*>(elem->getNextInStack());
192 }
193 return FALSE;
194 }
195
196 /*!
197 This method invalidates open caches. It should be called by
198 uncacheable nodes.
199 */
200 void
invalidate(SoState * const state)201 SoCacheElement::invalidate(SoState * const state)
202 {
203 #if COIN_DEBUG && 0 // debug
204 SoDebugError::postInfo("SoCacheElement::invalidate",
205 "Invalidate all caches");
206 #endif // debug
207
208 #ifdef COIN_THREADSAFE
209 *(invalidated_storage->get()) = TRUE;
210 #else // COIN_THREADSAFE
211 SoCacheElement::invalidated = TRUE;
212 #endif // ! COIN_THREADSAFE
213
214 const SoCacheElement * elem =
215 coin_assert_cast<const SoCacheElement *>
216 (
217 state->getElementNoPush(classStackIndex)
218 );
219
220 while (elem && elem->cache) {
221 elem->cache->invalidate();
222 elem = coin_safe_cast<const SoCacheElement *>(elem->getNextInStack());
223 }
224 }
225
226 /*!
227 SoCacheElement objects should not be compared because you obviously don't
228 cache them in the cache.
229 */
230 SbBool
matches(const SoElement * COIN_UNUSED_ARG (element)) const231 SoCacheElement::matches(const SoElement * COIN_UNUSED_ARG(element)) const
232 {
233 assert(FALSE && "this method should not be called for this element");
234 return FALSE;
235 }
236
237 /*!
238 SoCacheElement objects should not be "copied" because you obviously don't
239 cache them in the cache.
240
241 \sa SbBool SoCacheElement::matches(const SoElement * element) const
242 */
243 SoElement *
copyMatchInfo(void) const244 SoCacheElement::copyMatchInfo(void) const
245 {
246 assert(FALSE && "this method should not be called for this element");
247 return NULL;
248 }
249
250 /*!
251 This method returns the next cache element. That is the next cache
252 element pointing towards the bottom of the state.
253 */
254 SoCacheElement *
getNextCacheElement(void) const255 SoCacheElement::getNextCacheElement(void) const
256 {
257 return coin_safe_cast<SoCacheElement *>
258 (
259 this->getNextInStack()
260 );
261 }
262
263 /*!
264 This method adds \a element to the elements used lists of all the open
265 caches in \a state.
266 */
267
268 void
addElement(SoState * const state,const SoElement * const element)269 SoCacheElement::addElement(SoState * const state,
270 const SoElement * const element)
271 {
272 SoCacheElement * elem =
273 coin_assert_cast<SoCacheElement *>
274 (
275 state->getElementNoPush(classStackIndex)
276 );
277
278 while (elem) {
279 if (elem->cache) elem->cache->addElement(element);
280 elem = coin_safe_cast<SoCacheElement *>(elem->getNextInStack());
281 }
282 }
283
284 /*!
285 This method creates dependencies on \a cache for all the open caches
286 in \a state.
287 */
288
289 void
addCacheDependency(SoState * const state,SoCache * const cache)290 SoCacheElement::addCacheDependency(SoState * const state,
291 SoCache * const cache)
292 {
293 SoCacheElement * elem = coin_assert_cast<SoCacheElement *>
294 (
295 state->getElementNoPush(classStackIndex)
296 );
297 while (elem && elem->cache) {
298 elem->cache->addCacheDependency(state, cache);
299 elem = coin_assert_cast<SoCacheElement *>(elem->getNextInStack());
300 }
301 }
302
303 /*!
304 This method returns the old invalidated bit value, and sets it to
305 \a newvalue.
306 */
307
308 SbBool
setInvalid(const SbBool newvalue)309 SoCacheElement::setInvalid(const SbBool newvalue)
310 {
311 #ifdef COIN_THREADSAFE
312 SbBool * ptr = invalidated_storage->get();
313 SbBool oldval = *ptr;
314 *ptr = newvalue;
315 #else // COIN_THREADSAFE
316 SbBool oldval = SoCacheElement::invalidated;
317 SoCacheElement::invalidated = newvalue;
318 #endif // ! COIN_THREADSAFE
319 return oldval;
320 }
321
322 /*!
323 This method returns the current cache. No cache dependencies are honored.
324 */
325
326 SoCache *
getCurrentCache(SoState * const state)327 SoCacheElement::getCurrentCache(SoState * const state)
328 {
329 return (coin_assert_cast<const SoCacheElement *>(state->getElementNoPush(classStackIndex)))->cache;
330 }
331