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

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: rebase with latest skia in git instead of svn trunk Created 6 years, 6 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
« src/effects/SkBlurMask.cpp ('K') | « src/effects/SkBlurMask.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 e808885dddbe8a3143db1a7973dce6b11dd6aa28..1340ee750c578aa7228ee33f681fd5325e05f86d 100644
--- a/src/effects/SkBlurMaskFilter.cpp
+++ b/src/effects/SkBlurMaskFilter.cpp
@@ -6,6 +6,8 @@
* found in the LICENSE file.
*/
+#include <list>
Stephen White 2014/06/09 18:03:58 I'm not sure what the Skia project's official stan
+
#include "SkBlurMaskFilter.h"
#include "SkBlurMask.h"
#include "SkGpuBlurUtils.h"
@@ -14,6 +16,7 @@
#include "SkMaskFilter.h"
#include "SkRRect.h"
#include "SkRTConf.h"
+#include "SkScaledImageCache.h"
#include "SkStringUtils.h"
#include "SkStrokeRec.h"
@@ -65,6 +68,45 @@ 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, SkDiscardableMemoryMask* mask)
+ : fSigma(sigma),
+ fRectCount(rectCount),
+ fRects(rects),
+ fMask(mask) {}
+
+ ~BlurMaskRecord() {
+ if (fMask) {
+ delete fMask;
+ }
+ if (fRects) {
+ for(unsigned i = 0; i < fRectCount; i++) {
+ if (fRects[i])
+ delete fRects[i];
+ }
+ delete []fRects;
+ }
+ }
+
+ SkScalar fSigma;
+ unsigned fRectCount;
+ SkRect** fRects;
+ SkDiscardableMemoryMask* fMask;
+ };
+
+ static bool getBlurMaskRecord(SkScalar sigma,
+ unsigned rectCount,
+ const SkRect rects[],
+ SkDiscardableMemoryMask** mask);
+ static bool addBlurMaskRecord(BlurMaskRecord* blurMaskRecord);
+ static void clearBlurMaskRecordList();
+
SK_TO_STRING_OVERRIDE()
SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkBlurMaskFilterImpl)
@@ -107,11 +149,84 @@ private:
return SkMinScalar(xformedSigma, kMAX_BLUR_SIGMA);
}
+ typedef std::list<BlurMaskRecord*> BlurMaskRecordList;
+ static BlurMaskRecordList fCachedBlurMaskRecordList;
+
typedef SkMaskFilter INHERITED;
};
const SkScalar SkBlurMaskFilterImpl::kMAX_BLUR_SIGMA = SkIntToScalar(128);
+SkBlurMaskFilterImpl::BlurMaskRecordList SkBlurMaskFilterImpl::fCachedBlurMaskRecordList;
+SK_DECLARE_STATIC_MUTEX(gMutex);
+
+bool SkBlurMaskFilterImpl::getBlurMaskRecord(SkScalar sigma,
+ unsigned rectCount,
+ const SkRect rects[],
+ SkDiscardableMemoryMask** mask) {
+ SkAutoMutexAcquire am(gMutex);
+ 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 (unsigned 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;
Stephen White 2014/06/09 18:03:58 Perhaps this inner loop could be in its own functi
+ 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;
Stephen White 2014/06/09 18:03:58 Same here.
+ }
+ if (found) {
+ SkBitmap bitmap;
+ void* scaledCacheId = SkScaledImageCache::FindAndLock(cachedBlurMaskRecord->fMask->fPixelGenerationID,
+ cachedBlurMaskRecord->fMask->fMask.fBounds.width(),
+ cachedBlurMaskRecord->fMask->fMask.fBounds.height(),
+ &bitmap);
+ if (scaledCacheId) {
+ SkAutoLockPixels autoLockPixels(bitmap);
+ if (bitmap.getPixels()) {
+ cachedBlurMaskRecord->fMask->fCacheId = scaledCacheId;
+ *mask = cachedBlurMaskRecord->fMask;
+ return true;
+ }
+ }
+ fCachedBlurMaskRecordList.erase(--it.base());
+ return false;
+ }
+ }
+ }
+ }
+ return false;
+}
+
+bool SkBlurMaskFilterImpl::addBlurMaskRecord(BlurMaskRecord* blurMaskRecord) {
+ SkAutoMutexAcquire am(gMutex);
+ fCachedBlurMaskRecordList.push_back(blurMaskRecord);
+ return true;
+}
+
+void SkBlurMaskFilterImpl::clearBlurMaskRecordList() {
+ SkAutoMutexAcquire am(gMutex);
+ while (!fCachedBlurMaskRecordList.empty()) {
+ BlurMaskRecord* cachedBlurMaskRecord = fCachedBlurMaskRecordList.front();
+ fCachedBlurMaskRecordList.pop_front();
+ if (cachedBlurMaskRecord) {
+ delete cachedBlurMaskRecord;
+ cachedBlurMaskRecord = NULL;
+ }
+ }
+}
+
SkMaskFilter* SkBlurMaskFilter::Create(SkBlurStyle style, SkScalar sigma, uint32_t flags) {
if (!SkScalarIsFinite(sigma) || sigma <= 0) {
return NULL;
@@ -365,10 +480,24 @@ SkBlurMaskFilterImpl::filterRRectToNine(const SkRRect& rrect, const SkMatrix& ma
radii[SkRRect::kLowerLeft_Corner] = LL;
smallRR.setRectRadii(smallR, radii);
+ SkScalar sigma = this->computeXformedSigma(matrix);
+ SkDiscardableMemoryMask* cachedBlurMask = NULL;
+ SkRect rects[1];
+ rects[0] = rrect.rect();
+ if (getBlurMaskRecord(sigma, 1, rects, &cachedBlurMask)) {
+ patch->fDiscardableMemoryMask = *cachedBlurMask;
+ patch->fOuterRect = dstM.fBounds;
+ patch->fCenter.fX = SkScalarCeilToInt(leftUnstretched) + 1;
+ patch->fCenter.fY = SkScalarCeilToInt(topUnstretched) + 1;
+ return kTrue_FilterReturn;
+ }
+
+ SkBlurMask::addDiscardableMemoryMaskToMap(&(patch->fDiscardableMemoryMask.fMask),
+ &(patch->fDiscardableMemoryMask));
bool analyticBlurWorked = false;
if (c_analyticBlurRRect) {
analyticBlurWorked =
- this->filterRRectMask(&patch->fMask, smallRR, matrix, &margin,
+ this->filterRRectMask(&(patch->fDiscardableMemoryMask.fMask), smallRR, matrix, &margin,
SkMask::kComputeBoundsAndRenderImage_CreateMode);
}
@@ -379,15 +508,27 @@ SkBlurMaskFilterImpl::filterRRectToNine(const SkRRect& rrect, const SkMatrix& ma
SkAutoMaskFreeImage amf(srcM.fImage);
- if (!this->filterMask(&patch->fMask, srcM, matrix, &margin)) {
+ if (!this->filterMask(&(patch->fDiscardableMemoryMask.fMask), srcM, matrix, &margin)) {
return kFalse_FilterReturn;
}
}
- patch->fMask.fBounds.offsetTo(0, 0);
+ SkBlurMask::removeDiscardableMemoryMaskFromMap(&(patch->fDiscardableMemoryMask.fMask));
+ patch->fDiscardableMemoryMask.fMask.fBounds.offsetTo(0, 0);
patch->fOuterRect = dstM.fBounds;
patch->fCenter.fX = SkScalarCeilToInt(leftUnstretched) + 1;
patch->fCenter.fY = SkScalarCeilToInt(topUnstretched) + 1;
+ if (!cachedBlurMask) {
+ SkDiscardableMemoryMask* tempMask = new SkDiscardableMemoryMask;
+ *tempMask = patch->fDiscardableMemoryMask;
+ 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;
}
@@ -467,6 +608,15 @@ SkBlurMaskFilterImpl::filterRectsToNine(const SkRect rects[], int count,
smallH + (innerIR.top() - srcM.fBounds.top()));
}
+ SkScalar sigma = this->computeXformedSigma(matrix);
+ SkDiscardableMemoryMask* cachedBlurMask = NULL;
+ if (getBlurMaskRecord(sigma, count, rects, &cachedBlurMask)) {
+ patch->fDiscardableMemoryMask = *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;
@@ -491,25 +641,40 @@ SkBlurMaskFilterImpl::filterRectsToNine(const SkRect rects[], int count,
SkASSERT(!smallR[1].isEmpty());
}
+ SkBlurMask::addDiscardableMemoryMaskToMap(&(patch->fDiscardableMemoryMask.fMask),
+ &(patch->fDiscardableMemoryMask));
if (count > 1 || !c_analyticBlurNinepatch) {
if (!draw_rects_into_mask(smallR, count, &srcM)) {
return kFalse_FilterReturn;
}
-
SkAutoMaskFreeImage amf(srcM.fImage);
- if (!this->filterMask(&patch->fMask, srcM, matrix, &margin)) {
+ if (!this->filterMask(&patch->fDiscardableMemoryMask.fMask, srcM, matrix, &margin)) {
return kFalse_FilterReturn;
}
} else {
- if (!this->filterRectMask(&patch->fMask, smallR[0], matrix, &margin,
+ if (!this->filterRectMask(&patch->fDiscardableMemoryMask.fMask, smallR[0], matrix, &margin,
SkMask::kComputeBoundsAndRenderImage_CreateMode)) {
return kFalse_FilterReturn;
}
}
- patch->fMask.fBounds.offsetTo(0, 0);
+ patch->fDiscardableMemoryMask.fMask.fBounds.offsetTo(0, 0);
patch->fOuterRect = dstM.fBounds;
patch->fCenter = center;
+ SkBlurMask::removeDiscardableMemoryMaskFromMap(&(patch->fDiscardableMemoryMask.fMask));
+ if (!cachedBlurMask) {
+ SkDiscardableMemoryMask* tempMask = new SkDiscardableMemoryMask;
+ *tempMask = patch->fDiscardableMemoryMask;
+ 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;
}
« src/effects/SkBlurMask.cpp ('K') | « src/effects/SkBlurMask.cpp ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698