Update contrib.
2 * Copyright (c) 2005 Nokia Corporation and/or its subsidiary(-ies).
4 * This component and the accompanying materials are made available
5 * under the terms of the License "Eclipse Public License v1.0"
6 * which accompanies this distribution, and is available
7 * at the URL "http://www.eclipse.org/legal/epl-v10.html".
9 * Initial Contributors:
10 * Nokia Corporation - initial contribution.
14 * Description: Transformation cache implementation
22 * \brief Transformation cache implementation
25 #ifndef M3G_CORE_INCLUDE
26 # error included by m3g_core.c; do not compile separately.
29 #include "m3g_tcache.h"
31 /* NOTE size MUST be a power of two! */
32 #define TCACHE_COMPOSITES 128
33 #define TCACHE_PATHS 128
35 /*----------------------------------------------------------------------
37 *--------------------------------------------------------------------*/
41 * \brief Transformation path cache element
45 M3Gfloat elem[12]; /* NOTE the bottom row is always 0 0 0 1 */
47 M3Guint classified : 1;
50 const Node *from, *to;
53 M3G_CT_ASSERT2(sizeof(TCachePath) == 64);
57 * \brief Transformation cache data implementation
63 TCachePath paths[TCACHE_PATHS];
64 Matrix composites[TCACHE_COMPOSITES];
65 const Transformable *compositeObjs[TCACHE_COMPOSITES];
70 /*----------------------------------------------------------------------
72 *--------------------------------------------------------------------*/
74 static M3G_INLINE M3Gint m3gTransformableHash(const Transformable *t)
76 M3Guint a = (M3Guint) t;
77 M3Guint b = (M3Guint) t;
79 a += (a >> 3) + (a >> 9) + (a >> 17);
80 b = (b >> 16) | (b << 16);
81 b += (b >> 5) + (b >> 10) + (b >> 20);
82 return (M3Gint)(a ^ b);
85 static M3Gint m3gPathHash(const Node *from, const Node *to)
87 M3Guint a = (M3Guint) from;
88 M3Guint b = (M3Guint) to;
90 a += (a >> 3) + (a >> 9) + (a >> 17);
91 b = (b >> 16) | (b << 16);
92 b += (b >> 5) + (b >> 10) + (b >> 20);
93 return (M3Gint)(a ^ b);
96 static M3G_INLINE M3Gint m3gGetTransformableSlot(const TCache *tc, const Transformable *t)
99 return m3gTransformableHash(t) & (TCACHE_COMPOSITES - 1);
102 static M3G_INLINE M3Gint m3gGetPathSlot(const TCache *tc, const Node *from, const Node *to)
105 return m3gPathHash(from, to) & (TCACHE_PATHS - 1);
108 /*----------------------------------------------------------------------
110 *--------------------------------------------------------------------*/
116 static TCache* m3gCreateTransformCache(Interface *m3g)
118 TCache *cache = m3gAllocZ(m3g, sizeof(TCache));
121 cache->pathsInvalid = M3G_TRUE;
130 static void m3gDeleteTransformCache(TCache *cache)
133 m3gFree(cache->m3g, cache);
141 static void m3gCacheComposite(TCache *cache, const Transformable *t, const Matrix *m)
143 M3Gint idx = m3gGetTransformableSlot(cache, t);
145 /* If the matrix being added already exists in the cache, the
146 * cache is being used sub-optimally */
148 M3G_ASSERT(cache->compositeObjs[idx] != t);
150 /* Just overwrite any existing entries, but keep track of
151 * collisions for profiling */
153 if (cache->compositeObjs[idx]) {
154 m3gIncStat(cache->m3g, M3G_STAT_TCACHE_COMPOSITE_COLLISIONS, 1);
157 m3gIncStat(cache->m3g, M3G_STAT_TCACHE_COMPOSITE_LOAD, 1);
159 cache->composites[idx] = *m;
160 cache->compositeObjs[idx] = t;
162 m3gIncStat(cache->m3g, M3G_STAT_TCACHE_COMPOSITE_INSERTS, 1);
169 static void m3gCachePath(TCache *cache, const Node *from, const Node *to, const Matrix *m)
171 M3G_ASSERT(m3gIsWUnity(m));
172 /* These two asserts are not errors in a strict sense, but imply
173 * sub-optimal cache use */
174 M3G_ASSERT(from || to);
175 M3G_ASSERT(from != to);
177 M3G_BEGIN_PROFILE(cache->m3g, M3G_PROFILE_TCACHE);
179 /* If the cache has been invalidated, wipe it clean before
180 * inserting anything */
182 if (cache->pathsInvalid) {
183 m3gIncStat(cache->m3g, M3G_STAT_TCACHE_PATH_FLUSHES, 1);
184 m3gZero(cache->paths, TCACHE_PATHS * sizeof(cache->paths[0]));
185 cache->pathsInvalid = M3G_FALSE;
188 /* Hash to the cache, then just overwrite anything previously
191 M3Gint idx = m3gGetPathSlot(cache, from, to);
192 TCachePath *c = &cache->paths[idx];
194 /* If this assert is hit, the path being added already exists
195 * in the cache; this is not an error per se, but implies
196 * sub-optimal cache usage */
197 M3G_ASSERT(c->from != from || c->to != to);
199 /* Overwrite the matrix data */
201 const M3Gfloat *src = &m->elem[0];
202 M3Gfloat *dst = &c->elem[0];
204 for (col = 0; col < 4; ++col) {
205 for (row = 0; row < 3; ++row) {
211 c->classified = m->classified;
212 c->complete = m->complete;
215 /* Register collisions for bookkeeping */
217 if (c->from || c->to) {
218 m3gIncStat(cache->m3g, M3G_STAT_TCACHE_PATH_COLLISIONS, 1);
221 m3gIncStat(cache->m3g, M3G_STAT_TCACHE_PATH_LOAD, 1);
227 M3G_END_PROFILE(cache->m3g, M3G_PROFILE_TCACHE);
229 m3gIncStat(cache->m3g, M3G_STAT_TCACHE_PATH_INSERTS, 1);
236 static M3Gbool m3gGetCachedComposite(const TCache *cache, const Transformable *t, Matrix *m)
238 M3Gint idx = m3gGetTransformableSlot(cache, t);
239 if (cache->compositeObjs[idx] == t) {
240 *m = cache->composites[idx];
241 m3gIncStat(cache->m3g, M3G_STAT_TCACHE_COMPOSITE_HITS, 1);
244 m3gIncStat(cache->m3g, M3G_STAT_TCACHE_COMPOSITE_MISSES, 1);
252 static M3Gbool m3gGetCachedPath(const TCache *cache, const Node *from, const Node *to, Matrix *m)
254 M3G_BEGIN_PROFILE(cache->m3g, M3G_PROFILE_TCACHE);
256 if (!cache->pathsInvalid) {
258 /* Hash to the respective cache slot */
260 M3Gint idx = m3gGetPathSlot(cache, from, to);
261 const TCachePath *c = &cache->paths[idx];
263 /* If it matches, copy to the output matrix */
265 if (c->from == from && c->to == to) {
266 const M3Gfloat *src = &c->elem[0];
267 M3Gfloat *dst = &m->elem[0];
269 for (col = 0; col < 4; ++col) {
277 m->classified = c->classified;
278 m->complete = c->complete;
280 M3G_END_PROFILE(cache->m3g, M3G_PROFILE_TCACHE);
282 m3gIncStat(cache->m3g, M3G_STAT_TCACHE_PATH_HITS, 1);
286 M3G_END_PROFILE(cache->m3g, M3G_PROFILE_TCACHE);
288 m3gIncStat(cache->m3g, M3G_STAT_TCACHE_PATH_MISSES, 1);
296 static void m3gInvalidateCachedPaths(TCache *cache, const Node *n)
299 m3gResetStat(cache->m3g, M3G_STAT_TCACHE_PATH_LOAD);
300 cache->pathsInvalid = M3G_TRUE;
307 static void m3gInvalidateCachedTransforms(TCache *cache, const Transformable *t)
309 /* Look for a composite entry and wipe if found */
311 M3Gint idx = m3gGetTransformableSlot(cache, t);
312 if (cache->compositeObjs[idx] == t) {
313 cache->compositeObjs[idx] = NULL;
314 m3gIncStat(cache->m3g, M3G_STAT_TCACHE_COMPOSITE_LOAD, -1);
318 /* NOTE We just cast the pointer to a Node below -- it's only used
319 * for hashing, and every object will still be unique regardless
322 m3gInvalidateCachedPaths(cache, (const Node*) t);