blob: 0a5aca85edd2abf8a98c4f675114565f935afae0 [file] [log] [blame]
senorblanco@chromium.orgbf2768b2012-08-20 15:43:14 +00001/*
2 * Copyright 2012 The Android Open Source Project
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 "SkImageFilter.h"
senorblanco@chromium.org9f25de72012-10-10 20:36:13 +00009
10#include "SkBitmap.h"
mtklein19fcc742014-07-11 08:42:17 -070011#include "SkChecksum.h"
senorblanco@chromium.org11825292014-03-14 17:44:41 +000012#include "SkDevice.h"
senorblanco55b6d8b2014-07-30 11:26:46 -070013#include "SkLazyPtr.h"
senorblanco8c874ee2015-03-20 06:38:17 -070014#include "SkMatrixImageFilter.h"
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +000015#include "SkReadBuffer.h"
16#include "SkWriteBuffer.h"
senorblanco@chromium.orgbf2768b2012-08-20 15:43:14 +000017#include "SkRect.h"
commit-bot@chromium.orgf7efa502014-04-11 18:57:00 +000018#include "SkTDynamicHash.h"
senorblanco55b6d8b2014-07-30 11:26:46 -070019#include "SkTInternalLList.h"
commit-bot@chromium.orgc0b7e102013-10-23 17:06:21 +000020#include "SkValidationUtils.h"
senorblanco@chromium.orgd043cce2013-04-08 19:43:22 +000021#if SK_SUPPORT_GPU
22#include "GrContext.h"
senorblanco@chromium.org6aa6fec2014-03-03 22:13:56 +000023#include "SkGrPixelRef.h"
24#include "SkGr.h"
senorblanco@chromium.orgd043cce2013-04-08 19:43:22 +000025#endif
senorblanco@chromium.orgbf2768b2012-08-20 15:43:14 +000026
stephana195f62d2015-04-09 07:57:54 -070027#ifdef SK_BUILD_FOR_IOS
28 enum { kDefaultCacheSize = 2 * 1024 * 1024 };
29#else
30 enum { kDefaultCacheSize = 128 * 1024 * 1024 };
31#endif
senorblanco55b6d8b2014-07-30 11:26:46 -070032
33static int32_t next_image_filter_unique_id() {
34 static int32_t gImageFilterUniqueID;
35
36 // Never return 0.
37 int32_t id;
38 do {
39 id = sk_atomic_inc(&gImageFilterUniqueID) + 1;
40 } while (0 == id);
41 return id;
42}
43
senorblancobe129b22014-08-08 07:14:35 -070044struct SkImageFilter::Cache::Key {
senorblanco55b6d8b2014-07-30 11:26:46 -070045 Key(const uint32_t uniqueID, const SkMatrix& matrix, const SkIRect& clipBounds, uint32_t srcGenID)
46 : fUniqueID(uniqueID), fMatrix(matrix), fClipBounds(clipBounds), fSrcGenID(srcGenID) {
47 // Assert that Key is tightly-packed, since it is hashed.
48 SK_COMPILE_ASSERT(sizeof(Key) == sizeof(uint32_t) + sizeof(SkMatrix) + sizeof(SkIRect) +
49 sizeof(uint32_t), image_filter_key_tight_packing);
50 fMatrix.getType(); // force initialization of type, so hashes match
51 }
52 uint32_t fUniqueID;
53 SkMatrix fMatrix;
54 SkIRect fClipBounds;
55 uint32_t fSrcGenID;
56 bool operator==(const Key& other) const {
57 return fUniqueID == other.fUniqueID
58 && fMatrix == other.fMatrix
59 && fClipBounds == other.fClipBounds
60 && fSrcGenID == other.fSrcGenID;
61 }
62};
63
reedb959ec72014-07-17 07:03:09 -070064SkImageFilter::Common::~Common() {
65 for (int i = 0; i < fInputs.count(); ++i) {
66 SkSafeUnref(fInputs[i]);
67 }
68}
69
70void SkImageFilter::Common::allocInputs(int count) {
71 const size_t size = count * sizeof(SkImageFilter*);
72 fInputs.reset(count);
73 sk_bzero(fInputs.get(), size);
74}
75
76void SkImageFilter::Common::detachInputs(SkImageFilter** inputs) {
77 const size_t size = fInputs.count() * sizeof(SkImageFilter*);
78 memcpy(inputs, fInputs.get(), size);
79 sk_bzero(fInputs.get(), size);
80}
81
82bool SkImageFilter::Common::unflatten(SkReadBuffer& buffer, int expectedCount) {
reed9fa60da2014-08-21 07:59:51 -070083 const int count = buffer.readInt();
84 if (!buffer.validate(count >= 0)) {
85 return false;
reedb959ec72014-07-17 07:03:09 -070086 }
reed9fa60da2014-08-21 07:59:51 -070087 if (!buffer.validate(expectedCount < 0 || count == expectedCount)) {
reedb959ec72014-07-17 07:03:09 -070088 return false;
89 }
90
91 this->allocInputs(count);
92 for (int i = 0; i < count; i++) {
93 if (buffer.readBool()) {
94 fInputs[i] = buffer.readImageFilter();
95 }
96 if (!buffer.isValid()) {
97 return false;
98 }
99 }
100 SkRect rect;
101 buffer.readRect(&rect);
102 if (!buffer.isValid() || !buffer.validate(SkIsValidRect(rect))) {
103 return false;
104 }
mtklein148ec592014-10-13 13:17:56 -0700105
reedb959ec72014-07-17 07:03:09 -0700106 uint32_t flags = buffer.readUInt();
107 fCropRect = CropRect(rect, flags);
senorblanco4a22a432015-03-18 13:14:54 -0700108 if (buffer.isVersionLT(SkReadBuffer::kImageFilterNoUniqueID_Version)) {
109
110 (void) buffer.readUInt();
111 }
reedb959ec72014-07-17 07:03:09 -0700112 return buffer.isValid();
113}
114
115///////////////////////////////////////////////////////////////////////////////////////////////////
116
senorblanco24e06d52015-03-18 12:11:33 -0700117SkImageFilter::SkImageFilter(int inputCount, SkImageFilter** inputs, const CropRect* cropRect)
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000118 : fInputCount(inputCount),
119 fInputs(new SkImageFilter*[inputCount]),
senorblanco55b6d8b2014-07-30 11:26:46 -0700120 fUsesSrcInput(false),
121 fCropRect(cropRect ? *cropRect : CropRect(SkRect(), 0x0)),
senorblanco24e06d52015-03-18 12:11:33 -0700122 fUniqueID(next_image_filter_unique_id()) {
senorblanco@chromium.org8d21f6c2012-10-12 19:14:06 +0000123 for (int i = 0; i < inputCount; ++i) {
senorblanco55b6d8b2014-07-30 11:26:46 -0700124 if (NULL == inputs[i] || inputs[i]->usesSrcInput()) {
125 fUsesSrcInput = true;
126 }
senorblanco@chromium.org9f25de72012-10-10 20:36:13 +0000127 fInputs[i] = inputs[i];
128 SkSafeRef(fInputs[i]);
129 }
130}
131
senorblanco@chromium.org9f25de72012-10-10 20:36:13 +0000132SkImageFilter::~SkImageFilter() {
senorblanco@chromium.org8d21f6c2012-10-12 19:14:06 +0000133 for (int i = 0; i < fInputCount; i++) {
senorblanco@chromium.org9f25de72012-10-10 20:36:13 +0000134 SkSafeUnref(fInputs[i]);
135 }
136 delete[] fInputs;
137}
138
senorblanco55b6d8b2014-07-30 11:26:46 -0700139SkImageFilter::SkImageFilter(int inputCount, SkReadBuffer& buffer)
senorblanco24e06d52015-03-18 12:11:33 -0700140 : fUsesSrcInput(false)
141 , fUniqueID(next_image_filter_unique_id()) {
reedb959ec72014-07-17 07:03:09 -0700142 Common common;
143 if (common.unflatten(buffer, inputCount)) {
144 fCropRect = common.cropRect();
145 fInputCount = common.inputCount();
146 fInputs = SkNEW_ARRAY(SkImageFilter*, fInputCount);
147 common.detachInputs(fInputs);
senorblanco55b6d8b2014-07-30 11:26:46 -0700148 for (int i = 0; i < fInputCount; ++i) {
149 if (NULL == fInputs[i] || fInputs[i]->usesSrcInput()) {
150 fUsesSrcInput = true;
151 }
152 }
commit-bot@chromium.orgce33d602013-11-25 21:46:31 +0000153 } else {
154 fInputCount = 0;
155 fInputs = NULL;
senorblanco@chromium.org9f25de72012-10-10 20:36:13 +0000156 }
157}
158
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000159void SkImageFilter::flatten(SkWriteBuffer& buffer) const {
senorblanco@chromium.org8d21f6c2012-10-12 19:14:06 +0000160 buffer.writeInt(fInputCount);
161 for (int i = 0; i < fInputCount; i++) {
senorblanco@chromium.org9f25de72012-10-10 20:36:13 +0000162 SkImageFilter* input = getInput(i);
163 buffer.writeBool(input != NULL);
164 if (input != NULL) {
165 buffer.writeFlattenable(input);
166 }
167 }
senorblanco@chromium.org3f1f2a32013-10-16 18:07:48 +0000168 buffer.writeRect(fCropRect.rect());
169 buffer.writeUInt(fCropRect.flags());
senorblanco@chromium.org9f25de72012-10-10 20:36:13 +0000170}
171
senorblanco@chromium.orgbf2768b2012-08-20 15:43:14 +0000172bool SkImageFilter::filterImage(Proxy* proxy, const SkBitmap& src,
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +0000173 const Context& context,
commit-bot@chromium.orgae761f72014-02-05 22:32:02 +0000174 SkBitmap* result, SkIPoint* offset) const {
senorblanco@chromium.orgbf2768b2012-08-20 15:43:14 +0000175 SkASSERT(result);
senorblanco@chromium.org6776b822014-01-03 21:48:22 +0000176 SkASSERT(offset);
senorblanco55b6d8b2014-07-30 11:26:46 -0700177 uint32_t srcGenID = fUsesSrcInput ? src.getGenerationID() : 0;
senorblancobe129b22014-08-08 07:14:35 -0700178 Cache::Key key(fUniqueID, context.ctm(), context.clipBounds(), srcGenID);
179 if (context.cache()) {
senorblanco55b6d8b2014-07-30 11:26:46 -0700180 if (context.cache()->get(key, result, offset)) {
181 return true;
182 }
commit-bot@chromium.orgf7efa502014-04-11 18:57:00 +0000183 }
senorblanco@chromium.orgbf2768b2012-08-20 15:43:14 +0000184 /*
185 * Give the proxy first shot at the filter. If it returns false, ask
186 * the filter to do it.
187 */
commit-bot@chromium.orgf7efa502014-04-11 18:57:00 +0000188 if ((proxy && proxy->filterImage(this, src, context, result, offset)) ||
189 this->onFilterImage(proxy, src, context, result, offset)) {
senorblancobe129b22014-08-08 07:14:35 -0700190 if (context.cache()) {
senorblanco55b6d8b2014-07-30 11:26:46 -0700191 context.cache()->set(key, *result, *offset);
192 }
commit-bot@chromium.orgf7efa502014-04-11 18:57:00 +0000193 return true;
194 }
195 return false;
senorblanco@chromium.orgbf2768b2012-08-20 15:43:14 +0000196}
197
198bool SkImageFilter::filterBounds(const SkIRect& src, const SkMatrix& ctm,
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +0000199 SkIRect* dst) const {
senorblanco@chromium.orgbf2768b2012-08-20 15:43:14 +0000200 SkASSERT(dst);
201 return this->onFilterBounds(src, ctm, dst);
202}
203
senorblanco@chromium.org336d1d72014-01-27 21:03:17 +0000204void SkImageFilter::computeFastBounds(const SkRect& src, SkRect* dst) const {
205 if (0 == fInputCount) {
206 *dst = src;
207 return;
208 }
209 if (this->getInput(0)) {
210 this->getInput(0)->computeFastBounds(src, dst);
211 } else {
212 *dst = src;
213 }
214 for (int i = 1; i < fInputCount; i++) {
215 SkImageFilter* input = this->getInput(i);
216 if (input) {
217 SkRect bounds;
218 input->computeFastBounds(src, &bounds);
219 dst->join(bounds);
220 } else {
221 dst->join(src);
222 }
223 }
224}
225
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +0000226bool SkImageFilter::onFilterImage(Proxy*, const SkBitmap&, const Context&,
commit-bot@chromium.orgae761f72014-02-05 22:32:02 +0000227 SkBitmap*, SkIPoint*) const {
senorblanco@chromium.orgbf2768b2012-08-20 15:43:14 +0000228 return false;
229}
230
231bool SkImageFilter::canFilterImageGPU() const {
joshualittb0a8a372014-09-23 09:50:21 -0700232 return this->asFragmentProcessor(NULL, NULL, SkMatrix::I(), SkIRect());
senorblanco@chromium.orgbf2768b2012-08-20 15:43:14 +0000233}
234
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +0000235bool SkImageFilter::filterImageGPU(Proxy* proxy, const SkBitmap& src, const Context& ctx,
commit-bot@chromium.orgae761f72014-02-05 22:32:02 +0000236 SkBitmap* result, SkIPoint* offset) const {
senorblanco@chromium.orgd043cce2013-04-08 19:43:22 +0000237#if SK_SUPPORT_GPU
senorblanco@chromium.org6aa6fec2014-03-03 22:13:56 +0000238 SkBitmap input = src;
senorblanco@chromium.orgd043cce2013-04-08 19:43:22 +0000239 SkASSERT(fInputCount == 1);
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +0000240 SkIPoint srcOffset = SkIPoint::Make(0, 0);
senorblanco@chromium.org6aa6fec2014-03-03 22:13:56 +0000241 if (this->getInput(0) &&
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +0000242 !this->getInput(0)->getInputResultGPU(proxy, src, ctx, &input, &srcOffset)) {
senorblanco@chromium.orgd043cce2013-04-08 19:43:22 +0000243 return false;
244 }
commit-bot@chromium.orgb8d00db2013-06-26 19:18:23 +0000245 GrTexture* srcTexture = input.getTexture();
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000246 SkIRect bounds;
senorblanco@chromium.org11825292014-03-14 17:44:41 +0000247 if (!this->applyCropRect(ctx, proxy, input, &srcOffset, &bounds, &input)) {
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000248 return false;
249 }
250 SkRect srcRect = SkRect::Make(bounds);
251 SkRect dstRect = SkRect::MakeWH(srcRect.width(), srcRect.height());
senorblanco@chromium.orgd043cce2013-04-08 19:43:22 +0000252 GrContext* context = srcTexture->getContext();
253
bsalomonf2703d82014-10-28 14:33:06 -0700254 GrSurfaceDesc desc;
255 desc.fFlags = kRenderTarget_GrSurfaceFlag,
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000256 desc.fWidth = bounds.width();
257 desc.fHeight = bounds.height();
senorblanco@chromium.orgd043cce2013-04-08 19:43:22 +0000258 desc.fConfig = kRGBA_8888_GrPixelConfig;
259
bsalomond309e7a2015-04-30 14:18:54 -0700260 SkAutoTUnref<GrTexture> dst(context->textureProvider()->refScratchTexture(
261 desc, GrTextureProvider::kApprox_ScratchTexMatch));
bsalomone3059732014-10-14 11:47:22 -0700262 if (!dst) {
senorblanco673d9732014-08-15 10:48:43 -0700263 return false;
264 }
joshualitt25d9c152015-02-18 12:29:52 -0800265
joshualitt570d2f82015-02-25 13:19:48 -0800266 // setup new clip
267 GrClip clip(dstRect);
268
joshualittb0a8a372014-09-23 09:50:21 -0700269 GrFragmentProcessor* fp;
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +0000270 offset->fX = bounds.left();
271 offset->fY = bounds.top();
272 bounds.offset(-srcOffset);
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +0000273 SkMatrix matrix(ctx.ctm());
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000274 matrix.postTranslate(SkIntToScalar(-bounds.left()), SkIntToScalar(-bounds.top()));
bsalomonb501ecd2014-10-14 08:40:57 -0700275 if (this->asFragmentProcessor(&fp, srcTexture, matrix, bounds)) {
276 SkASSERT(fp);
277 GrPaint paint;
278 paint.addColorProcessor(fp)->unref();
joshualitt570d2f82015-02-25 13:19:48 -0800279 context->drawNonAARectToRect(dst->asRenderTarget(), clip, paint, SkMatrix::I(), dstRect,
280 srcRect);
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000281
bsalomone3059732014-10-14 11:47:22 -0700282 WrapTexture(dst, bounds.width(), bounds.height(), result);
bsalomonb501ecd2014-10-14 08:40:57 -0700283 return true;
284 }
senorblanco@chromium.orgd043cce2013-04-08 19:43:22 +0000285#endif
bsalomonb501ecd2014-10-14 08:40:57 -0700286 return false;
senorblanco@chromium.orgbf2768b2012-08-20 15:43:14 +0000287}
288
senorblanco@chromium.org11825292014-03-14 17:44:41 +0000289bool SkImageFilter::applyCropRect(const Context& ctx, const SkBitmap& src,
290 const SkIPoint& srcOffset, SkIRect* bounds) const {
291 SkIRect srcBounds;
292 src.getBounds(&srcBounds);
293 srcBounds.offset(srcOffset);
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000294 SkRect cropRect;
senorblanco@chromium.org11825292014-03-14 17:44:41 +0000295 ctx.ctm().mapRect(&cropRect, fCropRect.rect());
reedb07a94f2014-11-19 05:03:18 -0800296 const SkIRect cropRectI = cropRect.roundOut();
senorblanco@chromium.org3f1f2a32013-10-16 18:07:48 +0000297 uint32_t flags = fCropRect.flags();
senorblanco@chromium.org11825292014-03-14 17:44:41 +0000298 if (flags & CropRect::kHasLeft_CropEdge) srcBounds.fLeft = cropRectI.fLeft;
299 if (flags & CropRect::kHasTop_CropEdge) srcBounds.fTop = cropRectI.fTop;
300 if (flags & CropRect::kHasRight_CropEdge) srcBounds.fRight = cropRectI.fRight;
301 if (flags & CropRect::kHasBottom_CropEdge) srcBounds.fBottom = cropRectI.fBottom;
302 if (!srcBounds.intersect(ctx.clipBounds())) {
303 return false;
304 }
305 *bounds = srcBounds;
306 return true;
307}
308
309bool SkImageFilter::applyCropRect(const Context& ctx, Proxy* proxy, const SkBitmap& src,
310 SkIPoint* srcOffset, SkIRect* bounds, SkBitmap* dst) const {
311 SkIRect srcBounds;
312 src.getBounds(&srcBounds);
313 srcBounds.offset(*srcOffset);
314 SkRect cropRect;
315 ctx.ctm().mapRect(&cropRect, fCropRect.rect());
reedb07a94f2014-11-19 05:03:18 -0800316 const SkIRect cropRectI = cropRect.roundOut();
senorblanco@chromium.org11825292014-03-14 17:44:41 +0000317 uint32_t flags = fCropRect.flags();
318 *bounds = srcBounds;
319 if (flags & CropRect::kHasLeft_CropEdge) bounds->fLeft = cropRectI.fLeft;
320 if (flags & CropRect::kHasTop_CropEdge) bounds->fTop = cropRectI.fTop;
321 if (flags & CropRect::kHasRight_CropEdge) bounds->fRight = cropRectI.fRight;
322 if (flags & CropRect::kHasBottom_CropEdge) bounds->fBottom = cropRectI.fBottom;
323 if (!bounds->intersect(ctx.clipBounds())) {
324 return false;
325 }
326 if (srcBounds.contains(*bounds)) {
327 *dst = src;
328 return true;
329 } else {
330 SkAutoTUnref<SkBaseDevice> device(proxy->createDevice(bounds->width(), bounds->height()));
331 if (!device) {
332 return false;
333 }
334 SkCanvas canvas(device);
335 canvas.clear(0x00000000);
336 canvas.drawBitmap(src, srcOffset->x() - bounds->x(), srcOffset->y() - bounds->y());
337 *srcOffset = SkIPoint::Make(bounds->x(), bounds->y());
338 *dst = device->accessBitmap(false);
339 return true;
340 }
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000341}
342
senorblanco@chromium.orgbf2768b2012-08-20 15:43:14 +0000343bool SkImageFilter::onFilterBounds(const SkIRect& src, const SkMatrix& ctm,
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +0000344 SkIRect* dst) const {
345 if (fInputCount < 1) {
senorblanco8f3937d2014-10-29 12:36:32 -0700346 *dst = src;
347 return true;
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +0000348 }
349
350 SkIRect bounds;
351 for (int i = 0; i < fInputCount; ++i) {
352 SkImageFilter* filter = this->getInput(i);
353 SkIRect rect = src;
354 if (filter && !filter->filterBounds(src, ctm, &rect)) {
355 return false;
356 }
357 if (0 == i) {
358 bounds = rect;
359 } else {
360 bounds.join(rect);
361 }
362 }
363
364 // don't modify dst until now, so we don't accidentally change it in the
365 // loop, but then return false on the next filter.
366 *dst = bounds;
senorblanco@chromium.orgbf2768b2012-08-20 15:43:14 +0000367 return true;
368}
369
joshualittb0a8a372014-09-23 09:50:21 -0700370bool SkImageFilter::asFragmentProcessor(GrFragmentProcessor**, GrTexture*, const SkMatrix&,
371 const SkIRect&) const {
senorblanco@chromium.orgbf2768b2012-08-20 15:43:14 +0000372 return false;
373}
senorblanco@chromium.org8d21f6c2012-10-12 19:14:06 +0000374
senorblanco8c874ee2015-03-20 06:38:17 -0700375SkImageFilter* SkImageFilter::CreateMatrixFilter(const SkMatrix& matrix,
376 SkFilterQuality filterQuality,
377 SkImageFilter* input) {
378 return SkMatrixImageFilter::Create(matrix, filterQuality, input);
379}
380
senorblanco@chromium.org6aa6fec2014-03-03 22:13:56 +0000381#if SK_SUPPORT_GPU
382
383void SkImageFilter::WrapTexture(GrTexture* texture, int width, int height, SkBitmap* result) {
384 SkImageInfo info = SkImageInfo::MakeN32Premul(width, height);
commit-bot@chromium.orga3264e52014-05-30 13:26:10 +0000385 result->setInfo(info);
senorblanco@chromium.org6aa6fec2014-03-03 22:13:56 +0000386 result->setPixelRef(SkNEW_ARGS(SkGrPixelRef, (info, texture)))->unref();
387}
388
389bool SkImageFilter::getInputResultGPU(SkImageFilter::Proxy* proxy,
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +0000390 const SkBitmap& src, const Context& ctx,
senorblanco@chromium.org6aa6fec2014-03-03 22:13:56 +0000391 SkBitmap* result, SkIPoint* offset) const {
392 // Ensure that GrContext calls under filterImage and filterImageGPU below will see an identity
393 // matrix with no clip and that the matrix, clip, and render target set before this function was
394 // called are restored before we return to the caller.
395 GrContext* context = src.getTexture()->getContext();
joshualitt570d2f82015-02-25 13:19:48 -0800396
senorblanco@chromium.org6aa6fec2014-03-03 22:13:56 +0000397 if (this->canFilterImageGPU()) {
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +0000398 return this->filterImageGPU(proxy, src, ctx, result, offset);
senorblanco@chromium.org6aa6fec2014-03-03 22:13:56 +0000399 } else {
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +0000400 if (this->filterImage(proxy, src, ctx, result, offset)) {
senorblanco@chromium.org6aa6fec2014-03-03 22:13:56 +0000401 if (!result->getTexture()) {
commit-bot@chromium.org466f5f32014-05-27 21:30:37 +0000402 const SkImageInfo info = result->info();
403 if (kUnknown_SkColorType == info.colorType()) {
senorblanco@chromium.org6aa6fec2014-03-03 22:13:56 +0000404 return false;
405 }
bsalomonbcf0a522014-10-08 08:40:09 -0700406 SkAutoTUnref<GrTexture> resultTex(GrRefCachedBitmapTexture(context, *result, NULL));
407 result->setPixelRef(SkNEW_ARGS(SkGrPixelRef, (info, resultTex)))->unref();
senorblanco@chromium.org6aa6fec2014-03-03 22:13:56 +0000408 }
409 return true;
410 } else {
411 return false;
412 }
413 }
414}
415#endif
commit-bot@chromium.orgf7efa502014-04-11 18:57:00 +0000416
senorblanco55b6d8b2014-07-30 11:26:46 -0700417namespace {
418
senorblancobe129b22014-08-08 07:14:35 -0700419class CacheImpl : public SkImageFilter::Cache {
senorblanco55b6d8b2014-07-30 11:26:46 -0700420public:
senorblancobe129b22014-08-08 07:14:35 -0700421 CacheImpl(size_t maxBytes) : fMaxBytes(maxBytes), fCurrentBytes(0) {
senorblanco55b6d8b2014-07-30 11:26:46 -0700422 }
senorblancobe129b22014-08-08 07:14:35 -0700423 virtual ~CacheImpl() {
senorblanco55b6d8b2014-07-30 11:26:46 -0700424 SkTDynamicHash<Value, Key>::Iter iter(&fLookup);
425
426 while (!iter.done()) {
427 Value* v = &*iter;
428 ++iter;
429 delete v;
430 }
431 }
432 struct Value {
433 Value(const Key& key, const SkBitmap& bitmap, const SkIPoint& offset)
434 : fKey(key), fBitmap(bitmap), fOffset(offset) {}
435 Key fKey;
436 SkBitmap fBitmap;
437 SkIPoint fOffset;
438 static const Key& GetKey(const Value& v) {
439 return v.fKey;
440 }
441 static uint32_t Hash(const Key& key) {
442 return SkChecksum::Murmur3(reinterpret_cast<const uint32_t*>(&key), sizeof(Key));
443 }
444 SK_DECLARE_INTERNAL_LLIST_INTERFACE(Value);
445 };
mtklein36352bf2015-03-25 18:17:31 -0700446 bool get(const Key& key, SkBitmap* result, SkIPoint* offset) const override {
senorblanco55b6d8b2014-07-30 11:26:46 -0700447 SkAutoMutexAcquire mutex(fMutex);
448 if (Value* v = fLookup.find(key)) {
449 *result = v->fBitmap;
450 *offset = v->fOffset;
451 if (v != fLRU.head()) {
452 fLRU.remove(v);
453 fLRU.addToHead(v);
454 }
455 return true;
456 }
457 return false;
458 }
mtklein36352bf2015-03-25 18:17:31 -0700459 void set(const Key& key, const SkBitmap& result, const SkIPoint& offset) override {
senorblanco55b6d8b2014-07-30 11:26:46 -0700460 SkAutoMutexAcquire mutex(fMutex);
461 if (Value* v = fLookup.find(key)) {
462 removeInternal(v);
463 }
464 Value* v = new Value(key, result, offset);
465 fLookup.add(v);
466 fLRU.addToHead(v);
467 fCurrentBytes += result.getSize();
468 while (fCurrentBytes > fMaxBytes) {
469 Value* tail = fLRU.tail();
470 SkASSERT(tail);
471 if (tail == v) {
472 break;
473 }
474 removeInternal(tail);
475 }
476 }
477private:
478 void removeInternal(Value* v) {
479 fCurrentBytes -= v->fBitmap.getSize();
480 fLRU.remove(v);
481 fLookup.remove(v->fKey);
482 delete v;
483 }
484private:
485 SkTDynamicHash<Value, Key> fLookup;
486 mutable SkTInternalLList<Value> fLRU;
487 size_t fMaxBytes;
488 size_t fCurrentBytes;
489 mutable SkMutex fMutex;
490};
491
senorblancobe129b22014-08-08 07:14:35 -0700492SkImageFilter::Cache* CreateCache() {
493 return SkImageFilter::Cache::Create(kDefaultCacheSize);
senorblanco55b6d8b2014-07-30 11:26:46 -0700494}
495
496} // namespace
497
senorblancobe129b22014-08-08 07:14:35 -0700498SkImageFilter::Cache* SkImageFilter::Cache::Create(size_t maxBytes) {
499 return SkNEW_ARGS(CacheImpl, (maxBytes));
senorblanco55b6d8b2014-07-30 11:26:46 -0700500}
501
mtklein148ec592014-10-13 13:17:56 -0700502SK_DECLARE_STATIC_LAZY_PTR(SkImageFilter::Cache, cache, CreateCache);
503
senorblancobe129b22014-08-08 07:14:35 -0700504SkImageFilter::Cache* SkImageFilter::Cache::Get() {
senorblanco55b6d8b2014-07-30 11:26:46 -0700505 return cache.get();
506}