2014-10-08 12:17:12 +00:00
|
|
|
/*
|
|
|
|
* Copyright 2014 Google Inc.
|
|
|
|
*
|
|
|
|
* Use of this source code is governed by a BSD-style license that can be
|
|
|
|
* found in the LICENSE file.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "SkCachedData.h"
|
|
|
|
#include "SkDiscardableMemoryPool.h"
|
|
|
|
#include "Test.h"
|
|
|
|
|
|
|
|
enum LockedState {
|
|
|
|
kUnlocked,
|
|
|
|
kLocked,
|
|
|
|
};
|
|
|
|
|
|
|
|
enum CachedState {
|
|
|
|
kNotInCache,
|
|
|
|
kInCache,
|
|
|
|
};
|
|
|
|
|
|
|
|
static void check_data(skiatest::Reporter* reporter, SkCachedData* data,
|
|
|
|
int refcnt, CachedState cacheState, LockedState lockedState) {
|
|
|
|
REPORTER_ASSERT(reporter, data->testing_only_getRefCnt() == refcnt);
|
|
|
|
REPORTER_ASSERT(reporter, data->testing_only_isInCache() == (kInCache == cacheState));
|
|
|
|
REPORTER_ASSERT(reporter, data->testing_only_isLocked() == (lockedState == kLocked));
|
|
|
|
}
|
|
|
|
|
|
|
|
static SkCachedData* make_data(size_t size, SkDiscardableMemoryPool* pool) {
|
|
|
|
if (pool) {
|
|
|
|
SkDiscardableMemory* dm = pool->create(size);
|
|
|
|
// the pool "can" return null, but it shouldn't in these controlled conditions
|
|
|
|
SK_ALWAYSBREAK(dm);
|
2015-08-26 20:07:48 +00:00
|
|
|
return new SkCachedData(size, dm);
|
2014-10-08 12:17:12 +00:00
|
|
|
} else {
|
2015-08-26 20:07:48 +00:00
|
|
|
return new SkCachedData(sk_malloc_throw(size), size);
|
2014-10-08 12:17:12 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// returns with the data locked by client and cache
|
|
|
|
static SkCachedData* test_locking(skiatest::Reporter* reporter,
|
|
|
|
size_t size, SkDiscardableMemoryPool* pool) {
|
|
|
|
SkCachedData* data = make_data(size, pool);
|
|
|
|
|
|
|
|
memset(data->writable_data(), 0x80, size); // just to use writable_data()
|
|
|
|
|
|
|
|
check_data(reporter, data, 1, kNotInCache, kLocked);
|
|
|
|
|
|
|
|
data->ref();
|
|
|
|
check_data(reporter, data, 2, kNotInCache, kLocked);
|
|
|
|
data->unref();
|
|
|
|
check_data(reporter, data, 1, kNotInCache, kLocked);
|
|
|
|
|
|
|
|
data->attachToCacheAndRef();
|
|
|
|
check_data(reporter, data, 2, kInCache, kLocked);
|
|
|
|
|
|
|
|
data->unref();
|
|
|
|
check_data(reporter, data, 1, kInCache, kUnlocked);
|
|
|
|
|
|
|
|
data->ref();
|
|
|
|
check_data(reporter, data, 2, kInCache, kLocked);
|
|
|
|
|
|
|
|
return data;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* SkCachedData behaves differently (regarding its locked/unlocked state) depending on
|
|
|
|
* when it is in the cache or not. Being in the cache is signaled by calling attachToCacheAndRef()
|
|
|
|
* instead of ref(). (and balanced by detachFromCacheAndUnref).
|
|
|
|
*
|
|
|
|
* Thus, among other things, we test the end-of-life behavior when the client is the last owner
|
|
|
|
* and when the cache is.
|
|
|
|
*/
|
|
|
|
DEF_TEST(CachedData, reporter) {
|
|
|
|
SkAutoTUnref<SkDiscardableMemoryPool> pool(SkDiscardableMemoryPool::Create(1000));
|
|
|
|
|
|
|
|
for (int useDiscardable = 0; useDiscardable <= 1; ++useDiscardable) {
|
|
|
|
const size_t size = 100;
|
|
|
|
|
|
|
|
// test with client as last owner
|
2015-08-27 14:41:13 +00:00
|
|
|
SkCachedData* data = test_locking(reporter, size, useDiscardable ? pool.get() : nullptr);
|
2014-10-08 12:17:12 +00:00
|
|
|
check_data(reporter, data, 2, kInCache, kLocked);
|
|
|
|
data->detachFromCacheAndUnref();
|
|
|
|
check_data(reporter, data, 1, kNotInCache, kLocked);
|
|
|
|
data->unref();
|
|
|
|
|
|
|
|
// test with cache as last owner
|
2015-08-27 14:41:13 +00:00
|
|
|
data = test_locking(reporter, size, useDiscardable ? pool.get() : nullptr);
|
2014-10-08 12:17:12 +00:00
|
|
|
check_data(reporter, data, 2, kInCache, kLocked);
|
|
|
|
data->unref();
|
|
|
|
check_data(reporter, data, 1, kInCache, kUnlocked);
|
|
|
|
data->detachFromCacheAndUnref();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|