os/graphics/m3g/m3gcore11/src/m3g_tcache.c
author sl@SLION-WIN7.fritz.box
Fri, 15 Jun 2012 03:10:57 +0200
changeset 0 bde4ae8d615e
permissions -rw-r--r--
First public contribution.
     1 /*
     2 * Copyright (c) 2005 Nokia Corporation and/or its subsidiary(-ies).
     3 * All rights reserved.
     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".
     8 *
     9 * Initial Contributors:
    10 * Nokia Corporation - initial contribution.
    11 *
    12 * Contributors:
    13 *
    14 * Description: Transformation cache implementation
    15 *
    16 */
    17 
    18 
    19 /*!
    20  * \internal
    21  * \file
    22  * \brief Transformation cache implementation
    23  */
    24 
    25 #ifndef M3G_CORE_INCLUDE
    26 #   error included by m3g_core.c; do not compile separately.
    27 #endif
    28 
    29 #include "m3g_tcache.h"
    30 
    31 /* NOTE size MUST be a power of two! */
    32 #define TCACHE_COMPOSITES 128
    33 #define TCACHE_PATHS 128
    34 
    35 /*----------------------------------------------------------------------
    36  * Data structures
    37  *--------------------------------------------------------------------*/
    38 
    39 /*!
    40  * \internal
    41  * \brief Transformation path cache element
    42  */
    43 typedef struct
    44 {
    45     M3Gfloat elem[12];  /* NOTE the bottom row is always 0 0 0 1 */
    46     M3Guint mask;
    47     M3Guint classified  : 1;
    48     M3Guint complete    : 1;
    49     
    50     const Node *from, *to;
    51 } TCachePath;
    52 
    53 M3G_CT_ASSERT2(sizeof(TCachePath) == 64);
    54 
    55 /*!
    56  * \internal
    57  * \brief Transformation cache data implementation
    58  */
    59 struct TCacheImpl
    60 {
    61     Interface *m3g;
    62 
    63     TCachePath paths[TCACHE_PATHS];
    64     Matrix composites[TCACHE_COMPOSITES];
    65     const Transformable *compositeObjs[TCACHE_COMPOSITES];
    66     
    67     M3Gbool pathsInvalid;
    68 };
    69 
    70 /*----------------------------------------------------------------------
    71  * Private functions
    72  *--------------------------------------------------------------------*/
    73 
    74 static M3G_INLINE M3Gint m3gTransformableHash(const Transformable *t)
    75 {
    76     M3Guint a = (M3Guint) t;
    77     M3Guint b = (M3Guint) t;
    78     
    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);
    83 }
    84 
    85 static M3Gint m3gPathHash(const Node *from, const Node *to)
    86 {
    87     M3Guint a = (M3Guint) from;
    88     M3Guint b = (M3Guint) to;
    89 
    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);
    94 }
    95 
    96 static M3G_INLINE M3Gint m3gGetTransformableSlot(const TCache *tc, const Transformable *t)
    97 {
    98     M3G_UNREF(tc);
    99     return m3gTransformableHash(t) & (TCACHE_COMPOSITES - 1);
   100 }
   101 
   102 static M3G_INLINE M3Gint m3gGetPathSlot(const TCache *tc, const Node *from, const Node *to)
   103 {
   104     M3G_UNREF(tc);
   105     return m3gPathHash(from, to) & (TCACHE_PATHS - 1);
   106 }
   107     
   108 /*----------------------------------------------------------------------
   109  * Internal functions
   110  *--------------------------------------------------------------------*/
   111 
   112 /*!
   113  * \internal
   114  * \brief
   115  */
   116 static TCache* m3gCreateTransformCache(Interface *m3g)
   117 {
   118     TCache *cache = m3gAllocZ(m3g, sizeof(TCache));
   119     if (cache) {
   120         cache->m3g = m3g;
   121         cache->pathsInvalid = M3G_TRUE;
   122     }
   123     return cache;
   124 }
   125 
   126 /*!
   127  * \internal
   128  * \brief
   129  */
   130 static void m3gDeleteTransformCache(TCache *cache)
   131 {
   132     if (cache) {
   133         m3gFree(cache->m3g, cache);
   134     }
   135 }
   136 
   137 /*!
   138  * \internal
   139  * \brief
   140  */
   141 static void m3gCacheComposite(TCache *cache, const Transformable *t, const Matrix *m)
   142 {
   143     M3Gint idx = m3gGetTransformableSlot(cache, t);
   144 
   145     /* If the matrix being added already exists in the cache, the
   146      * cache is being used sub-optimally */
   147     
   148     M3G_ASSERT(cache->compositeObjs[idx] != t);
   149     
   150     /* Just overwrite any existing entries, but keep track of
   151      * collisions for profiling */
   152     
   153     if (cache->compositeObjs[idx]) {
   154         m3gIncStat(cache->m3g, M3G_STAT_TCACHE_COMPOSITE_COLLISIONS, 1);
   155     }
   156     else {
   157         m3gIncStat(cache->m3g, M3G_STAT_TCACHE_COMPOSITE_LOAD, 1);
   158     }
   159     cache->composites[idx] = *m;
   160     cache->compositeObjs[idx] = t;
   161     
   162     m3gIncStat(cache->m3g, M3G_STAT_TCACHE_COMPOSITE_INSERTS, 1);
   163 }
   164 
   165 /*!
   166  * \internal
   167  * \brief
   168  */
   169 static void m3gCachePath(TCache *cache, const Node *from, const Node *to, const Matrix *m)
   170 {
   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);
   176     
   177     M3G_BEGIN_PROFILE(cache->m3g, M3G_PROFILE_TCACHE);
   178     
   179     /* If the cache has been invalidated, wipe it clean before
   180      * inserting anything */
   181     
   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;
   186     }
   187 
   188     /* Hash to the cache, then just overwrite anything previously
   189      * there */
   190     {
   191         M3Gint idx = m3gGetPathSlot(cache, from, to);
   192         TCachePath *c = &cache->paths[idx];
   193 
   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);
   198         
   199         /* Overwrite the matrix data */
   200         {
   201             const M3Gfloat *src = &m->elem[0];
   202             M3Gfloat *dst = &c->elem[0];
   203             int row, col;
   204             for (col = 0; col < 4; ++col) {
   205                 for (row = 0; row < 3; ++row) {
   206                     *dst++ = *src++;
   207                 }
   208                 ++src;
   209             }
   210             c->mask = m->mask;
   211             c->classified = m->classified;
   212             c->complete = m->complete;
   213         }
   214 
   215         /* Register collisions for bookkeeping */
   216 
   217         if (c->from || c->to) {
   218             m3gIncStat(cache->m3g, M3G_STAT_TCACHE_PATH_COLLISIONS, 1);
   219         }
   220         else {
   221             m3gIncStat(cache->m3g, M3G_STAT_TCACHE_PATH_LOAD, 1);
   222         }
   223         
   224         c->from = from;
   225         c->to = to;
   226     }
   227     M3G_END_PROFILE(cache->m3g, M3G_PROFILE_TCACHE);
   228     
   229     m3gIncStat(cache->m3g, M3G_STAT_TCACHE_PATH_INSERTS, 1);
   230 }
   231 
   232 /*!
   233  * \internal
   234  * \brief
   235  */
   236 static M3Gbool m3gGetCachedComposite(const TCache *cache, const Transformable *t, Matrix *m)
   237 {
   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);
   242         return M3G_TRUE;
   243     }
   244     m3gIncStat(cache->m3g, M3G_STAT_TCACHE_COMPOSITE_MISSES, 1);
   245     return M3G_FALSE;
   246 }
   247 
   248 /*!
   249  * \internal
   250  * \brief
   251  */
   252 static M3Gbool m3gGetCachedPath(const TCache *cache, const Node *from, const Node *to, Matrix *m)
   253 {
   254     M3G_BEGIN_PROFILE(cache->m3g, M3G_PROFILE_TCACHE);
   255     
   256     if (!cache->pathsInvalid) {
   257 
   258         /* Hash to the respective cache slot */
   259         
   260         M3Gint idx = m3gGetPathSlot(cache, from, to);
   261         const TCachePath *c = &cache->paths[idx];
   262 
   263         /* If it matches, copy to the output matrix */
   264         
   265         if (c->from == from && c->to == to) {
   266             const M3Gfloat *src = &c->elem[0];
   267             M3Gfloat *dst = &m->elem[0];
   268             int col;
   269             for (col = 0; col < 4; ++col) {
   270                 *dst++ = *src++;
   271                 *dst++ = *src++;
   272                 *dst++ = *src++;
   273                 *dst++ = 0.0f;
   274             }
   275             m->elem[15] = 1.0f;
   276             m->mask = c->mask;
   277             m->classified = c->classified;
   278             m->complete = c->complete;
   279 
   280             M3G_END_PROFILE(cache->m3g, M3G_PROFILE_TCACHE);
   281     
   282             m3gIncStat(cache->m3g, M3G_STAT_TCACHE_PATH_HITS, 1);
   283             return M3G_TRUE;
   284         }
   285     }
   286     M3G_END_PROFILE(cache->m3g, M3G_PROFILE_TCACHE);
   287     
   288     m3gIncStat(cache->m3g, M3G_STAT_TCACHE_PATH_MISSES, 1);
   289     return M3G_FALSE;
   290 }
   291 
   292 /*!
   293  * \internal
   294  * \brief
   295  */
   296 static void m3gInvalidateCachedPaths(TCache *cache, const Node *n)
   297 {
   298     M3G_UNREF(n);
   299     m3gResetStat(cache->m3g, M3G_STAT_TCACHE_PATH_LOAD);
   300     cache->pathsInvalid = M3G_TRUE;
   301 }
   302 
   303 /*!
   304  * \internal
   305  * \brief
   306  */
   307 static void m3gInvalidateCachedTransforms(TCache *cache, const Transformable *t)
   308 {
   309     /* Look for a composite entry and wipe if found */
   310     {
   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);
   315         }
   316     }
   317     
   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
   320      * of the class */
   321     
   322     m3gInvalidateCachedPaths(cache, (const Node*) t);
   323 }