gfx/skia/trunk/src/lazy/SkDiscardableMemoryPool.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/gfx/skia/trunk/src/lazy/SkDiscardableMemoryPool.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,207 @@
     1.4 +/*
     1.5 + * Copyright 2013 Google Inc.
     1.6 + *
     1.7 + * Use of this source code is governed by a BSD-style license that can be
     1.8 + * found in the LICENSE file.
     1.9 + */
    1.10 +
    1.11 +#include "SkDiscardableMemoryPool.h"
    1.12 +#include "SkOnce.h"
    1.13 +
    1.14 +// Note:
    1.15 +// A PoolDiscardableMemory is memory that is counted in a pool.
    1.16 +// A DiscardableMemoryPool is a pool of PoolDiscardableMemorys.
    1.17 +
    1.18 +/**
    1.19 + *  A SkPoolDiscardableMemory is a SkDiscardableMemory that relies on
    1.20 + *  a SkDiscardableMemoryPool object to manage the memory.
    1.21 + */
    1.22 +class SkPoolDiscardableMemory : public SkDiscardableMemory {
    1.23 +public:
    1.24 +    SkPoolDiscardableMemory(SkDiscardableMemoryPool* pool,
    1.25 +                            void* pointer, size_t bytes);
    1.26 +    virtual ~SkPoolDiscardableMemory();
    1.27 +    virtual bool lock() SK_OVERRIDE;
    1.28 +    virtual void* data() SK_OVERRIDE;
    1.29 +    virtual void unlock() SK_OVERRIDE;
    1.30 +    friend class SkDiscardableMemoryPool;
    1.31 +private:
    1.32 +    SK_DECLARE_INTERNAL_LLIST_INTERFACE(SkPoolDiscardableMemory);
    1.33 +    SkDiscardableMemoryPool* const fPool;
    1.34 +    bool                           fLocked;
    1.35 +    void*                          fPointer;
    1.36 +    const size_t                   fBytes;
    1.37 +};
    1.38 +
    1.39 +SkPoolDiscardableMemory::SkPoolDiscardableMemory(SkDiscardableMemoryPool* pool,
    1.40 +                                                 void* pointer,
    1.41 +                                                 size_t bytes)
    1.42 +    : fPool(pool)
    1.43 +    , fLocked(true)
    1.44 +    , fPointer(pointer)
    1.45 +    , fBytes(bytes) {
    1.46 +    SkASSERT(fPool != NULL);
    1.47 +    SkASSERT(fPointer != NULL);
    1.48 +    SkASSERT(fBytes > 0);
    1.49 +    fPool->ref();
    1.50 +}
    1.51 +
    1.52 +SkPoolDiscardableMemory::~SkPoolDiscardableMemory() {
    1.53 +    SkASSERT(!fLocked); // contract for SkDiscardableMemory
    1.54 +    fPool->free(this);
    1.55 +    fPool->unref();
    1.56 +}
    1.57 +
    1.58 +bool SkPoolDiscardableMemory::lock() {
    1.59 +    SkASSERT(!fLocked); // contract for SkDiscardableMemory
    1.60 +    return fPool->lock(this);
    1.61 +}
    1.62 +
    1.63 +void* SkPoolDiscardableMemory::data() {
    1.64 +    SkASSERT(fLocked); // contract for SkDiscardableMemory
    1.65 +    return fPointer;
    1.66 +}
    1.67 +
    1.68 +void SkPoolDiscardableMemory::unlock() {
    1.69 +    SkASSERT(fLocked); // contract for SkDiscardableMemory
    1.70 +    fPool->unlock(this);
    1.71 +}
    1.72 +
    1.73 +////////////////////////////////////////////////////////////////////////////////
    1.74 +
    1.75 +SkDiscardableMemoryPool::SkDiscardableMemoryPool(size_t budget,
    1.76 +                                                 SkBaseMutex* mutex)
    1.77 +    : fMutex(mutex)
    1.78 +    , fBudget(budget)
    1.79 +    , fUsed(0) {
    1.80 +    #if LAZY_CACHE_STATS
    1.81 +    fCacheHits = 0;
    1.82 +    fCacheMisses = 0;
    1.83 +    #endif  // LAZY_CACHE_STATS
    1.84 +}
    1.85 +SkDiscardableMemoryPool::~SkDiscardableMemoryPool() {
    1.86 +    // SkPoolDiscardableMemory objects that belong to this pool are
    1.87 +    // always deleted before deleting this pool since each one has a
    1.88 +    // ref to the pool.
    1.89 +    SkASSERT(fList.isEmpty());
    1.90 +}
    1.91 +
    1.92 +void SkDiscardableMemoryPool::dumpDownTo(size_t budget) {
    1.93 +    // assert((NULL = fMutex) || fMutex->isLocked());
    1.94 +    // TODO(halcanary) implement bool fMutex::isLocked().
    1.95 +    // WARNING: only call this function after aquiring lock.
    1.96 +    if (fUsed <= budget) {
    1.97 +        return;
    1.98 +    }
    1.99 +    typedef SkTInternalLList<SkPoolDiscardableMemory>::Iter Iter;
   1.100 +    Iter iter;
   1.101 +    SkPoolDiscardableMemory* cur = iter.init(fList, Iter::kTail_IterStart);
   1.102 +    while ((fUsed > budget) && (NULL != cur)) {
   1.103 +        if (!cur->fLocked) {
   1.104 +            SkPoolDiscardableMemory* dm = cur;
   1.105 +            SkASSERT(dm->fPointer != NULL);
   1.106 +            sk_free(dm->fPointer);
   1.107 +            dm->fPointer = NULL;
   1.108 +            SkASSERT(fUsed >= dm->fBytes);
   1.109 +            fUsed -= dm->fBytes;
   1.110 +            cur = iter.prev();
   1.111 +            // Purged DMs are taken out of the list.  This saves times
   1.112 +            // looking them up.  Purged DMs are NOT deleted.
   1.113 +            fList.remove(dm);
   1.114 +        } else {
   1.115 +            cur = iter.prev();
   1.116 +        }
   1.117 +    }
   1.118 +}
   1.119 +
   1.120 +SkDiscardableMemory* SkDiscardableMemoryPool::create(size_t bytes) {
   1.121 +    void* addr = sk_malloc_flags(bytes, 0);
   1.122 +    if (NULL == addr) {
   1.123 +        return NULL;
   1.124 +    }
   1.125 +    SkPoolDiscardableMemory* dm = SkNEW_ARGS(SkPoolDiscardableMemory,
   1.126 +                                             (this, addr, bytes));
   1.127 +    SkAutoMutexAcquire autoMutexAcquire(fMutex);
   1.128 +    fList.addToHead(dm);
   1.129 +    fUsed += bytes;
   1.130 +    this->dumpDownTo(fBudget);
   1.131 +    return dm;
   1.132 +}
   1.133 +
   1.134 +void SkDiscardableMemoryPool::free(SkPoolDiscardableMemory* dm) {
   1.135 +    // This is called by dm's destructor.
   1.136 +    if (dm->fPointer != NULL) {
   1.137 +        SkAutoMutexAcquire autoMutexAcquire(fMutex);
   1.138 +        sk_free(dm->fPointer);
   1.139 +        dm->fPointer = NULL;
   1.140 +        SkASSERT(fUsed >= dm->fBytes);
   1.141 +        fUsed -= dm->fBytes;
   1.142 +        fList.remove(dm);
   1.143 +    } else {
   1.144 +        SkASSERT(!fList.isInList(dm));
   1.145 +    }
   1.146 +}
   1.147 +
   1.148 +bool SkDiscardableMemoryPool::lock(SkPoolDiscardableMemory* dm) {
   1.149 +    SkASSERT(dm != NULL);
   1.150 +    if (NULL == dm->fPointer) {
   1.151 +        #if LAZY_CACHE_STATS
   1.152 +        SkAutoMutexAcquire autoMutexAcquire(fMutex);
   1.153 +        ++fCacheMisses;
   1.154 +        #endif  // LAZY_CACHE_STATS
   1.155 +        return false;
   1.156 +    }
   1.157 +    SkAutoMutexAcquire autoMutexAcquire(fMutex);
   1.158 +    if (NULL == dm->fPointer) {
   1.159 +        // May have been purged while waiting for lock.
   1.160 +        #if LAZY_CACHE_STATS
   1.161 +        ++fCacheMisses;
   1.162 +        #endif  // LAZY_CACHE_STATS
   1.163 +        return false;
   1.164 +    }
   1.165 +    dm->fLocked = true;
   1.166 +    fList.remove(dm);
   1.167 +    fList.addToHead(dm);
   1.168 +    #if LAZY_CACHE_STATS
   1.169 +    ++fCacheHits;
   1.170 +    #endif  // LAZY_CACHE_STATS
   1.171 +    return true;
   1.172 +}
   1.173 +
   1.174 +void SkDiscardableMemoryPool::unlock(SkPoolDiscardableMemory* dm) {
   1.175 +    SkASSERT(dm != NULL);
   1.176 +    SkAutoMutexAcquire autoMutexAcquire(fMutex);
   1.177 +    dm->fLocked = false;
   1.178 +    this->dumpDownTo(fBudget);
   1.179 +}
   1.180 +
   1.181 +size_t SkDiscardableMemoryPool::getRAMUsed() {
   1.182 +    return fUsed;
   1.183 +}
   1.184 +void SkDiscardableMemoryPool::setRAMBudget(size_t budget) {
   1.185 +    SkAutoMutexAcquire autoMutexAcquire(fMutex);
   1.186 +    fBudget = budget;
   1.187 +    this->dumpDownTo(fBudget);
   1.188 +}
   1.189 +void SkDiscardableMemoryPool::dumpPool() {
   1.190 +    SkAutoMutexAcquire autoMutexAcquire(fMutex);
   1.191 +    this->dumpDownTo(0);
   1.192 +}
   1.193 +
   1.194 +////////////////////////////////////////////////////////////////////////////////
   1.195 +SK_DECLARE_STATIC_MUTEX(gMutex);
   1.196 +static void create_pool(SkDiscardableMemoryPool** pool) {
   1.197 +    SkASSERT(NULL == *pool);
   1.198 +    *pool = SkNEW_ARGS(SkDiscardableMemoryPool,
   1.199 +                       (SK_DEFAULT_GLOBAL_DISCARDABLE_MEMORY_POOL_SIZE,
   1.200 +                        &gMutex));
   1.201 +}
   1.202 +SkDiscardableMemoryPool* SkGetGlobalDiscardableMemoryPool() {
   1.203 +    static SkDiscardableMemoryPool* gPool(NULL);
   1.204 +    SK_DECLARE_STATIC_ONCE(create_pool_once);
   1.205 +    SkOnce(&create_pool_once, create_pool, &gPool);
   1.206 +    SkASSERT(NULL != gPool);
   1.207 +    return gPool;
   1.208 +}
   1.209 +
   1.210 +////////////////////////////////////////////////////////////////////////////////

mercurial