Use SkImage to manage mip map cache purging, not Bitmap/PixelRef

Lazy and GPU images manage the notification themselves, but raster
images now forward the notification request to the pixelRef.

Bug: skia:
Change-Id: I93e0ebd3749e3f7dbd506466299fde8923982435
Reviewed-on: https://skia-review.googlesource.com/c/161830
Commit-Queue: Mike Klein <mtklein@google.com>
Reviewed-by: Mike Klein <mtklein@google.com>
This commit is contained in:
Brian Osman 2018-10-15 10:33:54 -04:00 committed by Skia Commit-Bot
parent 11dd1ab3b9
commit 087c917670
6 changed files with 44 additions and 24 deletions

View File

@ -7,6 +7,7 @@
#include "SkAtomics.h"
#include "SkBitmapCache.h"
#include "SkBitmapProvider.h"
#include "SkImage.h"
#include "SkResourceCache.h"
#include "SkMipMap.h"
@ -342,12 +343,18 @@ static SkResourceCache::DiscardableFactory get_fact(SkResourceCache* localCache)
: SkResourceCache::GetDiscardableFactory();
}
const SkMipMap* SkMipMapCache::AddAndRef(const SkBitmap& src, SkResourceCache* localCache) {
const SkMipMap* SkMipMapCache::AddAndRef(const SkBitmapProvider& provider,
SkResourceCache* localCache) {
SkBitmap src;
if (!provider.asBitmap(&src)) {
return nullptr;
}
SkMipMap* mipmap = SkMipMap::Build(src, get_fact(localCache));
if (mipmap) {
MipMapRec* rec = new MipMapRec(SkBitmapCacheDesc::Make(src), mipmap);
MipMapRec* rec = new MipMapRec(provider.makeCacheDesc(), mipmap);
CHECK_LOCAL(localCache, add, Add, rec);
src.pixelRef()->notifyAddedToCache();
provider.notifyAddedToCache();
}
return mipmap;
}

View File

@ -11,6 +11,7 @@
#include "SkBitmap.h"
#include "SkMipMap.h"
class SkBitmapProvider;
class SkImage;
class SkResourceCache;
@ -61,7 +62,8 @@ class SkMipMapCache {
public:
static const SkMipMap* FindAndRef(const SkBitmapCacheDesc&,
SkResourceCache* localCache = nullptr);
static const SkMipMap* AddAndRef(const SkBitmap& src, SkResourceCache* localCache = nullptr);
static const SkMipMap* AddAndRef(const SkBitmapProvider&,
SkResourceCache* localCache = nullptr);
};
#endif

View File

@ -78,11 +78,7 @@ bool SkBitmapController::State::processMediumRequest(const SkBitmapProvider& pro
if (invScaleSize.width() > SK_Scalar1 || invScaleSize.height() > SK_Scalar1) {
fCurrMip.reset(SkMipMapCache::FindAndRef(provider.makeCacheDesc()));
if (nullptr == fCurrMip.get()) {
SkBitmap orig;
if (!provider.asBitmap(&orig)) {
return false;
}
fCurrMip.reset(SkMipMapCache::AddAndRef(orig));
fCurrMip.reset(SkMipMapCache::AddAndRef(provider));
if (nullptr == fCurrMip.get()) {
return false;
}

View File

@ -85,7 +85,7 @@ public:
// Call when this image is part of the key to a resourcecache entry. This allows the cache
// to know automatically those entries can be purged when this SkImage deleted.
void notifyAddedToRasterCache() const {
virtual void notifyAddedToRasterCache() const {
fAddedToRasterCache.store(true);
}

View File

@ -106,6 +106,13 @@ public:
sk_sp<SkImage> onMakeColorSpace(sk_sp<SkColorSpace>) const override;
bool onIsValid(GrContext* context) const override { return true; }
void notifyAddedToRasterCache() const override {
// We explicitly DON'T want to call INHERITED::notifyAddedToRasterCache. That ties the
// lifetime of derived/cached resources to the image. In this case, we only want cached
// data (eg mips) tied to the lifetime of the underlying pixelRef.
SkASSERT(fBitmap.pixelRef());
fBitmap.pixelRef()->notifyAddedToCache();
}
#if SK_SUPPORT_GPU
sk_sp<GrTextureProxy> refPinnedTextureProxy(uint32_t* uniqueID) const override;

View File

@ -7,6 +7,7 @@
#include "Test.h"
#include "SkBitmapCache.h"
#include "SkBitmapProvider.h"
#include "SkCanvas.h"
#include "SkDiscardableMemoryPool.h"
#include "SkGraphics.h"
@ -43,15 +44,18 @@ static void test_mipmapcache(skiatest::Reporter* reporter, SkResourceCache* cach
SkBitmap src;
src.allocN32Pixels(5, 5);
src.setImmutable();
sk_sp<SkImage> img = SkImage::MakeFromBitmap(src);
SkBitmapProvider provider(img.get());
const auto desc = provider.makeCacheDesc();
const SkMipMap* mipmap = SkMipMapCache::FindAndRef(SkBitmapCacheDesc::Make(src), cache);
const SkMipMap* mipmap = SkMipMapCache::FindAndRef(desc, cache);
REPORTER_ASSERT(reporter, nullptr == mipmap);
mipmap = SkMipMapCache::AddAndRef(src, cache);
mipmap = SkMipMapCache::AddAndRef(provider, cache);
REPORTER_ASSERT(reporter, mipmap);
{
const SkMipMap* mm = SkMipMapCache::FindAndRef(SkBitmapCacheDesc::Make(src), cache);
const SkMipMap* mm = SkMipMapCache::FindAndRef(desc, cache);
REPORTER_ASSERT(reporter, mm);
REPORTER_ASSERT(reporter, mm == mipmap);
mm->unref();
@ -65,7 +69,7 @@ static void test_mipmapcache(skiatest::Reporter* reporter, SkResourceCache* cach
check_data(reporter, mipmap, 1, kInCache, kNotLocked);
// find us again
mipmap = SkMipMapCache::FindAndRef(SkBitmapCacheDesc::Make(src), cache);
mipmap = SkMipMapCache::FindAndRef(desc, cache);
check_data(reporter, mipmap, 2, kInCache, kLocked);
cache->purgeAll();
@ -78,25 +82,29 @@ static void test_mipmap_notify(skiatest::Reporter* reporter, SkResourceCache* ca
const int N = 3;
SkBitmap src[N];
sk_sp<SkImage> img[N];
SkBitmapCacheDesc desc[N];
for (int i = 0; i < N; ++i) {
src[i].allocN32Pixels(5, 5);
src[i].setImmutable();
SkMipMapCache::AddAndRef(src[i], cache)->unref();
img[i] = SkImage::MakeFromBitmap(src[i]);
SkBitmapProvider provider(img[i].get());
SkMipMapCache::AddAndRef(provider, cache)->unref();
desc[i] = provider.makeCacheDesc();
}
for (int i = 0; i < N; ++i) {
const auto desc = SkBitmapCacheDesc::Make(src[i]);
const SkMipMap* mipmap = SkMipMapCache::FindAndRef(desc, cache);
if (cache) {
// if cache is null, we're working on the global cache, and other threads might purge
// it, making this check fragile.
REPORTER_ASSERT(reporter, mipmap);
}
const SkMipMap* mipmap = SkMipMapCache::FindAndRef(desc[i], cache);
// We're always using a local cache, so we know we won't be purged by other threads
REPORTER_ASSERT(reporter, mipmap);
SkSafeUnref(mipmap);
src[i].reset(); // delete the underlying pixelref, which *should* remove us from the cache
img[i].reset(); // delete the image, which *should not* remove us from the cache
mipmap = SkMipMapCache::FindAndRef(desc[i], cache);
REPORTER_ASSERT(reporter, mipmap);
mipmap = SkMipMapCache::FindAndRef(desc, cache);
src[i].reset(); // delete the underlying pixelref, which *should* remove us from the cache
mipmap = SkMipMapCache::FindAndRef(desc[i], cache);
REPORTER_ASSERT(reporter, !mipmap);
}
}