Add SkMaskCache

BUG=skia:

Review URL: https://codereview.chromium.org/670063004
This commit is contained in:
qiankun.miao 2014-10-23 07:58:17 -07:00 committed by Commit bot
parent 26979c8260
commit d9aac34ece
7 changed files with 338 additions and 0 deletions

View File

@ -104,6 +104,7 @@
'<(skia_src_path)/core/SkLineClipper.cpp',
'<(skia_src_path)/core/SkMallocPixelRef.cpp',
'<(skia_src_path)/core/SkMask.cpp',
'<(skia_src_path)/core/SkMaskCache.cpp',
'<(skia_src_path)/core/SkMaskFilter.cpp',
'<(skia_src_path)/core/SkMaskGamma.cpp',
'<(skia_src_path)/core/SkMaskGamma.h',

View File

@ -133,6 +133,7 @@
'../tests/LazyPtrTest.cpp',
'../tests/MD5Test.cpp',
'../tests/MallocPixelRefTest.cpp',
'../tests/MaskCacheTest.cpp',
'../tests/MathTest.cpp',
'../tests/Matrix44Test.cpp',
'../tests/MatrixClipCollapseTest.cpp',

173
src/core/SkMaskCache.cpp Normal file
View File

@ -0,0 +1,173 @@
/*
* 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 "SkMaskCache.h"
#define CHECK_LOCAL(localCache, localName, globalName, ...) \
((localCache) ? localCache->localName(__VA_ARGS__) : SkResourceCache::globalName(__VA_ARGS__))
struct MaskValue {
SkMask fMask;
SkCachedData* fData;
};
namespace {
static unsigned gRRectBlurKeyNamespaceLabel;
struct RRectBlurKey : public SkResourceCache::Key {
public:
RRectBlurKey(SkScalar sigma, const SkRRect& rrect, SkBlurStyle style, SkBlurQuality quality)
: fSigma(sigma)
, fRRect(rrect)
, fStyle(style)
, fQuality(quality) {
this->init(&gRRectBlurKeyNamespaceLabel,
sizeof(fSigma) + sizeof(fRRect) + sizeof(fStyle) + sizeof(fQuality));
}
SkScalar fSigma;
SkRRect fRRect;
int32_t fStyle;
int32_t fQuality;
};
struct RRectBlurRec : public SkResourceCache::Rec {
RRectBlurRec(RRectBlurKey key, const SkMask& mask, SkCachedData* data)
: fKey(key)
{
fValue.fMask = mask;
fValue.fData = data;
fValue.fData->attachToCacheAndRef();
}
~RRectBlurRec() {
fValue.fData->detachFromCacheAndUnref();
}
RRectBlurKey fKey;
MaskValue fValue;
virtual const Key& getKey() const SK_OVERRIDE { return fKey; }
virtual size_t bytesUsed() const SK_OVERRIDE { return sizeof(*this) + fValue.fData->size(); }
static bool Visitor(const SkResourceCache::Rec& baseRec, void* contextData) {
const RRectBlurRec& rec = static_cast<const RRectBlurRec&>(baseRec);
MaskValue* result = (MaskValue*)contextData;
SkCachedData* tmpData = rec.fValue.fData;
tmpData->ref();
if (NULL == tmpData->data()) {
tmpData->unref();
return false;
}
*result = rec.fValue;
return true;
}
};
} // namespace
SkCachedData* SkMaskCache::FindAndRef(SkScalar sigma, const SkRRect& rrect, SkBlurStyle style,
SkBlurQuality quality, SkMask* mask,
SkResourceCache* localCache) {
MaskValue result;
RRectBlurKey key(sigma, rrect, style, quality);
if (!CHECK_LOCAL(localCache, find, Find, key, RRectBlurRec::Visitor, &result)) {
return NULL;
}
*mask = result.fMask;
mask->fImage = (uint8_t*)(result.fData->data());
return result.fData;
}
void SkMaskCache::Add(SkScalar sigma, const SkRRect& rrect, SkBlurStyle style,
SkBlurQuality quality, const SkMask& mask, SkCachedData* data,
SkResourceCache* localCache) {
RRectBlurKey key(sigma, rrect, style, quality);
return CHECK_LOCAL(localCache, add, Add, SkNEW_ARGS(RRectBlurRec, (key, mask, data)));
}
//////////////////////////////////////////////////////////////////////////////////////////
namespace {
static unsigned gRectsBlurKeyNamespaceLabel;
struct RectsBlurKey : public SkResourceCache::Key {
public:
RectsBlurKey(SkScalar sigma, int count, const SkRect rects[], SkBlurStyle style)
: fSigma(sigma)
, fRecCount(count)
, fStyle(style){
SkASSERT(1 == count || 2 == count);
fRects[0] = SkRect::MakeEmpty();
fRects[1] = SkRect::MakeEmpty();
for (int i = 0; i < count; i++) {
fRects[i] = rects[i];
}
this->init(&gRectsBlurKeyNamespaceLabel,
sizeof(fSigma) + sizeof(fRecCount) + sizeof(fRects) + sizeof(fStyle));
}
SkScalar fSigma;
int fRecCount;
SkRect fRects[2];
int32_t fStyle;
};
struct RectsBlurRec : public SkResourceCache::Rec {
RectsBlurRec(RectsBlurKey key, const SkMask& mask, SkCachedData* data)
: fKey(key)
{
fValue.fMask = mask;
fValue.fData = data;
fValue.fData->attachToCacheAndRef();
}
~RectsBlurRec() {
fValue.fData->detachFromCacheAndUnref();
}
RectsBlurKey fKey;
MaskValue fValue;
virtual const Key& getKey() const SK_OVERRIDE { return fKey; }
virtual size_t bytesUsed() const SK_OVERRIDE { return sizeof(*this) + fValue.fData->size(); }
static bool Visitor(const SkResourceCache::Rec& baseRec, void* contextData) {
const RectsBlurRec& rec = static_cast<const RectsBlurRec&>(baseRec);
MaskValue* result = (MaskValue*)contextData;
SkCachedData* tmpData = rec.fValue.fData;
tmpData->ref();
if (NULL == tmpData->data()) {
tmpData->unref();
return false;
}
*result = rec.fValue;
return true;
}
};
} // namespace
SkCachedData* SkMaskCache::FindAndRef(SkScalar sigma, const SkRect rects[], int count,
SkBlurStyle style, SkMask* mask,
SkResourceCache* localCache) {
MaskValue result;
RectsBlurKey key(sigma, count, rects, style);
if (!CHECK_LOCAL(localCache, find, Find, key, RectsBlurRec::Visitor, &result)) {
return NULL;
}
*mask = result.fMask;
mask->fImage = (uint8_t*)(result.fData->data());
return result.fData;
}
void SkMaskCache::Add(SkScalar sigma, const SkRect rects[], int count, SkBlurStyle style,
const SkMask& mask, SkCachedData* data,
SkResourceCache* localCache) {
RectsBlurKey key(sigma, count, rects, style);
return CHECK_LOCAL(localCache, add, Add, SkNEW_ARGS(RectsBlurRec, (key, mask, data)));
}

42
src/core/SkMaskCache.h Normal file
View File

@ -0,0 +1,42 @@
/*
* Copyright 2014 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef SkMaskCache_DEFINED
#define SkMaskCache_DEFINED
#include "SkBlurTypes.h"
#include "SkCachedData.h"
#include "SkMask.h"
#include "SkRect.h"
#include "SkResourceCache.h"
#include "SkRRect.h"
class SkMaskCache {
public:
/**
* On success, return a ref to the SkCachedData that holds the pixels, and have mask
* already point to that memory.
*
* On failure, return NULL.
*/
static SkCachedData* FindAndRef(SkScalar sigma, const SkRRect& rrect, SkBlurStyle style,
SkBlurQuality quality, SkMask* mask,
SkResourceCache* localCache = NULL);
static SkCachedData* FindAndRef(SkScalar sigma, const SkRect rects[], int count,
SkBlurStyle style,SkMask* mask,
SkResourceCache* localCache = NULL);
/**
* Add a mask and its pixel-data to the cache.
*/
static void Add(SkScalar sigma, const SkRRect& rrect, SkBlurStyle style, SkBlurQuality quality,
const SkMask& mask, SkCachedData* data, SkResourceCache* localCache = NULL);
static void Add(SkScalar sigma, const SkRect rects[], int count, SkBlurStyle style,
const SkMask& mask, SkCachedData* data, SkResourceCache* localCache = NULL);
};
#endif

View File

@ -303,6 +303,15 @@ size_t SkResourceCache::setTotalByteLimit(size_t newLimit) {
return prevLimit;
}
SkCachedData* SkResourceCache::newCachedData(size_t bytes) {
if (fDiscardableFactory) {
SkDiscardableMemory* dm = fDiscardableFactory(bytes);
return dm ? SkNEW_ARGS(SkCachedData, (bytes, dm)) : NULL;
} else {
return SkNEW_ARGS(SkCachedData, (sk_malloc_throw(bytes), bytes));
}
}
///////////////////////////////////////////////////////////////////////////////
void SkResourceCache::detach(Rec* rec) {
@ -482,6 +491,11 @@ SkBitmap::Allocator* SkResourceCache::GetAllocator() {
return get_cache()->allocator();
}
SkCachedData* SkResourceCache::NewCachedData(size_t bytes) {
SkAutoMutexAcquire am(gMutex);
return get_cache()->newCachedData(bytes);
}
void SkResourceCache::Dump() {
SkAutoMutexAcquire am(gMutex);
get_cache()->dump();

View File

@ -137,6 +137,8 @@ public:
*/
static SkBitmap::Allocator* GetAllocator();
static SkCachedData* NewCachedData(size_t bytes);
/**
* Call SkDebugf() with diagnostic information about the state of the cache
*/

105
tests/MaskCacheTest.cpp Normal file
View File

@ -0,0 +1,105 @@
/*
* 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 "SkMaskCache.h"
#include "SkResourceCache.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));
bool isLocked = (data->data() != NULL);
REPORTER_ASSERT(reporter, isLocked == (lockedState == kLocked));
}
DEF_TEST(RRectMaskCache, reporter) {
SkResourceCache cache(1024);
SkScalar sigma = 0.8f;
SkRect rect = SkRect::MakeWH(100, 100);
SkRRect rrect;
rrect.setRectXY(rect, 30, 30);
SkBlurStyle style = kNormal_SkBlurStyle;
SkBlurQuality quality = kLow_SkBlurQuality;
SkMask mask;
SkCachedData* data = SkMaskCache::FindAndRef(sigma, rrect, style, quality, &mask, &cache);
REPORTER_ASSERT(reporter, NULL == data);
size_t size = 256;
data = cache.newCachedData(size);
memset(data->writable_data(), 0xff, size);
mask.fBounds.setXYWH(0, 0, 100, 100);
mask.fRowBytes = 100;
mask.fFormat = SkMask::kBW_Format;
SkMaskCache::Add(sigma, rrect, style, quality, mask, data, &cache);
check_data(reporter, data, 2, kInCache, kLocked);
data->unref();
check_data(reporter, data, 1, kInCache, kUnlocked);
sk_bzero(&mask, sizeof(mask));
data = SkMaskCache::FindAndRef(sigma, rrect, style, quality, &mask, &cache);
REPORTER_ASSERT(reporter, data);
REPORTER_ASSERT(reporter, data->size() == size);
REPORTER_ASSERT(reporter, mask.fBounds.top() == 0 && mask.fBounds.bottom() == 100);
REPORTER_ASSERT(reporter, data->data() == (const void*)mask.fImage);
check_data(reporter, data, 2, kInCache, kLocked);
cache.purgeAll();
check_data(reporter, data, 1, kNotInCache, kLocked);
data->unref();
}
DEF_TEST(RectsMaskCache, reporter) {
SkResourceCache cache(1024);
SkScalar sigma = 0.8f;
SkRect rect = SkRect::MakeWH(100, 100);
SkRect rects[2] = {rect};
SkBlurStyle style = kNormal_SkBlurStyle;
SkMask mask;
SkCachedData* data = SkMaskCache::FindAndRef(sigma, rects, 1, style, &mask, &cache);
REPORTER_ASSERT(reporter, NULL == data);
size_t size = 256;
data = cache.newCachedData(size);
memset(data->writable_data(), 0xff, size);
mask.fBounds.setXYWH(0, 0, 100, 100);
mask.fRowBytes = 100;
mask.fFormat = SkMask::kBW_Format;
SkMaskCache::Add(sigma, rects, 1, style, mask, data, &cache);
check_data(reporter, data, 2, kInCache, kLocked);
data->unref();
check_data(reporter, data, 1, kInCache, kUnlocked);
sk_bzero(&mask, sizeof(mask));
data = SkMaskCache::FindAndRef(sigma, rects, 1, style, &mask, &cache);
REPORTER_ASSERT(reporter, data);
REPORTER_ASSERT(reporter, data->size() == size);
REPORTER_ASSERT(reporter, mask.fBounds.top() == 0 && mask.fBounds.bottom() == 100);
REPORTER_ASSERT(reporter, data->data() == (const void*)mask.fImage);
check_data(reporter, data, 2, kInCache, kLocked);
cache.purgeAll();
check_data(reporter, data, 1, kNotInCache, kLocked);
data->unref();
}