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