Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1441)

Unified Diff: src/effects/SkBlurMaskFilter.cpp

Issue 286273002: Optimize CSS box-shadow performance by caching the SkMask of the blur effect. (Closed) Base URL: https://skia.googlecode.com/svn/trunk
Patch Set: Created 6 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/core/SkMaskFilter.cpp ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/effects/SkBlurMaskFilter.cpp
diff --git a/src/effects/SkBlurMaskFilter.cpp b/src/effects/SkBlurMaskFilter.cpp
index 2169a42cb6df9e043b34209de947f3d101d908a3..bf9712d67cd968fd701a177b68dbc78d10185b35 100644
--- a/src/effects/SkBlurMaskFilter.cpp
+++ b/src/effects/SkBlurMaskFilter.cpp
@@ -6,6 +6,8 @@
* found in the LICENSE file.
*/
+#include <list>
+
#include "SkBlurMaskFilter.h"
#include "SkBlurMask.h"
#include "SkGpuBlurUtils.h"
@@ -65,6 +67,49 @@ public:
virtual void computeFastBounds(const SkRect&, SkRect*) const SK_OVERRIDE;
virtual bool asABlur(BlurRec*) const SK_OVERRIDE;
+ class BlurMaskRecord {
+ public:
+ BlurMaskRecord(): fSigma(0),
+ fRectCount(0),
+ fRects(NULL),
+ fMask(NULL) {}
+
+ BlurMaskRecord(SkScalar sigma, unsigned rectCount, SkRect** rects, SkMask* mask)
+ : fSigma(sigma),
+ fRectCount(rectCount),
+ fRects(rects),
+ fMask(mask) {}
+
+ ~BlurMaskRecord() {
+ if (fMask) {
+ if (fMask->fImage)
+ SkMask::FreeImage(fMask->fImage);
+ delete fMask;
+ }
+ if (fRects) {
+ for(int i = 0; i < fRectCount; i++) {
+ if (fRects[i])
+ delete fRects[i];
+ }
+ delete []fRects;
+ }
+ }
+
+ SkScalar fSigma;
+ unsigned fRectCount;
+ SkRect** fRects;
+ SkMask* fMask;
+ };
+
+ static bool getBlurMaskRecord(SkScalar sigma,
+ unsigned rectCount,
+ const SkRect rects[],
+ SkMask** mask);
+ static bool addBlurMaskRecord(BlurMaskRecord* blurMaskRecord);
+ static void clearBlurMaskRecordList();
+ static unsigned getBlurMaskRecordsMemoryUsage() { return fCachedBlurMaskImageMemorySize; }
+ static void setBlurMaskRecordsLimit(unsigned, unsigned);
+
SK_TO_STRING_OVERRIDE()
SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkBlurMaskFilterImpl)
@@ -107,11 +152,90 @@ private:
return SkMinScalar(xformedSigma, kMAX_BLUR_SIGMA);
}
+ typedef std::list<BlurMaskRecord*> BlurMaskRecordList;
+ static BlurMaskRecordList fCachedBlurMaskRecordList;
+ static unsigned fCachedBlurMaskImageMemorySize;
+ static unsigned fMaxBlurMaskListSize;
+ static unsigned fMaxImageMemorySize;
+
typedef SkMaskFilter INHERITED;
};
const SkScalar SkBlurMaskFilterImpl::kMAX_BLUR_SIGMA = SkIntToScalar(128);
+SkBlurMaskFilterImpl::BlurMaskRecordList SkBlurMaskFilterImpl::fCachedBlurMaskRecordList;
reveman 2014/05/16 18:49:16 I'm failing to see how the use of this is thread s
junj 2014/05/19 12:54:49 Yes, I should add a mutex to make it thread-safe.
+unsigned SkBlurMaskFilterImpl::fCachedBlurMaskImageMemorySize = 0;
+unsigned SkBlurMaskFilterImpl::fMaxBlurMaskListSize = 50;
+unsigned SkBlurMaskFilterImpl::fMaxImageMemorySize = 2 * 1024 * 1024;
reveman 2014/05/16 18:49:16 Please allow SkDiscardableMemory to be used instea
junj 2014/05/19 12:54:49 I have had a look at the interface of SkScaledImag
reveman 2014/05/19 14:09:37 Yes, I'm hoping to enable it this week and remove
+
+bool SkBlurMaskFilterImpl::getBlurMaskRecord(SkScalar sigma,
+ unsigned rectCount,
+ const SkRect rects[],
+ SkMask** mask) {
+ if (!fCachedBlurMaskRecordList.empty()) {
+ for (BlurMaskRecordList::reverse_iterator it = fCachedBlurMaskRecordList.rbegin();
+ it != fCachedBlurMaskRecordList.rend(); ++it) {
+ BlurMaskRecord* cachedBlurMaskRecord = *it;
+ if (cachedBlurMaskRecord->fSigma == sigma
+ && cachedBlurMaskRecord->fRectCount == rectCount) {
+ bool found = true;
+ SkRect* tempRects[2] = {NULL, NULL};
+ for (int i = 0; i < rectCount; i++) {
+ tempRects[i] = *(cachedBlurMaskRecord->fRects + i);
+ if (tempRects[i]->width() != rects[i].width() ||
+ tempRects[i]->height() != rects[i].height()) {
+ found = false;
+ break;
+ }
+ }
+ if (found && rectCount == 2) {
+ if ((tempRects[0]->x() - rects[0].x()) != (tempRects[1]->x() - rects[1].x()) ||
+ (tempRects[0]->y() - rects[0].y()) != (tempRects[1]->y() - rects[1].y()))
+ found = false;
+ }
+ if (found) {
+ *mask = cachedBlurMaskRecord->fMask;
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+}
+
+bool SkBlurMaskFilterImpl::addBlurMaskRecord(BlurMaskRecord* blurMaskRecord) {
+ while (fCachedBlurMaskRecordList.size() >= fMaxBlurMaskListSize
+ || fCachedBlurMaskImageMemorySize >= fMaxImageMemorySize) {
+ BlurMaskRecord* cachedBlurMaskRecord = fCachedBlurMaskRecordList.front();
+ fCachedBlurMaskRecordList.pop_front();
+ if (cachedBlurMaskRecord) {
+ fCachedBlurMaskImageMemorySize -= cachedBlurMaskRecord->fMask->computeImageSize();
+ delete cachedBlurMaskRecord;
+ cachedBlurMaskRecord = NULL;
+ }
+ }
+ fCachedBlurMaskRecordList.push_back(blurMaskRecord);
+ fCachedBlurMaskImageMemorySize += blurMaskRecord->fMask->computeImageSize();
+ return true;
+}
+
+void SkBlurMaskFilterImpl::clearBlurMaskRecordList() {
+ while (!fCachedBlurMaskRecordList.empty()) {
+ BlurMaskRecord* cachedBlurMaskRecord = fCachedBlurMaskRecordList.front();
+ fCachedBlurMaskRecordList.pop_front();
+ if (cachedBlurMaskRecord) {
+ delete cachedBlurMaskRecord;
+ cachedBlurMaskRecord = NULL;
+ }
+ }
+ fCachedBlurMaskImageMemorySize = 0;
+}
+
+void SkBlurMaskFilterImpl::setBlurMaskRecordsLimit(unsigned listSize, unsigned memSize) {
+ fMaxBlurMaskListSize = listSize;
+ fMaxImageMemorySize = memSize;
+}
+
SkMaskFilter* SkBlurMaskFilter::Create(SkBlurStyle style, SkScalar sigma, uint32_t flags) {
if (!SkScalarIsFinite(sigma) || sigma <= 0) {
return NULL;
@@ -380,6 +504,18 @@ SkBlurMaskFilterImpl::filterRRectToNine(const SkRRect& rrect, const SkMatrix& ma
radii[SkRRect::kLowerLeft_Corner] = LL;
smallRR.setRectRadii(smallR, radii);
+ SkScalar sigma = this->computeXformedSigma(matrix);
+ SkMask* cachedBlurMask = NULL;
+ SkRect rects[1];
+ rects[0] = rrect.rect();
+ if (getBlurMaskRecord(sigma, 1, rects, &cachedBlurMask)) {
+ patch->fMask = *cachedBlurMask;
+ patch->fOuterRect = dstM.fBounds;
+ patch->fCenter.fX = SkScalarCeilToInt(leftUnstretched) + 1;
+ patch->fCenter.fY = SkScalarCeilToInt(topUnstretched) + 1;
+ return kTrue_FilterReturn;
+ }
+
bool analyticBlurWorked = false;
if (c_analyticBlurRRect) {
analyticBlurWorked =
@@ -403,6 +539,17 @@ SkBlurMaskFilterImpl::filterRRectToNine(const SkRRect& rrect, const SkMatrix& ma
patch->fOuterRect = dstM.fBounds;
patch->fCenter.fX = SkScalarCeilToInt(leftUnstretched) + 1;
patch->fCenter.fY = SkScalarCeilToInt(topUnstretched) + 1;
+ if (!cachedBlurMask) {
+ SkMask* tempMask = new SkMask;
+ *tempMask = patch->fMask;
+ SkRect** tempRects = new SkRect* [1];
+ tempRects[0] = new SkRect;
+ *(tempRects[0]) = rrect.rect();
+ BlurMaskRecord * blurMaskRecord = new BlurMaskRecord(sigma, 1, tempRects, tempMask);
+ if (blurMaskRecord)
+ addBlurMaskRecord(blurMaskRecord);
+ }
+
return kTrue_FilterReturn;
}
@@ -482,6 +629,15 @@ SkBlurMaskFilterImpl::filterRectsToNine(const SkRect rects[], int count,
smallH + (innerIR.top() - srcM.fBounds.top()));
}
+ SkScalar sigma = this->computeXformedSigma(matrix);
+ SkMask* cachedBlurMask = NULL;
+ if (getBlurMaskRecord(sigma, count, rects, &cachedBlurMask)) {
+ patch->fMask = *cachedBlurMask;
+ patch->fOuterRect = dstM.fBounds;
+ patch->fCenter = center;
+ return kTrue_FilterReturn;
+ }
+
// +1 so we get a clean, stretchable, center row/col
smallW += 1;
smallH += 1;
@@ -510,7 +666,6 @@ SkBlurMaskFilterImpl::filterRectsToNine(const SkRect rects[], int count,
if (!draw_rects_into_mask(smallR, count, &srcM)) {
return kFalse_FilterReturn;
}
-
SkAutoMaskFreeImage amf(srcM.fImage);
if (!this->filterMask(&patch->fMask, srcM, matrix, &margin)) {
@@ -525,6 +680,20 @@ SkBlurMaskFilterImpl::filterRectsToNine(const SkRect rects[], int count,
patch->fMask.fBounds.offsetTo(0, 0);
patch->fOuterRect = dstM.fBounds;
patch->fCenter = center;
+
+ if (!cachedBlurMask) {
+ SkMask* tempMask = new SkMask;
+ *tempMask = patch->fMask;
+ SkRect** tempRects = new SkRect* [count];
+ for (int i = 0; i < count; i++) {
+ tempRects[i] = new SkRect;
+ *(tempRects[i]) = rects[i];
+ }
+ BlurMaskRecord * blurMaskRecord = new BlurMaskRecord(sigma, count, tempRects, tempMask);
+ if (blurMaskRecord)
+ addBlurMaskRecord(blurMaskRecord);
+ }
+
return kTrue_FilterReturn;
}
« no previous file with comments | « src/core/SkMaskFilter.cpp ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698