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 #ifdef SK_SUPPORT_LEGACY_COLORTABLE 52 SkPixelRef::SkPixelRef(int width, int height, void* pixels, size_t rowBytes, sk_sp<SkColorTable>) 53 : fWidth(width) 54 , fHeight(height) 55 , fPixels(pixels) 56 , fRowBytes(rowBytes) 57 #ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK 58 , fStableID(SkNextID::ImageID()) 59 #endif 60 { 61 #ifdef SK_TRACE_PIXELREF_LIFETIME 62 SkDebugf(" pixelref %d\n", sk_atomic_inc(&gInstCounter)); 63 #endif 64 65 this->needsNewGenID(); 66 fMutability = kMutable; 67 fAddedToCache.store(false); 68 } 69 #endif 70 71 SkPixelRef::~SkPixelRef() { 72 #ifdef SK_TRACE_PIXELREF_LIFETIME 73 SkDebugf("~pixelref %d\n", sk_atomic_dec(&gInstCounter) - 1); 74 #endif 75 this->callGenIDChangeListeners(); 76 } 77 78 // This is undefined if there are clients in-flight trying to use us 79 void SkPixelRef::android_only_reset(int width, int height, size_t rowBytes 80 #ifdef SK_SUPPORT_LEGACY_COLORTABLE 81 , sk_sp<SkColorTable> ctable 82 #endif 83 ) { 84 fWidth = width; 85 fHeight = height; 86 fRowBytes = rowBytes; 87 // note: we do not change fPixels 88 89 // conservative, since its possible the "new" settings are the same as the old. 90 this->notifyPixelsChanged(); 91 } 92 93 void SkPixelRef::needsNewGenID() { 94 fTaggedGenID.store(0); 95 SkASSERT(!this->genIDIsUnique()); // This method isn't threadsafe, so the assert should be fine. 96 } 97 98 uint32_t SkPixelRef::getGenerationID() const { 99 uint32_t id = fTaggedGenID.load(); 100 if (0 == id) { 101 uint32_t next = SkNextID::ImageID() | 1u; 102 if (fTaggedGenID.compare_exchange(&id, next)) { 103 id = next; // There was no race or we won the race. fTaggedGenID is next now. 104 } else { 105 // We lost a race to set fTaggedGenID. compare_exchange() filled id with the winner. 106 } 107 // We can't quite SkASSERT(this->genIDIsUnique()). It could be non-unique 108 // if we got here via the else path (pretty unlikely, but possible). 109 } 110 return id & ~1u; // Mask off bottom unique bit. 111 } 112 113 void SkPixelRef::addGenIDChangeListener(GenIDChangeListener* listener) { 114 if (nullptr == listener || !this->genIDIsUnique()) { 115 // No point in tracking this if we're not going to call it. 116 delete listener; 117 return; 118 } 119 *fGenIDChangeListeners.append() = listener; 120 } 121 122 // we need to be called *before* the genID gets changed or zerod 123 void SkPixelRef::callGenIDChangeListeners() { 124 // We don't invalidate ourselves if we think another SkPixelRef is sharing our genID. 125 if (this->genIDIsUnique()) { 126 for (int i = 0; i < fGenIDChangeListeners.count(); i++) { 127 fGenIDChangeListeners[i]->onChange(); 128 } 129 130 // TODO: SkAtomic could add "old_value = atomic.xchg(new_value)" to make this clearer. 131 if (fAddedToCache.load()) { 132 SkNotifyBitmapGenIDIsStale(this->getGenerationID()); 133 fAddedToCache.store(false); 134 } 135 } 136 // Listeners get at most one shot, so whether these triggered or not, blow them away. 137 fGenIDChangeListeners.deleteAll(); 138 } 139 140 void SkPixelRef::notifyPixelsChanged() { 141 #ifdef SK_DEBUG 142 if (this->isImmutable()) { 143 SkDebugf("========== notifyPixelsChanged called on immutable pixelref"); 144 } 145 #endif 146 this->callGenIDChangeListeners(); 147 this->needsNewGenID(); 148 this->onNotifyPixelsChanged(); 149 } 150 151 void SkPixelRef::setImmutable() { 152 fMutability = kImmutable; 153 } 154 155 void SkPixelRef::setImmutableWithID(uint32_t genID) { 156 /* 157 * We are forcing the genID to match an external value. The caller must ensure that this 158 * value does not conflict with other content. 159 * 160 * One use is to force this pixelref's id to match an SkImage's id 161 */ 162 fMutability = kImmutable; 163 fTaggedGenID.store(genID); 164 } 165 166 void SkPixelRef::setTemporarilyImmutable() { 167 SkASSERT(fMutability != kImmutable); 168 fMutability = kTemporarilyImmutable; 169 } 170 171 void SkPixelRef::restoreMutability() { 172 SkASSERT(fMutability != kImmutable); 173 fMutability = kMutable; 174 } 175 176 void SkPixelRef::onNotifyPixelsChanged() { } 177