Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
GrGradientBitmapCache.cpp
Go to the documentation of this file.
1/*
2 * Copyright 2018 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
10
14#include "src/base/SkHalf.h"
18
19#include <functional>
20
21using namespace skia_private;
22
26
27 void* fBuffer;
28 size_t fSize;
30
31 Entry(const void* buffer, size_t size, const SkBitmap& bm)
32 : fPrev(nullptr),
33 fNext(nullptr),
34 fBitmap(bm) {
36 fSize = size;
37 memcpy(fBuffer, buffer, size);
38 }
39
41
42 bool equals(const void* buffer, size_t size) const {
43 return (fSize == size) && !memcmp(fBuffer, buffer, size);
44 }
45};
46
48 : fMaxEntries(max)
49 , fResolution(res) {
50 fEntryCount = 0;
51 fHead = fTail = nullptr;
52
53 this->validate();
54}
55
57 this->validate();
58
59 Entry* entry = fHead;
60 while (entry) {
61 Entry* next = entry->fNext;
62 delete entry;
63 entry = next;
64 }
65}
66
67GrGradientBitmapCache::Entry* GrGradientBitmapCache::release(Entry* entry) const {
68 if (entry->fPrev) {
69 SkASSERT(fHead != entry);
70 entry->fPrev->fNext = entry->fNext;
71 } else {
72 SkASSERT(fHead == entry);
73 fHead = entry->fNext;
74 }
75 if (entry->fNext) {
76 SkASSERT(fTail != entry);
77 entry->fNext->fPrev = entry->fPrev;
78 } else {
79 SkASSERT(fTail == entry);
80 fTail = entry->fPrev;
81 }
82 return entry;
83}
84
85void GrGradientBitmapCache::attachToHead(Entry* entry) const {
86 entry->fPrev = nullptr;
87 entry->fNext = fHead;
88 if (fHead) {
89 fHead->fPrev = entry;
90 } else {
91 fTail = entry;
92 }
93 fHead = entry;
94}
95
96bool GrGradientBitmapCache::find(const void* buffer, size_t size, SkBitmap* bm) const {
97 AutoValidate av(this);
98
99 Entry* entry = fHead;
100 while (entry) {
101 if (entry->equals(buffer, size)) {
102 if (bm) {
103 *bm = entry->fBitmap;
104 }
105 // move to the head of our list, so we purge it last
106 this->release(entry);
107 this->attachToHead(entry);
108 return true;
109 }
110 entry = entry->fNext;
111 }
112 return false;
113}
114
115void GrGradientBitmapCache::add(const void* buffer, size_t len, const SkBitmap& bm) {
116 AutoValidate av(this);
117
118 if (fEntryCount == fMaxEntries) {
119 SkASSERT(fTail);
120 delete this->release(fTail);
121 fEntryCount -= 1;
122 }
123
124 Entry* entry = new Entry(buffer, len, bm);
125 this->attachToHead(entry);
126 fEntryCount += 1;
127}
128
129///////////////////////////////////////////////////////////////////////////////
130
131void GrGradientBitmapCache::fillGradient(const SkPMColor4f* colors,
132 const SkScalar* positions,
133 int count,
134 bool colorsAreOpaque,
135 const SkGradientShader::Interpolation& interpolation,
136 const SkColorSpace* intermediateColorSpace,
137 const SkColorSpace* dstColorSpace,
138 SkBitmap* bitmap) {
139 SkArenaAlloc alloc(/*firstHeapAllocation=*/0);
140 SkRasterPipeline p(&alloc);
141 SkRasterPipeline_MemoryCtx ctx = { bitmap->getPixels(), 0 };
142
143 p.append(SkRasterPipelineOp::seed_shader);
144 p.appendMatrix(&alloc, SkMatrix::Scale(1.0f / bitmap->width(), 1.0f));
145 SkGradientBaseShader::AppendGradientFillStages(&p, &alloc, colors, positions, count);
147 &p, &alloc, colorsAreOpaque, interpolation, intermediateColorSpace, dstColorSpace);
148 p.appendStore(bitmap->colorType(), &ctx);
149 p.run(0, 0, bitmap->width(), 1);
150}
151
153 const SkScalar* positions,
154 int count,
155 bool colorsAreOpaque,
156 const SkGradientShader::Interpolation& interpolation,
157 const SkColorSpace* intermediateColorSpace,
158 const SkColorSpace* dstColorSpace,
160 SkAlphaType alphaType,
161 SkBitmap* bitmap) {
162 // Build our key:
163 // [numColors + colors[] + positions[] + alphaType + colorType + interpolation + dstColorSpace]
164 // NOTE: colorsAreOpaque is redundant with the actual colors. intermediateColorSpace is fully
165 // determined by interpolation and dstColorSpace.
166 static_assert(sizeof(SkPMColor4f) % sizeof(int32_t) == 0, "");
167 const int colorsAsIntCount = count * sizeof(SkPMColor4f) / sizeof(int32_t);
168 SkASSERT(count > 2); // Otherwise, we should have used the single-interval colorizer
169 const int keyCount = 1 + // count
170 colorsAsIntCount + // colors
171 (count - 2) + // positions
172 1 + // alphaType
173 1 + // colorType
174 3 + // interpolation
175 (dstColorSpace ? 2 : 0); // dstColorSpace
176
177 AutoSTMalloc<64, int32_t> storage(keyCount);
178 int32_t* buffer = storage.get();
179
180 *buffer++ = count;
181 memcpy(buffer, colors, count * sizeof(SkPMColor4f));
182 buffer += colorsAsIntCount;
183 for (int i = 1; i < count - 1; i++) {
184 *buffer++ = SkFloat2Bits(positions[i]);
185 }
186 *buffer++ = static_cast<int32_t>(alphaType);
187 *buffer++ = static_cast<int32_t>(colorType);
188 *buffer++ = static_cast<int32_t>(interpolation.fInPremul);
189 *buffer++ = static_cast<int32_t>(interpolation.fColorSpace);
190 *buffer++ = static_cast<int32_t>(interpolation.fHueMethod);
191 if (dstColorSpace) {
192 *buffer++ = dstColorSpace->toXYZD50Hash();
193 *buffer++ = dstColorSpace->transferFnHash();
194 }
195 SkASSERT(buffer - storage.get() == keyCount);
196
197 ///////////////////////////////////
198
199 // acquire lock for checking/adding to cache
200 SkAutoMutexExclusive ama(fMutex);
201 size_t size = keyCount * sizeof(int32_t);
202 if (!this->find(storage.get(), size, bitmap)) {
203 SkImageInfo info = SkImageInfo::Make(fResolution, 1, colorType, alphaType);
204 bitmap->allocPixels(info);
205 this->fillGradient(colors,
206 positions,
207 count,
208 colorsAreOpaque,
209 interpolation,
210 intermediateColorSpace,
211 dstColorSpace,
212 bitmap);
213 bitmap->setImmutable();
214 this->add(storage.get(), size, *bitmap);
215 }
216}
217
218///////////////////////////////////////////////////////////////////////////////
219
220#ifdef SK_DEBUG
221
222void GrGradientBitmapCache::validate() const {
223 SkASSERT(fEntryCount >= 0 && fEntryCount <= fMaxEntries);
224
225 if (fEntryCount > 0) {
226 SkASSERT(nullptr == fHead->fPrev);
227 SkASSERT(nullptr == fTail->fNext);
228
229 if (fEntryCount == 1) {
230 SkASSERT(fHead == fTail);
231 } else {
232 SkASSERT(fHead != fTail);
233 }
234
235 Entry* entry = fHead;
236 int count = 0;
237 while (entry) {
238 count += 1;
239 entry = entry->fNext;
240 }
241 SkASSERT(count == fEntryCount);
242
243 entry = fTail;
244 while (entry) {
245 count -= 1;
246 entry = entry->fPrev;
247 }
248 SkASSERT(0 == count);
249 } else {
250 SkASSERT(nullptr == fHead);
251 SkASSERT(nullptr == fTail);
252 }
253}
254
255#endif
static void info(const char *fmt,...) SK_PRINTF_LIKE(1
Definition DM.cpp:213
int count
static float next(float f)
SkAlphaType
Definition SkAlphaType.h:26
#define SkASSERT(cond)
Definition SkAssert.h:116
SkRGBA4f< kPremul_SkAlphaType > SkPMColor4f
SkColorType
Definition SkColorType.h:19
static uint32_t SkFloat2Bits(float value)
Definition SkFloatBits.h:41
static SkColorType colorType(AImageDecoder *decoder, const AImageDecoderHeaderInfo *headerInfo)
SK_API void sk_free(void *)
static void * sk_malloc_throw(size_t size)
Definition SkMalloc.h:67
void getGradient(const SkPMColor4f *colors, const SkScalar *positions, int count, bool colorsAreOpaque, const SkGradientShader::Interpolation &interpolation, const SkColorSpace *intermediateColorSpace, const SkColorSpace *dstColorSpace, SkColorType colorType, SkAlphaType alphaType, SkBitmap *bitmap)
GrGradientBitmapCache(int maxEntries, int resolution)
uint32_t toXYZD50Hash() const
uint32_t transferFnHash() const
static void AppendGradientFillStages(SkRasterPipeline *p, SkArenaAlloc *alloc, const SkPMColor4f *colors, const SkScalar *positions, int count)
static void AppendInterpolatedToDstStages(SkRasterPipeline *p, SkArenaAlloc *alloc, bool colorsAreOpaque, const Interpolation &interpolation, const SkColorSpace *intermediateColorSpace, const SkColorSpace *dstColorSpace)
static SkMatrix Scale(SkScalar sx, SkScalar sy)
Definition SkMatrix.h:75
float SkScalar
Definition extension.cpp:12
static const uint8_t buffer[]
static float max(float r, float g, float b)
Definition hsl.cpp:49
bool equals(const void *buffer, size_t size) const
Entry(const void *buffer, size_t size, const SkBitmap &bm)
static SkImageInfo Make(int width, int height, SkColorType ct, SkAlphaType at)