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

Side by Side Diff: src/effects/SkBlurMaskFilter.cpp

Issue 18110012: Add canFilterMaskGPU & filterMaskGPU to SkMaskFilter (Closed) Base URL: http://skia.googlecode.com/svn/trunk/
Patch Set: added comments & fixed nits Created 7 years, 5 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 unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 1
2 /* 2 /*
3 * Copyright 2006 The Android Open Source Project 3 * Copyright 2006 The Android Open Source Project
4 * 4 *
5 * Use of this source code is governed by a BSD-style license that can be 5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file. 6 * found in the LICENSE file.
7 */ 7 */
8 8
9 #include "SkBlurMaskFilter.h" 9 #include "SkBlurMaskFilter.h"
10 #include "SkBlurMask.h" 10 #include "SkBlurMask.h"
11 #include "SkFlattenableBuffers.h" 11 #include "SkFlattenableBuffers.h"
12 #include "SkMaskFilter.h" 12 #include "SkMaskFilter.h"
13 #include "SkBounder.h"
14 #include "SkRasterClip.h"
15 #include "SkRTConf.h" 13 #include "SkRTConf.h"
16 #include "SkStringUtils.h" 14 #include "SkStringUtils.h"
15 #include "SkStrokeRec.h"
16
17 #if SK_SUPPORT_GPU
18 #include "GrContext.h"
19 #include "GrTexture.h"
20 #include "effects/GrSimpleTextureEffect.h"
21 #include "SkGrPixelRef.h"
22 #endif
17 23
18 class SkBlurMaskFilterImpl : public SkMaskFilter { 24 class SkBlurMaskFilterImpl : public SkMaskFilter {
19 public: 25 public:
20 SkBlurMaskFilterImpl(SkScalar radius, SkBlurMaskFilter::BlurStyle, 26 SkBlurMaskFilterImpl(SkScalar radius, SkBlurMaskFilter::BlurStyle,
21 uint32_t flags); 27 uint32_t flags);
22 28
23 // overrides from SkMaskFilter 29 // overrides from SkMaskFilter
24 virtual SkMask::Format getFormat() const SK_OVERRIDE; 30 virtual SkMask::Format getFormat() const SK_OVERRIDE;
25 virtual bool filterMask(SkMask* dst, const SkMask& src, const SkMatrix&, 31 virtual bool filterMask(SkMask* dst, const SkMask& src, const SkMatrix&,
26 SkIPoint* margin) const SK_OVERRIDE; 32 SkIPoint* margin) const SK_OVERRIDE;
27 33
28 virtual BlurType asABlur(BlurInfo*) const SK_OVERRIDE; 34 #if SK_SUPPORT_GPU
35 virtual bool canFilterMaskGPU(const SkRect& devBounds,
36 const SkIRect& clipBounds,
37 const SkMatrix& ctm,
38 SkRect* maskRect) const SK_OVERRIDE;
39 virtual bool filterMaskGPU(GrTexture* src,
40 const SkRect& maskRect,
41 GrTexture** result,
42 bool canOverwriteSrc) const;
43 #endif
44
29 virtual void computeFastBounds(const SkRect&, SkRect*) const SK_OVERRIDE; 45 virtual void computeFastBounds(const SkRect&, SkRect*) const SK_OVERRIDE;
30 46
31 SkDEVCODE(virtual void toString(SkString* str) const SK_OVERRIDE;) 47 SkDEVCODE(virtual void toString(SkString* str) const SK_OVERRIDE;)
32 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkBlurMaskFilterImpl) 48 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkBlurMaskFilterImpl)
33 49
34 protected: 50 protected:
35 virtual FilterReturn filterRectsToNine(const SkRect[], int count, const SkMa trix&, 51 virtual FilterReturn filterRectsToNine(const SkRect[], int count, const SkMa trix&,
36 const SkIRect& clipBounds, 52 const SkIRect& clipBounds,
37 NinePatch*) const SK_OVERRIDE; 53 NinePatch*) const SK_OVERRIDE;
38 54
39 bool filterRectMask(SkMask* dstM, const SkRect& r, const SkMatrix& matrix, 55 bool filterRectMask(SkMask* dstM, const SkRect& r, const SkMatrix& matrix,
40 SkIPoint* margin, SkMask::CreateMode createMode) const; 56 SkIPoint* margin, SkMask::CreateMode createMode) const;
41 57
42 private: 58 private:
59 // To avoid unseemly allocation requests (esp. for finite platforms like
60 // handset) we limit the radius so something manageable. (as opposed to
61 // a request like 10,000)
62 static const SkScalar kMAX_RADIUS;
63 // This constant approximates the scaling done in the software path's
64 // "high quality" mode, in SkBlurMask::Blur() (1 / sqrt(3)).
65 // IMHO, it actually should be 1: we blur "less" than we should do
66 // according to the CSS and canvas specs, simply because Safari does the sam e.
67 // Firefox used to do the same too, until 4.0 where they fixed it. So at so me
68 // point we should probably get rid of these scaling constants and rebaselin e
69 // all the blur tests.
70 static const SkScalar kBLUR_SIGMA_SCALE;
71
43 SkScalar fRadius; 72 SkScalar fRadius;
44 SkBlurMaskFilter::BlurStyle fBlurStyle; 73 SkBlurMaskFilter::BlurStyle fBlurStyle;
45 uint32_t fBlurFlags; 74 uint32_t fBlurFlags;
46 75
47 SkBlurMaskFilterImpl(SkFlattenableReadBuffer&); 76 SkBlurMaskFilterImpl(SkFlattenableReadBuffer&);
48 virtual void flatten(SkFlattenableWriteBuffer&) const SK_OVERRIDE; 77 virtual void flatten(SkFlattenableWriteBuffer&) const SK_OVERRIDE;
78 #if SK_SUPPORT_GPU
79 SkScalar computeXformedRadius(const SkMatrix& ctm) const {
80 bool ignoreTransform = SkToBool(fBlurFlags & SkBlurMaskFilter::kIgnoreTr ansform_BlurFlag);
81
82 SkScalar xformedRadius = ignoreTransform ? fRadius
83 : ctm.mapRadius(fRadius);
84 return SkMinScalar(xformedRadius, kMAX_RADIUS);
85 }
86 #endif
49 87
50 typedef SkMaskFilter INHERITED; 88 typedef SkMaskFilter INHERITED;
51 }; 89 };
52 90
91 const SkScalar SkBlurMaskFilterImpl::kMAX_RADIUS = SkIntToScalar(128);
92 const SkScalar SkBlurMaskFilterImpl::kBLUR_SIGMA_SCALE = 0.6f;
93
53 SkMaskFilter* SkBlurMaskFilter::Create(SkScalar radius, 94 SkMaskFilter* SkBlurMaskFilter::Create(SkScalar radius,
54 SkBlurMaskFilter::BlurStyle style, 95 SkBlurMaskFilter::BlurStyle style,
55 uint32_t flags) { 96 uint32_t flags) {
56 // use !(radius > 0) instead of radius <= 0 to reject NaN values 97 // use !(radius > 0) instead of radius <= 0 to reject NaN values
57 if (!(radius > 0) || (unsigned)style >= SkBlurMaskFilter::kBlurStyleCount 98 if (!(radius > 0) || (unsigned)style >= SkBlurMaskFilter::kBlurStyleCount
58 || flags > SkBlurMaskFilter::kAll_BlurFlag) { 99 || flags > SkBlurMaskFilter::kAll_BlurFlag) {
59 return NULL; 100 return NULL;
60 } 101 }
61 102
62 return SkNEW_ARGS(SkBlurMaskFilterImpl, (radius, style, flags)); 103 return SkNEW_ARGS(SkBlurMaskFilterImpl, (radius, style, flags));
(...skipping 27 matching lines...) Expand all
90 bool SkBlurMaskFilterImpl::filterMask(SkMask* dst, const SkMask& src, 131 bool SkBlurMaskFilterImpl::filterMask(SkMask* dst, const SkMask& src,
91 const SkMatrix& matrix, 132 const SkMatrix& matrix,
92 SkIPoint* margin) const{ 133 SkIPoint* margin) const{
93 SkScalar radius; 134 SkScalar radius;
94 if (fBlurFlags & SkBlurMaskFilter::kIgnoreTransform_BlurFlag) { 135 if (fBlurFlags & SkBlurMaskFilter::kIgnoreTransform_BlurFlag) {
95 radius = fRadius; 136 radius = fRadius;
96 } else { 137 } else {
97 radius = matrix.mapRadius(fRadius); 138 radius = matrix.mapRadius(fRadius);
98 } 139 }
99 140
100 // To avoid unseemly allocation requests (esp. for finite platforms like 141 radius = SkMinScalar(radius, kMAX_RADIUS);
101 // handset) we limit the radius so something manageable. (as opposed to
102 // a request like 10,000)
103 static const SkScalar MAX_RADIUS = SkIntToScalar(128);
104 radius = SkMinScalar(radius, MAX_RADIUS);
105 SkBlurMask::Quality blurQuality = 142 SkBlurMask::Quality blurQuality =
106 (fBlurFlags & SkBlurMaskFilter::kHighQuality_BlurFlag) ? 143 (fBlurFlags & SkBlurMaskFilter::kHighQuality_BlurFlag) ?
107 SkBlurMask::kHigh_Quality : SkBlurMask::kLow_Quality; 144 SkBlurMask::kHigh_Quality : SkBlurMask::kLow_Quality;
108 145
109 return SkBlurMask::Blur(dst, src, radius, (SkBlurMask::Style)fBlurStyle, 146 return SkBlurMask::Blur(dst, src, radius, (SkBlurMask::Style)fBlurStyle,
110 blurQuality, margin); 147 blurQuality, margin);
111 } 148 }
112 149
113 bool SkBlurMaskFilterImpl::filterRectMask(SkMask* dst, const SkRect& r, 150 bool SkBlurMaskFilterImpl::filterRectMask(SkMask* dst, const SkRect& r,
114 const SkMatrix& matrix, 151 const SkMatrix& matrix,
115 SkIPoint* margin, SkMask::CreateMode c reateMode) const{ 152 SkIPoint* margin, SkMask::CreateMode c reateMode) const{
116 SkScalar radius; 153 SkScalar radius;
117 if (fBlurFlags & SkBlurMaskFilter::kIgnoreTransform_BlurFlag) { 154 if (fBlurFlags & SkBlurMaskFilter::kIgnoreTransform_BlurFlag) {
118 radius = fRadius; 155 radius = fRadius;
119 } else { 156 } else {
120 radius = matrix.mapRadius(fRadius); 157 radius = matrix.mapRadius(fRadius);
121 } 158 }
122 159
123 // To avoid unseemly allocation requests (esp. for finite platforms like 160 radius = SkMinScalar(radius, kMAX_RADIUS);
124 // handset) we limit the radius so something manageable. (as opposed to
125 // a request like 10,000)
126 static const SkScalar MAX_RADIUS = SkIntToScalar(128);
127 radius = SkMinScalar(radius, MAX_RADIUS);
128 161
129 return SkBlurMask::BlurRect(dst, r, radius, (SkBlurMask::Style)fBlurStyle, 162 return SkBlurMask::BlurRect(dst, r, radius, (SkBlurMask::Style)fBlurStyle,
130 margin, createMode); 163 margin, createMode);
131 } 164 }
132 165
133 #include "SkCanvas.h" 166 #include "SkCanvas.h"
134 167
135 static bool drawRectsIntoMask(const SkRect rects[], int count, SkMask* mask) { 168 static bool drawRectsIntoMask(const SkRect rects[], int count, SkMask* mask) {
136 rects[0].roundOut(&mask->fBounds); 169 rects[0].roundOut(&mask->fBounds);
137 mask->fRowBytes = SkAlign4(mask->fBounds.width()); 170 mask->fRowBytes = SkAlign4(mask->fBounds.width());
(...skipping 175 matching lines...) Expand 10 before | Expand all | Expand 10 after
313 SkASSERT((unsigned)fBlurStyle < SkBlurMaskFilter::kBlurStyleCount); 346 SkASSERT((unsigned)fBlurStyle < SkBlurMaskFilter::kBlurStyleCount);
314 } 347 }
315 348
316 void SkBlurMaskFilterImpl::flatten(SkFlattenableWriteBuffer& buffer) const { 349 void SkBlurMaskFilterImpl::flatten(SkFlattenableWriteBuffer& buffer) const {
317 this->INHERITED::flatten(buffer); 350 this->INHERITED::flatten(buffer);
318 buffer.writeScalar(fRadius); 351 buffer.writeScalar(fRadius);
319 buffer.writeInt(fBlurStyle); 352 buffer.writeInt(fBlurStyle);
320 buffer.writeUInt(fBlurFlags); 353 buffer.writeUInt(fBlurFlags);
321 } 354 }
322 355
323 static const SkMaskFilter::BlurType gBlurStyle2BlurType[] = { 356 #if SK_SUPPORT_GPU
324 SkMaskFilter::kNormal_BlurType,
325 SkMaskFilter::kSolid_BlurType,
326 SkMaskFilter::kOuter_BlurType,
327 SkMaskFilter::kInner_BlurType,
328 };
329 357
330 SkMaskFilter::BlurType SkBlurMaskFilterImpl::asABlur(BlurInfo* info) const { 358 bool SkBlurMaskFilterImpl::canFilterMaskGPU(const SkRect& srcBounds,
331 if (info) { 359 const SkIRect& clipBounds,
332 info->fRadius = fRadius; 360 const SkMatrix& ctm,
333 info->fIgnoreTransform = SkToBool(fBlurFlags & SkBlurMaskFilter::kIgnore Transform_BlurFlag); 361 SkRect* maskRect) const {
334 info->fHighQuality = SkToBool(fBlurFlags & SkBlurMaskFilter::kHighQualit y_BlurFlag); 362 SkScalar xformedRadius = this->computeXformedRadius(ctm);
363 if (xformedRadius <= 0) {
364 return false;
335 } 365 }
336 return gBlurStyle2BlurType[fBlurStyle]; 366
367 static const SkScalar kMIN_GPU_BLUR_SIZE = SkIntToScalar(64);
368 static const SkScalar kMIN_GPU_BLUR_RADIUS = SkIntToScalar(32);
369
370 if (srcBounds.width() <= kMIN_GPU_BLUR_SIZE &&
371 srcBounds.height() <= kMIN_GPU_BLUR_SIZE &&
372 xformedRadius <= kMIN_GPU_BLUR_RADIUS) {
373 // We prefer to blur small rect with small radius via CPU.
374 return false;
375 }
376
377 if (NULL == maskRect) {
378 // don't need to compute maskRect
379 return true;
380 }
381
382 float sigma3 = 3 * SkScalarToFloat(xformedRadius) * kBLUR_SIGMA_SCALE;
383
384 SkRect clipRect = SkRect::MakeFromIRect(clipBounds);
385 SkRect srcRect(srcBounds);
386
387 // Outset srcRect and clipRect by 3 * sigma, to compute affected blur area.
388 srcRect.outset(SkFloatToScalar(sigma3), SkFloatToScalar(sigma3));
389 clipRect.outset(SkFloatToScalar(sigma3), SkFloatToScalar(sigma3));
390 srcRect.intersect(clipRect);
391 *maskRect = srcRect;
392 return true;
337 } 393 }
338 394
395 bool SkBlurMaskFilterImpl::filterMaskGPU(GrTexture* src,
396 const SkRect& maskRect,
397 GrTexture** result,
398 bool canOverwriteSrc) const {
399 SkRect clipRect = SkRect::MakeWH(maskRect.width(), maskRect.height());
400
401 GrContext* context = src->getContext();
402
403 GrContext::AutoWideOpenIdentityDraw awo(context, NULL);
404
405 SkScalar xformedRadius = this->computeXformedRadius(context->getMatrix());
406 SkASSERT(xformedRadius > 0);
407
408 float sigma = SkScalarToFloat(xformedRadius) * kBLUR_SIGMA_SCALE;
409
410 // If we're doing a normal blur, we can clobber the pathTexture in the
411 // gaussianBlur. Otherwise, we need to save it for later compositing.
412 bool isNormalBlur = (SkBlurMaskFilter::kNormal_BlurStyle == fBlurStyle);
413 *result = context->gaussianBlur(src, isNormalBlur && canOverwriteSrc,
414 clipRect, sigma, sigma);
415 if (NULL == result) {
416 return false;
417 }
418
419 if (!isNormalBlur) {
420 context->setIdentityMatrix();
421 GrPaint paint;
422 SkMatrix matrix;
423 matrix.setIDiv(src->width(), src->height());
424 // Blend pathTexture over blurTexture.
425 GrContext::AutoRenderTarget art(context, (*result)->asRenderTarget());
426 paint.colorStage(0)->setEffect(
427 GrSimpleTextureEffect::Create(src, matrix))->unref();
428 if (SkBlurMaskFilter::kInner_BlurStyle == fBlurStyle) {
429 // inner: dst = dst * src
430 paint.setBlendFunc(kDC_GrBlendCoeff, kZero_GrBlendCoeff);
431 } else if (SkBlurMaskFilter::kSolid_BlurStyle == fBlurStyle) {
432 // solid: dst = src + dst - src * dst
433 // = (1 - dst) * src + 1 * dst
434 paint.setBlendFunc(kIDC_GrBlendCoeff, kOne_GrBlendCoeff);
435 } else if (SkBlurMaskFilter::kOuter_BlurStyle == fBlurStyle) {
436 // outer: dst = dst * (1 - src)
437 // = 0 * src + (1 - src) * dst
438 paint.setBlendFunc(kZero_GrBlendCoeff, kISC_GrBlendCoeff);
439 }
440 context->drawRect(paint, clipRect);
441 }
442
443 return true;
444 }
445
446 #endif // SK_SUPPORT_GPU
447
448
339 #ifdef SK_DEVELOPER 449 #ifdef SK_DEVELOPER
340 void SkBlurMaskFilterImpl::toString(SkString* str) const { 450 void SkBlurMaskFilterImpl::toString(SkString* str) const {
341 str->append("SkBlurMaskFilterImpl: ("); 451 str->append("SkBlurMaskFilterImpl: (");
342 452
343 str->append("radius: "); 453 str->append("radius: ");
344 str->appendScalar(fRadius); 454 str->appendScalar(fRadius);
345 str->append(" "); 455 str->append(" ");
346 456
347 static const char* gStyleName[SkBlurMaskFilter::kBlurStyleCount] = { 457 static const char* gStyleName[SkBlurMaskFilter::kBlurStyleCount] = {
348 "normal", "solid", "outer", "inner" 458 "normal", "solid", "outer", "inner"
(...skipping 12 matching lines...) Expand all
361 } else { 471 } else {
362 str->append("None"); 472 str->append("None");
363 } 473 }
364 str->append("))"); 474 str->append("))");
365 } 475 }
366 #endif 476 #endif
367 477
368 SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkBlurMaskFilter) 478 SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkBlurMaskFilter)
369 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkBlurMaskFilterImpl) 479 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkBlurMaskFilterImpl)
370 SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END 480 SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698