Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(125)

Unified Diff: src/core/SkCachedData.cpp

Issue 592843003: Add SkCachedData and use it for SkMipMap (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: use natural bools for state tracking Created 6 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: src/core/SkCachedData.cpp
diff --git a/src/core/SkCachedData.cpp b/src/core/SkCachedData.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..213294b80e992d7075fbcb99d290bdf2c9dd3a3b
--- /dev/null
+++ b/src/core/SkCachedData.cpp
@@ -0,0 +1,170 @@
+/*
+ * 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_priv.h"
+#include "SkRefCnt.h"
+#include "SkDiscardableMemory.h"
+
+SkCachedData::SkCachedData(void* data, size_t size)
+ : fData(data)
+ , fSize(size)
+ , fRefCnt(1)
+ , fStorageType(kMalloc_StorageType)
+ , fInCache(false)
+ , fIsLocked(true)
+{
+ fStorage.fMalloc = data;
+}
+
+SkCachedData::SkCachedData(size_t size, SkDiscardableMemory* dm)
+ : fData(dm->data())
+ , fSize(size)
+ , fRefCnt(1)
+ , fStorageType(kDiscardableMemory_StorageType)
+ , fInCache(false)
+ , fIsLocked(true)
+{
+ fStorage.fDM = dm;
+}
+
+SkCachedData::~SkCachedData() {
+ switch (fStorageType) {
+ case kMalloc_StorageType:
+ sk_free(fStorage.fMalloc);
+ break;
+ case kDiscardableMemory_StorageType:
+ SkDELETE(fStorage.fDM);
+ break;
+ }
+}
+
+class SkCachedData::AutoMutexWritable {
+public:
+ AutoMutexWritable(const SkCachedData* cd) : fCD(const_cast<SkCachedData*>(cd)) {
+ fCD->get_mutex().acquire();
+ fCD->validate();
+ }
+ ~AutoMutexWritable() {
+ fCD->validate();
+ fCD->get_mutex().release();
+ }
+
+ SkCachedData* get() { return fCD; }
+ SkCachedData* operator->() { return fCD; }
+
+private:
+ SkCachedData* fCD;
+};
+
+void SkCachedData::internalRef(bool fromCache) const {
+ AutoMutexWritable writable(this);
mtklein 2014/09/27 14:47:49 I really like this pattern.
+
+ SkASSERT(!fromCache || !writable->fInCache); // we can only be in a cache once
+
+ if ((1 == writable->fRefCnt) && fInCache) {
+ writable->in_mutex_lock();
+ }
+
+ writable->fRefCnt += 1;
+ writable->fInCache |= fromCache;
mtklein 2014/09/27 14:47:49 Just a nit, but I'd go with ||= here. It really i
reed1 2014/09/27 17:25:58 ||= isn't legal afaik However, I did rewrite to u
+}
+
+bool SkCachedData::doInternalUnref(bool fromCache) const {
+ AutoMutexWritable writable(this);
+
+ switch (writable->fRefCnt) {
mtklein 2014/09/27 14:47:49 These guys might read better if you decrement firs
reed1 2014/09/27 17:25:58 Done.
+ case 1:
+ // we're going to be deleted, so we need to be unlocked (for DiscardableMemory)
+ if (writable->fIsLocked) {
+ writable->in_mutex_unlock();
+ }
+ break;
+ case 2:
+ if (fInCache && !fromCache) {
+ // If we're down to 1 owner, and that owner is the cache, this it is safe
+ // to unlock (and mutate fData) even if the cache is in a different thread,
+ // as the cache is NOT allowed to inspect or use fData.
+ writable->in_mutex_unlock();
+ }
+ break;
+ default:
+ break;
+ }
+
+ if (fromCache) {
+ SkASSERT(writable->fInCache);
+ writable->fInCache = false;
+ }
+
+ // return true when we need to be deleted
+ return 0 == --writable->fRefCnt;
+}
+
+void SkCachedData::internalUnref(bool fromCache) const {
+ if (this->doInternalUnref(fromCache)) {
+ // can't delete inside doInternalUnref, since it is locking a mutex (which we own)
+ SkDELETE(this);
+ }
+}
+
+void SkCachedData::in_mutex_lock() {
+ this->assert_in_mutex();
+
+ SkASSERT(!fIsLocked);
+ fIsLocked = true;
+
+ switch (fStorageType) {
+ case kMalloc_StorageType:
+ this->setData(fStorage.fMalloc);
+ break;
+ case kDiscardableMemory_StorageType:
+ if (fStorage.fDM->lock()) {
+ this->setData(fStorage.fDM->data());
+ } else {
+ this->setData(NULL); // signal failure to lock, contents are gone
+ }
+ break;
+ }
+}
+
+void SkCachedData::in_mutex_unlock() {
+ this->assert_in_mutex();
+
+ SkASSERT(fIsLocked);
+ fIsLocked = false;
+
+ switch (fStorageType) {
+ case kMalloc_StorageType:
+ // nothing to do/check
+ break;
+ case kDiscardableMemory_StorageType:
+ if (fData) { // did the previous lock succeed?
+ fStorage.fDM->unlock();
+ }
+ break;
+ }
+ this->setData(NULL); // signal that we're in an unlocked state
+}
+
+#ifdef SK_DEBUG
+void SkCachedData::validate() const {
+ if (fIsLocked) {
+ SkASSERT((fInCache && fRefCnt > 1) || !fInCache);
+ switch (fStorageType) {
+ case kMalloc_StorageType:
+ SkASSERT(fData == fStorage.fMalloc);
+ break;
+ case kDiscardableMemory_StorageType:
+ // fData can be null or the actual value, depending if DM's lock succeeded
+ break;
+ }
+ } else {
+ SkASSERT((fInCache && 1 == fRefCnt) || (0 == fRefCnt));
+ SkASSERT(NULL == fData);
+ }
+}
+#endif

Powered by Google App Engine
This is Rietveld 408576698