blob: 94b90d6a0561c3741730e6c94ba3bd4d2a44ac57 [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"
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +000014#include "SkReadBuffer.h"
15#include "SkWriteBuffer.h"
senorblanco@chromium.orgbf2768b2012-08-20 15:43:14 +000016#include "SkRect.h"
commit-bot@chromium.orgf7efa502014-04-11 18:57:00 +000017#include "SkTDynamicHash.h"
senorblanco55b6d8b2014-07-30 11:26:46 -070018#include "SkTInternalLList.h"
commit-bot@chromium.orgc0b7e102013-10-23 17:06:21 +000019#include "SkValidationUtils.h"
senorblanco@chromium.orgd043cce2013-04-08 19:43:22 +000020#if SK_SUPPORT_GPU
21#include "GrContext.h"
senorblanco@chromium.org6aa6fec2014-03-03 22:13:56 +000022#include "SkGrPixelRef.h"
23#include "SkGr.h"
senorblanco@chromium.orgd043cce2013-04-08 19:43:22 +000024#endif
senorblanco@chromium.orgbf2768b2012-08-20 15:43:14 +000025
senorblanco55b6d8b2014-07-30 11:26:46 -070026enum { kDefaultCacheSize = 128 * 1024 * 1024 };
27
28static int32_t next_image_filter_unique_id() {
29 static int32_t gImageFilterUniqueID;
30
31 // Never return 0.
32 int32_t id;
33 do {
34 id = sk_atomic_inc(&gImageFilterUniqueID) + 1;
35 } while (0 == id);
36 return id;
37}
38
senorblancobe129b22014-08-08 07:14:35 -070039struct SkImageFilter::Cache::Key {
senorblanco55b6d8b2014-07-30 11:26:46 -070040 Key(const uint32_t uniqueID, const SkMatrix& matrix, const SkIRect& clipBounds, uint32_t srcGenID)
41 : fUniqueID(uniqueID), fMatrix(matrix), fClipBounds(clipBounds), fSrcGenID(srcGenID) {
42 // Assert that Key is tightly-packed, since it is hashed.
43 SK_COMPILE_ASSERT(sizeof(Key) == sizeof(uint32_t) + sizeof(SkMatrix) + sizeof(SkIRect) +
44 sizeof(uint32_t), image_filter_key_tight_packing);
45 fMatrix.getType(); // force initialization of type, so hashes match
46 }
47 uint32_t fUniqueID;
48 SkMatrix fMatrix;
49 SkIRect fClipBounds;
50 uint32_t fSrcGenID;
51 bool operator==(const Key& other) const {
52 return fUniqueID == other.fUniqueID
53 && fMatrix == other.fMatrix
54 && fClipBounds == other.fClipBounds
55 && fSrcGenID == other.fSrcGenID;
56 }
57};
58
reedb959ec72014-07-17 07:03:09 -070059SkImageFilter::Common::~Common() {
60 for (int i = 0; i < fInputs.count(); ++i) {
61 SkSafeUnref(fInputs[i]);
62 }
63}
64
65void SkImageFilter::Common::allocInputs(int count) {
66 const size_t size = count * sizeof(SkImageFilter*);
67 fInputs.reset(count);
68 sk_bzero(fInputs.get(), size);
69}
70
71void SkImageFilter::Common::detachInputs(SkImageFilter** inputs) {
72 const size_t size = fInputs.count() * sizeof(SkImageFilter*);
73 memcpy(inputs, fInputs.get(), size);
74 sk_bzero(fInputs.get(), size);
75}
76
77bool SkImageFilter::Common::unflatten(SkReadBuffer& buffer, int expectedCount) {
reed9fa60da2014-08-21 07:59:51 -070078 const int count = buffer.readInt();
79 if (!buffer.validate(count >= 0)) {
80 return false;
reedb959ec72014-07-17 07:03:09 -070081 }
reed9fa60da2014-08-21 07:59:51 -070082 if (!buffer.validate(expectedCount < 0 || count == expectedCount)) {
reedb959ec72014-07-17 07:03:09 -070083 return false;
84 }
85
86 this->allocInputs(count);
87 for (int i = 0; i < count; i++) {
88 if (buffer.readBool()) {
89 fInputs[i] = buffer.readImageFilter();
90 }
91 if (!buffer.isValid()) {
92 return false;
93 }
94 }
95 SkRect rect;
96 buffer.readRect(&rect);
97 if (!buffer.isValid() || !buffer.validate(SkIsValidRect(rect))) {
98 return false;
99 }
mtklein148ec592014-10-13 13:17:56 -0700100
reedb959ec72014-07-17 07:03:09 -0700101 uint32_t flags = buffer.readUInt();
102 fCropRect = CropRect(rect, flags);
mtklein88fd0fb2014-12-01 06:56:38 -0800103 fUniqueID = buffer.readUInt();
reedb959ec72014-07-17 07:03:09 -0700104 return buffer.isValid();
105}
106
107///////////////////////////////////////////////////////////////////////////////////////////////////
108
senorblanco5e5f9482014-08-26 12:27:12 -0700109SkImageFilter::SkImageFilter(int inputCount, SkImageFilter** inputs, const CropRect* cropRect, uint32_t uniqueID)
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000110 : fInputCount(inputCount),
111 fInputs(new SkImageFilter*[inputCount]),
senorblanco55b6d8b2014-07-30 11:26:46 -0700112 fUsesSrcInput(false),
113 fCropRect(cropRect ? *cropRect : CropRect(SkRect(), 0x0)),
senorblanco5e5f9482014-08-26 12:27:12 -0700114 fUniqueID(uniqueID ? uniqueID : next_image_filter_unique_id()) {
senorblanco@chromium.org8d21f6c2012-10-12 19:14:06 +0000115 for (int i = 0; i < inputCount; ++i) {
senorblanco55b6d8b2014-07-30 11:26:46 -0700116 if (NULL == inputs[i] || inputs[i]->usesSrcInput()) {
117 fUsesSrcInput = true;
118 }
senorblanco@chromium.org9f25de72012-10-10 20:36:13 +0000119 fInputs[i] = inputs[i];
120 SkSafeRef(fInputs[i]);
121 }
122}
123
senorblanco@chromium.org9f25de72012-10-10 20:36:13 +0000124SkImageFilter::~SkImageFilter() {
senorblanco@chromium.org8d21f6c2012-10-12 19:14:06 +0000125 for (int i = 0; i < fInputCount; i++) {
senorblanco@chromium.org9f25de72012-10-10 20:36:13 +0000126 SkSafeUnref(fInputs[i]);
127 }
128 delete[] fInputs;
129}
130
senorblanco55b6d8b2014-07-30 11:26:46 -0700131SkImageFilter::SkImageFilter(int inputCount, SkReadBuffer& buffer)
132 : fUsesSrcInput(false) {
reedb959ec72014-07-17 07:03:09 -0700133 Common common;
134 if (common.unflatten(buffer, inputCount)) {
135 fCropRect = common.cropRect();
136 fInputCount = common.inputCount();
137 fInputs = SkNEW_ARRAY(SkImageFilter*, fInputCount);
138 common.detachInputs(fInputs);
senorblanco55b6d8b2014-07-30 11:26:46 -0700139 for (int i = 0; i < fInputCount; ++i) {
140 if (NULL == fInputs[i] || fInputs[i]->usesSrcInput()) {
141 fUsesSrcInput = true;
142 }
143 }
144 fUniqueID = buffer.isCrossProcess() ? next_image_filter_unique_id() : common.uniqueID();
commit-bot@chromium.orgce33d602013-11-25 21:46:31 +0000145 } else {
146 fInputCount = 0;
147 fInputs = NULL;
senorblanco@chromium.org9f25de72012-10-10 20:36:13 +0000148 }
149}
150
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000151void SkImageFilter::flatten(SkWriteBuffer& buffer) const {
senorblanco@chromium.org8d21f6c2012-10-12 19:14:06 +0000152 buffer.writeInt(fInputCount);
153 for (int i = 0; i < fInputCount; i++) {
senorblanco@chromium.org9f25de72012-10-10 20:36:13 +0000154 SkImageFilter* input = getInput(i);
155 buffer.writeBool(input != NULL);
156 if (input != NULL) {
157 buffer.writeFlattenable(input);
158 }
159 }
senorblanco@chromium.org3f1f2a32013-10-16 18:07:48 +0000160 buffer.writeRect(fCropRect.rect());
161 buffer.writeUInt(fCropRect.flags());
senorblanco55b6d8b2014-07-30 11:26:46 -0700162 buffer.writeUInt(fUniqueID);
senorblanco@chromium.org9f25de72012-10-10 20:36:13 +0000163}
164
senorblanco@chromium.orgbf2768b2012-08-20 15:43:14 +0000165bool SkImageFilter::filterImage(Proxy* proxy, const SkBitmap& src,
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +0000166 const Context& context,
commit-bot@chromium.orgae761f72014-02-05 22:32:02 +0000167 SkBitmap* result, SkIPoint* offset) const {
senorblanco@chromium.orgbf2768b2012-08-20 15:43:14 +0000168 SkASSERT(result);
senorblanco@chromium.org6776b822014-01-03 21:48:22 +0000169 SkASSERT(offset);
senorblanco55b6d8b2014-07-30 11:26:46 -0700170 uint32_t srcGenID = fUsesSrcInput ? src.getGenerationID() : 0;
senorblancobe129b22014-08-08 07:14:35 -0700171 Cache::Key key(fUniqueID, context.ctm(), context.clipBounds(), srcGenID);
172 if (context.cache()) {
senorblanco55b6d8b2014-07-30 11:26:46 -0700173 if (context.cache()->get(key, result, offset)) {
174 return true;
175 }
commit-bot@chromium.orgf7efa502014-04-11 18:57:00 +0000176 }
senorblanco@chromium.orgbf2768b2012-08-20 15:43:14 +0000177 /*
178 * Give the proxy first shot at the filter. If it returns false, ask
179 * the filter to do it.
180 */
commit-bot@chromium.orgf7efa502014-04-11 18:57:00 +0000181 if ((proxy && proxy->filterImage(this, src, context, result, offset)) ||
182 this->onFilterImage(proxy, src, context, result, offset)) {
senorblancobe129b22014-08-08 07:14:35 -0700183 if (context.cache()) {
senorblanco55b6d8b2014-07-30 11:26:46 -0700184 context.cache()->set(key, *result, *offset);
185 }
commit-bot@chromium.orgf7efa502014-04-11 18:57:00 +0000186 return true;
187 }
188 return false;
senorblanco@chromium.orgbf2768b2012-08-20 15:43:14 +0000189}
190
191bool SkImageFilter::filterBounds(const SkIRect& src, const SkMatrix& ctm,
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +0000192 SkIRect* dst) const {
senorblanco@chromium.orgbf2768b2012-08-20 15:43:14 +0000193 SkASSERT(&src);
194 SkASSERT(dst);
195 return this->onFilterBounds(src, ctm, dst);
196}
197
senorblanco@chromium.org336d1d72014-01-27 21:03:17 +0000198void SkImageFilter::computeFastBounds(const SkRect& src, SkRect* dst) const {
199 if (0 == fInputCount) {
200 *dst = src;
201 return;
202 }
203 if (this->getInput(0)) {
204 this->getInput(0)->computeFastBounds(src, dst);
205 } else {
206 *dst = src;
207 }
208 for (int i = 1; i < fInputCount; i++) {
209 SkImageFilter* input = this->getInput(i);
210 if (input) {
211 SkRect bounds;
212 input->computeFastBounds(src, &bounds);
213 dst->join(bounds);
214 } else {
215 dst->join(src);
216 }
217 }
218}
219
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +0000220bool SkImageFilter::onFilterImage(Proxy*, const SkBitmap&, const Context&,
commit-bot@chromium.orgae761f72014-02-05 22:32:02 +0000221 SkBitmap*, SkIPoint*) const {
senorblanco@chromium.orgbf2768b2012-08-20 15:43:14 +0000222 return false;
223}
224
225bool SkImageFilter::canFilterImageGPU() const {
joshualittb0a8a372014-09-23 09:50:21 -0700226 return this->asFragmentProcessor(NULL, NULL, SkMatrix::I(), SkIRect());
senorblanco@chromium.orgbf2768b2012-08-20 15:43:14 +0000227}
228
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +0000229bool SkImageFilter::filterImageGPU(Proxy* proxy, const SkBitmap& src, const Context& ctx,
commit-bot@chromium.orgae761f72014-02-05 22:32:02 +0000230 SkBitmap* result, SkIPoint* offset) const {
senorblanco@chromium.orgd043cce2013-04-08 19:43:22 +0000231#if SK_SUPPORT_GPU
senorblanco@chromium.org6aa6fec2014-03-03 22:13:56 +0000232 SkBitmap input = src;
senorblanco@chromium.orgd043cce2013-04-08 19:43:22 +0000233 SkASSERT(fInputCount == 1);
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +0000234 SkIPoint srcOffset = SkIPoint::Make(0, 0);
senorblanco@chromium.org6aa6fec2014-03-03 22:13:56 +0000235 if (this->getInput(0) &&
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +0000236 !this->getInput(0)->getInputResultGPU(proxy, src, ctx, &input, &srcOffset)) {
senorblanco@chromium.orgd043cce2013-04-08 19:43:22 +0000237 return false;
238 }
commit-bot@chromium.orgb8d00db2013-06-26 19:18:23 +0000239 GrTexture* srcTexture = input.getTexture();
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000240 SkIRect bounds;
senorblanco@chromium.org11825292014-03-14 17:44:41 +0000241 if (!this->applyCropRect(ctx, proxy, input, &srcOffset, &bounds, &input)) {
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000242 return false;
243 }
244 SkRect srcRect = SkRect::Make(bounds);
245 SkRect dstRect = SkRect::MakeWH(srcRect.width(), srcRect.height());
senorblanco@chromium.orgd043cce2013-04-08 19:43:22 +0000246 GrContext* context = srcTexture->getContext();
247
bsalomonf2703d82014-10-28 14:33:06 -0700248 GrSurfaceDesc desc;
249 desc.fFlags = kRenderTarget_GrSurfaceFlag,
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000250 desc.fWidth = bounds.width();
251 desc.fHeight = bounds.height();
senorblanco@chromium.orgd043cce2013-04-08 19:43:22 +0000252 desc.fConfig = kRGBA_8888_GrPixelConfig;
253
bsalomone3059732014-10-14 11:47:22 -0700254 SkAutoTUnref<GrTexture> dst(
255 context->refScratchTexture(desc, GrContext::kApprox_ScratchTexMatch));
256 if (!dst) {
senorblanco673d9732014-08-15 10:48:43 -0700257 return false;
258 }
joshualitt25d9c152015-02-18 12:29:52 -0800259
joshualitt570d2f82015-02-25 13:19:48 -0800260 // setup new clip
261 GrClip clip(dstRect);
262
joshualittb0a8a372014-09-23 09:50:21 -0700263 GrFragmentProcessor* fp;
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +0000264 offset->fX = bounds.left();
265 offset->fY = bounds.top();
266 bounds.offset(-srcOffset);
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +0000267 SkMatrix matrix(ctx.ctm());
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000268 matrix.postTranslate(SkIntToScalar(-bounds.left()), SkIntToScalar(-bounds.top()));
bsalomonb501ecd2014-10-14 08:40:57 -0700269 if (this->asFragmentProcessor(&fp, srcTexture, matrix, bounds)) {
270 SkASSERT(fp);
271 GrPaint paint;
272 paint.addColorProcessor(fp)->unref();
joshualitt570d2f82015-02-25 13:19:48 -0800273 context->drawNonAARectToRect(dst->asRenderTarget(), clip, paint, SkMatrix::I(), dstRect,
274 srcRect);
senorblanco@chromium.org4e16bb22013-07-26 00:10:07 +0000275
bsalomone3059732014-10-14 11:47:22 -0700276 WrapTexture(dst, bounds.width(), bounds.height(), result);
bsalomonb501ecd2014-10-14 08:40:57 -0700277 return true;
278 }
senorblanco@chromium.orgd043cce2013-04-08 19:43:22 +0000279#endif
bsalomonb501ecd2014-10-14 08:40:57 -0700280 return false;
senorblanco@chromium.orgbf2768b2012-08-20 15:43:14 +0000281}
282
senorblanco@chromium.org11825292014-03-14 17:44:41 +0000283bool SkImageFilter::applyCropRect(const Context& ctx, const SkBitmap& src,
284 const SkIPoint& srcOffset, SkIRect* bounds) const {
285 SkIRect srcBounds;
286 src.getBounds(&srcBounds);
287 srcBounds.offset(srcOffset);
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +0000288 SkRect cropRect;
senorblanco@chromium.org11825292014-03-14 17:44:41 +0000289 ctx.ctm().mapRect(&cropRect, fCropRect.rect());
reedb07a94f2014-11-19 05:03:18 -0800290 const SkIRect cropRectI = cropRect.roundOut();
senorblanco@chromium.org3f1f2a32013-10-16 18:07:48 +0000291 uint32_t flags = fCropRect.flags();
senorblanco@chromium.org11825292014-03-14 17:44:41 +0000292 if (flags & CropRect::kHasLeft_CropEdge) srcBounds.fLeft = cropRectI.fLeft;
293 if (flags & CropRect::kHasTop_CropEdge) srcBounds.fTop = cropRectI.fTop;
294 if (flags & CropRect::kHasRight_CropEdge) srcBounds.fRight = cropRectI.fRight;
295 if (flags & CropRect::kHasBottom_CropEdge) srcBounds.fBottom = cropRectI.fBottom;
296 if (!srcBounds.intersect(ctx.clipBounds())) {
297 return false;
298 }
299 *bounds = srcBounds;
300 return true;
301}
302
303bool SkImageFilter::applyCropRect(const Context& ctx, Proxy* proxy, const SkBitmap& src,
304 SkIPoint* srcOffset, SkIRect* bounds, SkBitmap* dst) const {
305 SkIRect srcBounds;
306 src.getBounds(&srcBounds);
307 srcBounds.offset(*srcOffset);
308 SkRect cropRect;
309 ctx.ctm().mapRect(&cropRect, fCropRect.rect());
reedb07a94f2014-11-19 05:03:18 -0800310 const SkIRect cropRectI = cropRect.roundOut();
senorblanco@chromium.org11825292014-03-14 17:44:41 +0000311 uint32_t flags = fCropRect.flags();
312 *bounds = srcBounds;
313 if (flags & CropRect::kHasLeft_CropEdge) bounds->fLeft = cropRectI.fLeft;
314 if (flags & CropRect::kHasTop_CropEdge) bounds->fTop = cropRectI.fTop;
315 if (flags & CropRect::kHasRight_CropEdge) bounds->fRight = cropRectI.fRight;
316 if (flags & CropRect::kHasBottom_CropEdge) bounds->fBottom = cropRectI.fBottom;
317 if (!bounds->intersect(ctx.clipBounds())) {
318 return false;
319 }
320 if (srcBounds.contains(*bounds)) {
321 *dst = src;
322 return true;
323 } else {
324 SkAutoTUnref<SkBaseDevice> device(proxy->createDevice(bounds->width(), bounds->height()));
325 if (!device) {
326 return false;
327 }
328 SkCanvas canvas(device);
329 canvas.clear(0x00000000);
330 canvas.drawBitmap(src, srcOffset->x() - bounds->x(), srcOffset->y() - bounds->y());
331 *srcOffset = SkIPoint::Make(bounds->x(), bounds->y());
332 *dst = device->accessBitmap(false);
333 return true;
334 }
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000335}
336
senorblanco@chromium.orgbf2768b2012-08-20 15:43:14 +0000337bool SkImageFilter::onFilterBounds(const SkIRect& src, const SkMatrix& ctm,
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +0000338 SkIRect* dst) const {
339 if (fInputCount < 1) {
senorblanco8f3937d2014-10-29 12:36:32 -0700340 *dst = src;
341 return true;
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +0000342 }
343
344 SkIRect bounds;
345 for (int i = 0; i < fInputCount; ++i) {
346 SkImageFilter* filter = this->getInput(i);
347 SkIRect rect = src;
348 if (filter && !filter->filterBounds(src, ctm, &rect)) {
349 return false;
350 }
351 if (0 == i) {
352 bounds = rect;
353 } else {
354 bounds.join(rect);
355 }
356 }
357
358 // don't modify dst until now, so we don't accidentally change it in the
359 // loop, but then return false on the next filter.
360 *dst = bounds;
senorblanco@chromium.orgbf2768b2012-08-20 15:43:14 +0000361 return true;
362}
363
joshualittb0a8a372014-09-23 09:50:21 -0700364bool SkImageFilter::asFragmentProcessor(GrFragmentProcessor**, GrTexture*, const SkMatrix&,
365 const SkIRect&) const {
senorblanco@chromium.orgbf2768b2012-08-20 15:43:14 +0000366 return false;
367}
senorblanco@chromium.org8d21f6c2012-10-12 19:14:06 +0000368
sugoi@google.coma1c511b2013-02-21 15:02:28 +0000369bool SkImageFilter::asColorFilter(SkColorFilter**) const {
370 return false;
senorblanco@chromium.org8d21f6c2012-10-12 19:14:06 +0000371}
senorblanco@chromium.org6aa6fec2014-03-03 22:13:56 +0000372
373#if SK_SUPPORT_GPU
374
375void SkImageFilter::WrapTexture(GrTexture* texture, int width, int height, SkBitmap* result) {
376 SkImageInfo info = SkImageInfo::MakeN32Premul(width, height);
commit-bot@chromium.orga3264e52014-05-30 13:26:10 +0000377 result->setInfo(info);
senorblanco@chromium.org6aa6fec2014-03-03 22:13:56 +0000378 result->setPixelRef(SkNEW_ARGS(SkGrPixelRef, (info, texture)))->unref();
379}
380
381bool SkImageFilter::getInputResultGPU(SkImageFilter::Proxy* proxy,
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +0000382 const SkBitmap& src, const Context& ctx,
senorblanco@chromium.org6aa6fec2014-03-03 22:13:56 +0000383 SkBitmap* result, SkIPoint* offset) const {
384 // Ensure that GrContext calls under filterImage and filterImageGPU below will see an identity
385 // matrix with no clip and that the matrix, clip, and render target set before this function was
386 // called are restored before we return to the caller.
387 GrContext* context = src.getTexture()->getContext();
joshualitt570d2f82015-02-25 13:19:48 -0800388
senorblanco@chromium.org6aa6fec2014-03-03 22:13:56 +0000389 if (this->canFilterImageGPU()) {
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +0000390 return this->filterImageGPU(proxy, src, ctx, result, offset);
senorblanco@chromium.org6aa6fec2014-03-03 22:13:56 +0000391 } else {
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +0000392 if (this->filterImage(proxy, src, ctx, result, offset)) {
senorblanco@chromium.org6aa6fec2014-03-03 22:13:56 +0000393 if (!result->getTexture()) {
commit-bot@chromium.org466f5f32014-05-27 21:30:37 +0000394 const SkImageInfo info = result->info();
395 if (kUnknown_SkColorType == info.colorType()) {
senorblanco@chromium.org6aa6fec2014-03-03 22:13:56 +0000396 return false;
397 }
bsalomonbcf0a522014-10-08 08:40:09 -0700398 SkAutoTUnref<GrTexture> resultTex(GrRefCachedBitmapTexture(context, *result, NULL));
399 result->setPixelRef(SkNEW_ARGS(SkGrPixelRef, (info, resultTex)))->unref();
senorblanco@chromium.org6aa6fec2014-03-03 22:13:56 +0000400 }
401 return true;
402 } else {
403 return false;
404 }
405 }
406}
407#endif
commit-bot@chromium.orgf7efa502014-04-11 18:57:00 +0000408
senorblanco55b6d8b2014-07-30 11:26:46 -0700409namespace {
410
senorblancobe129b22014-08-08 07:14:35 -0700411class CacheImpl : public SkImageFilter::Cache {
senorblanco55b6d8b2014-07-30 11:26:46 -0700412public:
senorblancobe129b22014-08-08 07:14:35 -0700413 CacheImpl(size_t maxBytes) : fMaxBytes(maxBytes), fCurrentBytes(0) {
senorblanco55b6d8b2014-07-30 11:26:46 -0700414 }
senorblancobe129b22014-08-08 07:14:35 -0700415 virtual ~CacheImpl() {
senorblanco55b6d8b2014-07-30 11:26:46 -0700416 SkTDynamicHash<Value, Key>::Iter iter(&fLookup);
417
418 while (!iter.done()) {
419 Value* v = &*iter;
420 ++iter;
421 delete v;
422 }
423 }
424 struct Value {
425 Value(const Key& key, const SkBitmap& bitmap, const SkIPoint& offset)
426 : fKey(key), fBitmap(bitmap), fOffset(offset) {}
427 Key fKey;
428 SkBitmap fBitmap;
429 SkIPoint fOffset;
430 static const Key& GetKey(const Value& v) {
431 return v.fKey;
432 }
433 static uint32_t Hash(const Key& key) {
434 return SkChecksum::Murmur3(reinterpret_cast<const uint32_t*>(&key), sizeof(Key));
435 }
436 SK_DECLARE_INTERNAL_LLIST_INTERFACE(Value);
437 };
mtklein72c9faa2015-01-09 10:06:39 -0800438 bool get(const Key& key, SkBitmap* result, SkIPoint* offset) const SK_OVERRIDE {
senorblanco55b6d8b2014-07-30 11:26:46 -0700439 SkAutoMutexAcquire mutex(fMutex);
440 if (Value* v = fLookup.find(key)) {
441 *result = v->fBitmap;
442 *offset = v->fOffset;
443 if (v != fLRU.head()) {
444 fLRU.remove(v);
445 fLRU.addToHead(v);
446 }
447 return true;
448 }
449 return false;
450 }
mtklein72c9faa2015-01-09 10:06:39 -0800451 void set(const Key& key, const SkBitmap& result, const SkIPoint& offset) SK_OVERRIDE {
senorblanco55b6d8b2014-07-30 11:26:46 -0700452 SkAutoMutexAcquire mutex(fMutex);
453 if (Value* v = fLookup.find(key)) {
454 removeInternal(v);
455 }
456 Value* v = new Value(key, result, offset);
457 fLookup.add(v);
458 fLRU.addToHead(v);
459 fCurrentBytes += result.getSize();
460 while (fCurrentBytes > fMaxBytes) {
461 Value* tail = fLRU.tail();
462 SkASSERT(tail);
463 if (tail == v) {
464 break;
465 }
466 removeInternal(tail);
467 }
468 }
469private:
470 void removeInternal(Value* v) {
471 fCurrentBytes -= v->fBitmap.getSize();
472 fLRU.remove(v);
473 fLookup.remove(v->fKey);
474 delete v;
475 }
476private:
477 SkTDynamicHash<Value, Key> fLookup;
478 mutable SkTInternalLList<Value> fLRU;
479 size_t fMaxBytes;
480 size_t fCurrentBytes;
481 mutable SkMutex fMutex;
482};
483
senorblancobe129b22014-08-08 07:14:35 -0700484SkImageFilter::Cache* CreateCache() {
485 return SkImageFilter::Cache::Create(kDefaultCacheSize);
senorblanco55b6d8b2014-07-30 11:26:46 -0700486}
487
488} // namespace
489
senorblancobe129b22014-08-08 07:14:35 -0700490SkImageFilter::Cache* SkImageFilter::Cache::Create(size_t maxBytes) {
491 return SkNEW_ARGS(CacheImpl, (maxBytes));
senorblanco55b6d8b2014-07-30 11:26:46 -0700492}
493
mtklein148ec592014-10-13 13:17:56 -0700494SK_DECLARE_STATIC_LAZY_PTR(SkImageFilter::Cache, cache, CreateCache);
495
senorblancobe129b22014-08-08 07:14:35 -0700496SkImageFilter::Cache* SkImageFilter::Cache::Get() {
senorblanco55b6d8b2014-07-30 11:26:46 -0700497 return cache.get();
498}