1cb93a386Sopenharmony_ci/* 2cb93a386Sopenharmony_ci * Copyright 2018 Google Inc. 3cb93a386Sopenharmony_ci * 4cb93a386Sopenharmony_ci * Use of this source code is governed by a BSD-style license that can be 5cb93a386Sopenharmony_ci * found in the LICENSE file. 6cb93a386Sopenharmony_ci */ 7cb93a386Sopenharmony_ci 8cb93a386Sopenharmony_ci 9cb93a386Sopenharmony_ci#include "src/gpu/gradients/GrGradientBitmapCache.h" 10cb93a386Sopenharmony_ci 11cb93a386Sopenharmony_ci#include "include/private/SkFloatBits.h" 12cb93a386Sopenharmony_ci#include "include/private/SkHalf.h" 13cb93a386Sopenharmony_ci#include "include/private/SkMalloc.h" 14cb93a386Sopenharmony_ci#include "include/private/SkTemplates.h" 15cb93a386Sopenharmony_ci 16cb93a386Sopenharmony_ci#include <functional> 17cb93a386Sopenharmony_ci 18cb93a386Sopenharmony_cistruct GrGradientBitmapCache::Entry { 19cb93a386Sopenharmony_ci Entry* fPrev; 20cb93a386Sopenharmony_ci Entry* fNext; 21cb93a386Sopenharmony_ci 22cb93a386Sopenharmony_ci void* fBuffer; 23cb93a386Sopenharmony_ci size_t fSize; 24cb93a386Sopenharmony_ci SkBitmap fBitmap; 25cb93a386Sopenharmony_ci 26cb93a386Sopenharmony_ci Entry(const void* buffer, size_t size, const SkBitmap& bm) 27cb93a386Sopenharmony_ci : fPrev(nullptr), 28cb93a386Sopenharmony_ci fNext(nullptr), 29cb93a386Sopenharmony_ci fBitmap(bm) { 30cb93a386Sopenharmony_ci fBuffer = sk_malloc_throw(size); 31cb93a386Sopenharmony_ci fSize = size; 32cb93a386Sopenharmony_ci memcpy(fBuffer, buffer, size); 33cb93a386Sopenharmony_ci } 34cb93a386Sopenharmony_ci 35cb93a386Sopenharmony_ci ~Entry() { sk_free(fBuffer); } 36cb93a386Sopenharmony_ci 37cb93a386Sopenharmony_ci bool equals(const void* buffer, size_t size) const { 38cb93a386Sopenharmony_ci return (fSize == size) && !memcmp(fBuffer, buffer, size); 39cb93a386Sopenharmony_ci } 40cb93a386Sopenharmony_ci}; 41cb93a386Sopenharmony_ci 42cb93a386Sopenharmony_ciGrGradientBitmapCache::GrGradientBitmapCache(int max, int res) 43cb93a386Sopenharmony_ci : fMaxEntries(max) 44cb93a386Sopenharmony_ci , fResolution(res) { 45cb93a386Sopenharmony_ci fEntryCount = 0; 46cb93a386Sopenharmony_ci fHead = fTail = nullptr; 47cb93a386Sopenharmony_ci 48cb93a386Sopenharmony_ci this->validate(); 49cb93a386Sopenharmony_ci} 50cb93a386Sopenharmony_ci 51cb93a386Sopenharmony_ciGrGradientBitmapCache::~GrGradientBitmapCache() { 52cb93a386Sopenharmony_ci this->validate(); 53cb93a386Sopenharmony_ci 54cb93a386Sopenharmony_ci Entry* entry = fHead; 55cb93a386Sopenharmony_ci while (entry) { 56cb93a386Sopenharmony_ci Entry* next = entry->fNext; 57cb93a386Sopenharmony_ci delete entry; 58cb93a386Sopenharmony_ci entry = next; 59cb93a386Sopenharmony_ci } 60cb93a386Sopenharmony_ci} 61cb93a386Sopenharmony_ci 62cb93a386Sopenharmony_ciGrGradientBitmapCache::Entry* GrGradientBitmapCache::release(Entry* entry) const { 63cb93a386Sopenharmony_ci if (entry->fPrev) { 64cb93a386Sopenharmony_ci SkASSERT(fHead != entry); 65cb93a386Sopenharmony_ci entry->fPrev->fNext = entry->fNext; 66cb93a386Sopenharmony_ci } else { 67cb93a386Sopenharmony_ci SkASSERT(fHead == entry); 68cb93a386Sopenharmony_ci fHead = entry->fNext; 69cb93a386Sopenharmony_ci } 70cb93a386Sopenharmony_ci if (entry->fNext) { 71cb93a386Sopenharmony_ci SkASSERT(fTail != entry); 72cb93a386Sopenharmony_ci entry->fNext->fPrev = entry->fPrev; 73cb93a386Sopenharmony_ci } else { 74cb93a386Sopenharmony_ci SkASSERT(fTail == entry); 75cb93a386Sopenharmony_ci fTail = entry->fPrev; 76cb93a386Sopenharmony_ci } 77cb93a386Sopenharmony_ci return entry; 78cb93a386Sopenharmony_ci} 79cb93a386Sopenharmony_ci 80cb93a386Sopenharmony_civoid GrGradientBitmapCache::attachToHead(Entry* entry) const { 81cb93a386Sopenharmony_ci entry->fPrev = nullptr; 82cb93a386Sopenharmony_ci entry->fNext = fHead; 83cb93a386Sopenharmony_ci if (fHead) { 84cb93a386Sopenharmony_ci fHead->fPrev = entry; 85cb93a386Sopenharmony_ci } else { 86cb93a386Sopenharmony_ci fTail = entry; 87cb93a386Sopenharmony_ci } 88cb93a386Sopenharmony_ci fHead = entry; 89cb93a386Sopenharmony_ci} 90cb93a386Sopenharmony_ci 91cb93a386Sopenharmony_cibool GrGradientBitmapCache::find(const void* buffer, size_t size, SkBitmap* bm) const { 92cb93a386Sopenharmony_ci AutoValidate av(this); 93cb93a386Sopenharmony_ci 94cb93a386Sopenharmony_ci Entry* entry = fHead; 95cb93a386Sopenharmony_ci while (entry) { 96cb93a386Sopenharmony_ci if (entry->equals(buffer, size)) { 97cb93a386Sopenharmony_ci if (bm) { 98cb93a386Sopenharmony_ci *bm = entry->fBitmap; 99cb93a386Sopenharmony_ci } 100cb93a386Sopenharmony_ci // move to the head of our list, so we purge it last 101cb93a386Sopenharmony_ci this->release(entry); 102cb93a386Sopenharmony_ci this->attachToHead(entry); 103cb93a386Sopenharmony_ci return true; 104cb93a386Sopenharmony_ci } 105cb93a386Sopenharmony_ci entry = entry->fNext; 106cb93a386Sopenharmony_ci } 107cb93a386Sopenharmony_ci return false; 108cb93a386Sopenharmony_ci} 109cb93a386Sopenharmony_ci 110cb93a386Sopenharmony_civoid GrGradientBitmapCache::add(const void* buffer, size_t len, const SkBitmap& bm) { 111cb93a386Sopenharmony_ci AutoValidate av(this); 112cb93a386Sopenharmony_ci 113cb93a386Sopenharmony_ci if (fEntryCount == fMaxEntries) { 114cb93a386Sopenharmony_ci SkASSERT(fTail); 115cb93a386Sopenharmony_ci delete this->release(fTail); 116cb93a386Sopenharmony_ci fEntryCount -= 1; 117cb93a386Sopenharmony_ci } 118cb93a386Sopenharmony_ci 119cb93a386Sopenharmony_ci Entry* entry = new Entry(buffer, len, bm); 120cb93a386Sopenharmony_ci this->attachToHead(entry); 121cb93a386Sopenharmony_ci fEntryCount += 1; 122cb93a386Sopenharmony_ci} 123cb93a386Sopenharmony_ci 124cb93a386Sopenharmony_ci/////////////////////////////////////////////////////////////////////////////// 125cb93a386Sopenharmony_ci 126cb93a386Sopenharmony_ci 127cb93a386Sopenharmony_civoid GrGradientBitmapCache::fillGradient(const SkPMColor4f* colors, const SkScalar* positions, 128cb93a386Sopenharmony_ci int count, SkColorType colorType, SkBitmap* bitmap) { 129cb93a386Sopenharmony_ci SkHalf* pixelsF16 = reinterpret_cast<SkHalf*>(bitmap->getPixels()); 130cb93a386Sopenharmony_ci uint32_t* pixels32 = reinterpret_cast<uint32_t*>(bitmap->getPixels()); 131cb93a386Sopenharmony_ci 132cb93a386Sopenharmony_ci typedef std::function<void(const Sk4f&, int)> pixelWriteFn_t; 133cb93a386Sopenharmony_ci 134cb93a386Sopenharmony_ci pixelWriteFn_t writeF16Pixel = [&](const Sk4f& x, int index) { 135cb93a386Sopenharmony_ci Sk4h c = SkFloatToHalf_finite_ftz(x); 136cb93a386Sopenharmony_ci pixelsF16[4*index+0] = c[0]; 137cb93a386Sopenharmony_ci pixelsF16[4*index+1] = c[1]; 138cb93a386Sopenharmony_ci pixelsF16[4*index+2] = c[2]; 139cb93a386Sopenharmony_ci pixelsF16[4*index+3] = c[3]; 140cb93a386Sopenharmony_ci }; 141cb93a386Sopenharmony_ci pixelWriteFn_t write8888Pixel = [&](const Sk4f& c, int index) { 142cb93a386Sopenharmony_ci pixels32[index] = Sk4f_toL32(c); 143cb93a386Sopenharmony_ci }; 144cb93a386Sopenharmony_ci 145cb93a386Sopenharmony_ci pixelWriteFn_t writePixel = 146cb93a386Sopenharmony_ci (colorType == kRGBA_F16_SkColorType) ? writeF16Pixel : write8888Pixel; 147cb93a386Sopenharmony_ci 148cb93a386Sopenharmony_ci int prevIndex = 0; 149cb93a386Sopenharmony_ci for (int i = 1; i < count; i++) { 150cb93a386Sopenharmony_ci // Historically, stops have been mapped to [0, 256], with 256 then nudged to the next 151cb93a386Sopenharmony_ci // smaller value, then truncate for the texture index. This seems to produce the best 152cb93a386Sopenharmony_ci // results for some common distributions, so we preserve the behavior. 153cb93a386Sopenharmony_ci int nextIndex = std::min(positions[i] * fResolution, 154cb93a386Sopenharmony_ci SkIntToScalar(fResolution - 1)); 155cb93a386Sopenharmony_ci 156cb93a386Sopenharmony_ci if (nextIndex > prevIndex) { 157cb93a386Sopenharmony_ci Sk4f c0 = Sk4f::Load(colors[i - 1].vec()), 158cb93a386Sopenharmony_ci c1 = Sk4f::Load(colors[i ].vec()); 159cb93a386Sopenharmony_ci 160cb93a386Sopenharmony_ci Sk4f step = Sk4f(1.0f / static_cast<float>(nextIndex - prevIndex)); 161cb93a386Sopenharmony_ci Sk4f delta = (c1 - c0) * step; 162cb93a386Sopenharmony_ci 163cb93a386Sopenharmony_ci for (int curIndex = prevIndex; curIndex <= nextIndex; ++curIndex) { 164cb93a386Sopenharmony_ci writePixel(c0, curIndex); 165cb93a386Sopenharmony_ci c0 += delta; 166cb93a386Sopenharmony_ci } 167cb93a386Sopenharmony_ci } 168cb93a386Sopenharmony_ci prevIndex = nextIndex; 169cb93a386Sopenharmony_ci } 170cb93a386Sopenharmony_ci SkASSERT(prevIndex == fResolution - 1); 171cb93a386Sopenharmony_ci} 172cb93a386Sopenharmony_ci 173cb93a386Sopenharmony_civoid GrGradientBitmapCache::getGradient(const SkPMColor4f* colors, const SkScalar* positions, 174cb93a386Sopenharmony_ci int count, SkColorType colorType, SkAlphaType alphaType, SkBitmap* bitmap) { 175cb93a386Sopenharmony_ci // build our key: [numColors + colors[] + positions[] + alphaType + colorType ] 176cb93a386Sopenharmony_ci static_assert(sizeof(SkPMColor4f) % sizeof(int32_t) == 0, ""); 177cb93a386Sopenharmony_ci const int colorsAsIntCount = count * sizeof(SkPMColor4f) / sizeof(int32_t); 178cb93a386Sopenharmony_ci int keyCount = 1 + colorsAsIntCount + 1 + 1; 179cb93a386Sopenharmony_ci if (count > 2) { 180cb93a386Sopenharmony_ci keyCount += count - 1; 181cb93a386Sopenharmony_ci } 182cb93a386Sopenharmony_ci 183cb93a386Sopenharmony_ci SkAutoSTMalloc<64, int32_t> storage(keyCount); 184cb93a386Sopenharmony_ci int32_t* buffer = storage.get(); 185cb93a386Sopenharmony_ci 186cb93a386Sopenharmony_ci *buffer++ = count; 187cb93a386Sopenharmony_ci memcpy(buffer, colors, count * sizeof(SkPMColor4f)); 188cb93a386Sopenharmony_ci buffer += colorsAsIntCount; 189cb93a386Sopenharmony_ci if (count > 2) { 190cb93a386Sopenharmony_ci for (int i = 1; i < count; i++) { 191cb93a386Sopenharmony_ci *buffer++ = SkFloat2Bits(positions[i]); 192cb93a386Sopenharmony_ci } 193cb93a386Sopenharmony_ci } 194cb93a386Sopenharmony_ci *buffer++ = static_cast<int32_t>(alphaType); 195cb93a386Sopenharmony_ci *buffer++ = static_cast<int32_t>(colorType); 196cb93a386Sopenharmony_ci SkASSERT(buffer - storage.get() == keyCount); 197cb93a386Sopenharmony_ci 198cb93a386Sopenharmony_ci /////////////////////////////////// 199cb93a386Sopenharmony_ci 200cb93a386Sopenharmony_ci // acquire lock for checking/adding to cache 201cb93a386Sopenharmony_ci SkAutoMutexExclusive ama(fMutex); 202cb93a386Sopenharmony_ci size_t size = keyCount * sizeof(int32_t); 203cb93a386Sopenharmony_ci if (!this->find(storage.get(), size, bitmap)) { 204cb93a386Sopenharmony_ci SkImageInfo info = SkImageInfo::Make(fResolution, 1, colorType, alphaType); 205cb93a386Sopenharmony_ci bitmap->allocPixels(info); 206cb93a386Sopenharmony_ci GrGradientBitmapCache::fillGradient(colors, positions, count, colorType, bitmap); 207cb93a386Sopenharmony_ci bitmap->setImmutable(); 208cb93a386Sopenharmony_ci this->add(storage.get(), size, *bitmap); 209cb93a386Sopenharmony_ci } 210cb93a386Sopenharmony_ci} 211cb93a386Sopenharmony_ci 212cb93a386Sopenharmony_ci/////////////////////////////////////////////////////////////////////////////// 213cb93a386Sopenharmony_ci 214cb93a386Sopenharmony_ci#ifdef SK_DEBUG 215cb93a386Sopenharmony_ci 216cb93a386Sopenharmony_civoid GrGradientBitmapCache::validate() const { 217cb93a386Sopenharmony_ci SkASSERT(fEntryCount >= 0 && fEntryCount <= fMaxEntries); 218cb93a386Sopenharmony_ci 219cb93a386Sopenharmony_ci if (fEntryCount > 0) { 220cb93a386Sopenharmony_ci SkASSERT(nullptr == fHead->fPrev); 221cb93a386Sopenharmony_ci SkASSERT(nullptr == fTail->fNext); 222cb93a386Sopenharmony_ci 223cb93a386Sopenharmony_ci if (fEntryCount == 1) { 224cb93a386Sopenharmony_ci SkASSERT(fHead == fTail); 225cb93a386Sopenharmony_ci } else { 226cb93a386Sopenharmony_ci SkASSERT(fHead != fTail); 227cb93a386Sopenharmony_ci } 228cb93a386Sopenharmony_ci 229cb93a386Sopenharmony_ci Entry* entry = fHead; 230cb93a386Sopenharmony_ci int count = 0; 231cb93a386Sopenharmony_ci while (entry) { 232cb93a386Sopenharmony_ci count += 1; 233cb93a386Sopenharmony_ci entry = entry->fNext; 234cb93a386Sopenharmony_ci } 235cb93a386Sopenharmony_ci SkASSERT(count == fEntryCount); 236cb93a386Sopenharmony_ci 237cb93a386Sopenharmony_ci entry = fTail; 238cb93a386Sopenharmony_ci while (entry) { 239cb93a386Sopenharmony_ci count -= 1; 240cb93a386Sopenharmony_ci entry = entry->fPrev; 241cb93a386Sopenharmony_ci } 242cb93a386Sopenharmony_ci SkASSERT(0 == count); 243cb93a386Sopenharmony_ci } else { 244cb93a386Sopenharmony_ci SkASSERT(nullptr == fHead); 245cb93a386Sopenharmony_ci SkASSERT(nullptr == fTail); 246cb93a386Sopenharmony_ci } 247cb93a386Sopenharmony_ci} 248cb93a386Sopenharmony_ci 249cb93a386Sopenharmony_ci#endif 250