1 /* 2 * Copyright 2011 Google Inc. 3 * 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7 8 #include "SkBitmapCache.h" 9 #include "SkMutex.h" 10 #include "SkPixelRef.h" 11 #include "SkTraceEvent.h" 12 13 //#define SK_TRACE_PIXELREF_LIFETIME 14 15 #include "SkNextID.h" 16 17 uint32_t SkNextID::ImageID() { 18 static uint32_t gID = 0; 19 uint32_t id; 20 // Loop in case our global wraps around, as we never want to return a 0. 21 do { 22 id = sk_atomic_fetch_add(&gID, 2u) + 2; // Never set the low bit. 23 } while (0 == id); 24 return id; 25 } 26 27 /////////////////////////////////////////////////////////////////////////////// 28 29 #ifdef SK_TRACE_PIXELREF_LIFETIME 30 static int32_t gInstCounter; 31 #endif 32 33 SkPixelRef::SkPixelRef(int width, int height, void* pixels, size_t rowBytes) 34 : fWidth(width) 35 , fHeight(height) 36 , fPixels(pixels) 37 , fRowBytes(rowBytes) 38 #ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK 39 , fStableID(SkNextID::ImageID()) 40 #endif 41 { 42 #ifdef SK_TRACE_PIXELREF_LIFETIME 43 SkDebugf(" pixelref %d\n", sk_atomic_inc(&gInstCounter)); 44 #endif 45 46 this->needsNewGenID(); 47 fMutability = kMutable; 48 fAddedToCache.store(false); 49 } 50 51 SkPixelRef::~SkPixelRef() { 52 #ifdef SK_TRACE_PIXELREF_LIFETIME 53 SkDebugf("~pixelref %d\n", sk_atomic_dec(&gInstCounter) - 1); 54 #endif 55 this->callGenIDChangeListeners(); 56 } 57 58 // This is undefined if there are clients in-flight trying to use us 59 void SkPixelRef::android_only_reset(int width, int height, size_t rowBytes) { 60 fWidth = width; 61 fHeight = height; 62 fRowBytes = rowBytes; 63 // note: we do not change fPixels 64 65 // conservative, since its possible the "new" settings are the same as the old. 66 this->notifyPixelsChanged(); 67 } 68 69 void SkPixelRef::needsNewGenID() { 70 fTaggedGenID.store(0); 71 SkASSERT(!this->genIDIsUnique()); // This method isn't threadsafe, so the assert should be fine. 72 } 73 74 uint32_t SkPixelRef::getGenerationID() const { 75 uint32_t id = fTaggedGenID.load(); 76 if (0 == id) { 77 uint32_t next = SkNextID::ImageID() | 1u; 78 if (fTaggedGenID.compare_exchange(&id, next)) { 79 id = next; // There was no race or we won the race. fTaggedGenID is next now. 80 } else { 81 // We lost a race to set fTaggedGenID. compare_exchange() filled id with the winner. 82 } 83 // We can't quite SkASSERT(this->genIDIsUnique()). It could be non-unique 84 // if we got here via the else path (pretty unlikely, but possible). 85 } 86 return id & ~1u; // Mask off bottom unique bit. 87 } 88 89 void SkPixelRef::addGenIDChangeListener(GenIDChangeListener* listener) { 90 if (nullptr == listener || !this->genIDIsUnique()) { 91 // No point in tracking this if we're not going to call it. 92 delete listener; 93 return; 94 } 95 *fGenIDChangeListeners.append() = listener; 96 } 97 98 // we need to be called *before* the genID gets changed or zerod 99 void SkPixelRef::callGenIDChangeListeners() { 100 // We don't invalidate ourselves if we think another SkPixelRef is sharing our genID. 101 if (this->genIDIsUnique()) { 102 for (int i = 0; i < fGenIDChangeListeners.count(); i++) { 103 fGenIDChangeListeners[i]->onChange(); 104 } 105 106 // TODO: SkAtomic could add "old_value = atomic.xchg(new_value)" to make this clearer. 107 if (fAddedToCache.load()) { 108 SkNotifyBitmapGenIDIsStale(this->getGenerationID()); 109 fAddedToCache.store(false); 110 } 111 } 112 // Listeners get at most one shot, so whether these triggered or not, blow them away. 113 fGenIDChangeListeners.deleteAll(); 114 } 115 116 void SkPixelRef::notifyPixelsChanged() { 117 #ifdef SK_DEBUG 118 if (this->isImmutable()) { 119 SkDebugf("========== notifyPixelsChanged called on immutable pixelref"); 120 } 121 #endif 122 this->callGenIDChangeListeners(); 123 this->needsNewGenID(); 124 this->onNotifyPixelsChanged(); 125 } 126 127 void SkPixelRef::setImmutable() { 128 fMutability = kImmutable; 129 } 130 131 void SkPixelRef::setImmutableWithID(uint32_t genID) { 132 /* 133 * We are forcing the genID to match an external value. The caller must ensure that this 134 * value does not conflict with other content. 135 * 136 * One use is to force this pixelref's id to match an SkImage's id 137 */ 138 fMutability = kImmutable; 139 fTaggedGenID.store(genID); 140 } 141 142 void SkPixelRef::setTemporarilyImmutable() { 143 SkASSERT(fMutability != kImmutable); 144 fMutability = kTemporarilyImmutable; 145 } 146 147 void SkPixelRef::restoreMutability() { 148 SkASSERT(fMutability != kImmutable); 149 fMutability = kMutable; 150 } 151 152 void SkPixelRef::onNotifyPixelsChanged() { } 153