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

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

Issue 2255803003: Moving SkBlurImageFilter into core (Closed) Base URL: https://skia.googlesource.com/skia@master
Patch Set: ... made req changes onto correct branch Created 4 years, 3 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
« no previous file with comments | « src/core/SkGpuBlurUtils.cpp ('k') | src/effects/SkGpuBlurUtils.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 /*
2 * Copyright 2011 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 "SkBlurImageFilter.h"
9
10 #include "SkAutoPixmapStorage.h"
11 #include "SkColorPriv.h"
12 #include "SkGpuBlurUtils.h"
13 #include "SkOpts.h"
14 #include "SkReadBuffer.h"
15 #include "SkSpecialImage.h"
16 #include "SkWriteBuffer.h"
17
18 #if SK_SUPPORT_GPU
19 #include "GrContext.h"
20 #include "SkGr.h"
21 #endif
22
23 sk_sp<SkImageFilter> SkBlurImageFilter::Make(SkScalar sigmaX, SkScalar sigmaY,
24 sk_sp<SkImageFilter> input,
25 const CropRect* cropRect) {
26 if (0 == sigmaX && 0 == sigmaY && !cropRect) {
27 return input;
28 }
29 return sk_sp<SkImageFilter>(new SkBlurImageFilter(sigmaX, sigmaY, input, cro pRect));
30 }
31
32 // This rather arbitrary-looking value results in a maximum box blur kernel size
33 // of 1000 pixels on the raster path, which matches the WebKit and Firefox
34 // implementations. Since the GPU path does not compute a box blur, putting
35 // the limit on sigma ensures consistent behaviour between the GPU and
36 // raster paths.
37 #define MAX_SIGMA SkIntToScalar(532)
38
39 static SkVector map_sigma(const SkSize& localSigma, const SkMatrix& ctm) {
40 SkVector sigma = SkVector::Make(localSigma.width(), localSigma.height());
41 ctm.mapVectors(&sigma, 1);
42 sigma.fX = SkMinScalar(SkScalarAbs(sigma.fX), MAX_SIGMA);
43 sigma.fY = SkMinScalar(SkScalarAbs(sigma.fY), MAX_SIGMA);
44 return sigma;
45 }
46
47 SkBlurImageFilter::SkBlurImageFilter(SkScalar sigmaX,
48 SkScalar sigmaY,
49 sk_sp<SkImageFilter> input,
50 const CropRect* cropRect)
51 : INHERITED(&input, 1, cropRect)
52 , fSigma(SkSize::Make(sigmaX, sigmaY)) {
53 }
54
55 sk_sp<SkFlattenable> SkBlurImageFilter::CreateProc(SkReadBuffer& buffer) {
56 SK_IMAGEFILTER_UNFLATTEN_COMMON(common, 1);
57 SkScalar sigmaX = buffer.readScalar();
58 SkScalar sigmaY = buffer.readScalar();
59 return Make(sigmaX, sigmaY, common.getInput(0), &common.cropRect());
60 }
61
62 void SkBlurImageFilter::flatten(SkWriteBuffer& buffer) const {
63 this->INHERITED::flatten(buffer);
64 buffer.writeScalar(fSigma.fWidth);
65 buffer.writeScalar(fSigma.fHeight);
66 }
67
68 static void get_box3_params(SkScalar s, int *kernelSize, int* kernelSize3, int * lowOffset,
69 int *highOffset) {
70 float pi = SkScalarToFloat(SK_ScalarPI);
71 int d = static_cast<int>(floorf(SkScalarToFloat(s) * 3.0f * sqrtf(2.0f * pi) / 4.0f + 0.5f));
72 *kernelSize = d;
73 if (d % 2 == 1) {
74 *lowOffset = *highOffset = (d - 1) / 2;
75 *kernelSize3 = d;
76 } else {
77 *highOffset = d / 2;
78 *lowOffset = *highOffset - 1;
79 *kernelSize3 = d + 1;
80 }
81 }
82
83 sk_sp<SkSpecialImage> SkBlurImageFilter::onFilterImage(SkSpecialImage* source,
84 const Context& ctx,
85 SkIPoint* offset) const {
86 SkIPoint inputOffset = SkIPoint::Make(0, 0);
87
88 sk_sp<SkSpecialImage> input(this->filterInput(0, source, ctx, &inputOffset)) ;
89 if (!input) {
90 return nullptr;
91 }
92
93 SkIRect inputBounds = SkIRect::MakeXYWH(inputOffset.fX, inputOffset.fY,
94 input->width(), input->height());
95
96 SkIRect dstBounds;
97 if (!this->applyCropRect(this->mapContext(ctx), inputBounds, &dstBounds)) {
98 return nullptr;
99 }
100 if (!inputBounds.intersect(dstBounds)) {
101 return nullptr;
102 }
103
104 const SkVector sigma = map_sigma(fSigma, ctx.ctm());
105
106 #if SK_SUPPORT_GPU
107 if (source->isTextureBacked()) {
108 GrContext* context = source->getContext();
109 sk_sp<GrTexture> inputTexture(input->asTextureRef(context));
110 SkASSERT(inputTexture);
111
112 if (0 == sigma.x() && 0 == sigma.y()) {
113 offset->fX = inputBounds.x();
114 offset->fY = inputBounds.y();
115 return input->makeSubset(inputBounds.makeOffset(-inputOffset.x(),
116 -inputOffset.y()));
117 }
118
119 offset->fX = dstBounds.fLeft;
120 offset->fY = dstBounds.fTop;
121 inputBounds.offset(-inputOffset);
122 dstBounds.offset(-inputOffset);
123 sk_sp<GrDrawContext> drawContext(SkGpuBlurUtils::GaussianBlur(
124 context,
125 inputTexture.get (),
126 sk_ref_sp(source ->getColorSpace()),
127 dstBounds,
128 &inputBounds,
129 sigma.x(),
130 sigma.y()));
131 if (!drawContext) {
132 return nullptr;
133 }
134
135 // TODO: Get the colorSpace from the drawContext (once it has one)
136 return SkSpecialImage::MakeFromGpu(SkIRect::MakeWH(dstBounds.width(), ds tBounds.height()),
137 kNeedNewImageUniqueID_SpecialImage,
138 drawContext->asTexture(),
139 sk_ref_sp(input->getColorSpace()), &s ource->props());
140 }
141 #endif
142
143 int kernelSizeX, kernelSizeX3, lowOffsetX, highOffsetX;
144 int kernelSizeY, kernelSizeY3, lowOffsetY, highOffsetY;
145 get_box3_params(sigma.x(), &kernelSizeX, &kernelSizeX3, &lowOffsetX, &highOf fsetX);
146 get_box3_params(sigma.y(), &kernelSizeY, &kernelSizeY3, &lowOffsetY, &highOf fsetY);
147
148 if (kernelSizeX < 0 || kernelSizeY < 0) {
149 return nullptr;
150 }
151
152 if (kernelSizeX == 0 && kernelSizeY == 0) {
153 offset->fX = inputBounds.x();
154 offset->fY = inputBounds.y();
155 return input->makeSubset(inputBounds.makeOffset(-inputOffset.x(),
156 -inputOffset.y()));
157 }
158
159 SkBitmap inputBM;
160
161 if (!input->getROPixels(&inputBM)) {
162 return nullptr;
163 }
164
165 if (inputBM.colorType() != kN32_SkColorType) {
166 return nullptr;
167 }
168
169 SkImageInfo info = SkImageInfo::Make(dstBounds.width(), dstBounds.height(),
170 inputBM.colorType(), inputBM.alphaType( ));
171
172 SkBitmap tmp, dst;
173 if (!tmp.tryAllocPixels(info) || !dst.tryAllocPixels(info)) {
174 return nullptr;
175 }
176
177 SkAutoLockPixels inputLock(inputBM), tmpLock(tmp), dstLock(dst);
178
179 offset->fX = dstBounds.fLeft;
180 offset->fY = dstBounds.fTop;
181 SkPMColor* t = tmp.getAddr32(0, 0);
182 SkPMColor* d = dst.getAddr32(0, 0);
183 int w = dstBounds.width(), h = dstBounds.height();
184 const SkPMColor* s = inputBM.getAddr32(inputBounds.x() - inputOffset.x(),
185 inputBounds.y() - inputOffset.y());
186 inputBounds.offset(-dstBounds.x(), -dstBounds.y());
187 dstBounds.offset(-dstBounds.x(), -dstBounds.y());
188 SkIRect inputBoundsT = SkIRect::MakeLTRB(inputBounds.top(), inputBounds.left (),
189 inputBounds.bottom(), inputBounds.r ight());
190 SkIRect dstBoundsT = SkIRect::MakeWH(dstBounds.height(), dstBounds.width());
191 int sw = int(inputBM.rowBytes() >> 2);
192
193 /**
194 *
195 * In order to make memory accesses cache-friendly, we reorder the passes to
196 * use contiguous memory reads wherever possible.
197 *
198 * For example, the 6 passes of the X-and-Y blur case are rewritten as
199 * follows. Instead of 3 passes in X and 3 passes in Y, we perform
200 * 2 passes in X, 1 pass in X transposed to Y on write, 2 passes in X,
201 * then 1 pass in X transposed to Y on write.
202 *
203 * +----+ +----+ +----+ +---+ +---+ +---+ +----+
204 * + AB + ----> | AB | ----> | AB | -----> | A | ----> | A | ----> | A | --- --> | AB |
205 * +----+ blurX +----+ blurX +----+ blurXY | B | blurX | B | blurX | B | blu rXY +----+
206 * +---+ +---+ +---+
207 *
208 * In this way, two of the y-blurs become x-blurs applied to transposed
209 * images, and all memory reads are contiguous.
210 */
211 if (kernelSizeX > 0 && kernelSizeY > 0) {
212 SkOpts::box_blur_xx(s, sw, inputBounds, t, kernelSizeX, lowOffsetX, highOffsetX, w, h);
213 SkOpts::box_blur_xx(t, w, dstBounds, d, kernelSizeX, highOffsetX, lowOffsetX, w, h);
214 SkOpts::box_blur_xy(d, w, dstBounds, t, kernelSizeX3, highOffsetX, highOffsetX, w, h);
215 SkOpts::box_blur_xx(t, h, dstBoundsT, d, kernelSizeY, lowOffsetY, highOffsetY, h, w);
216 SkOpts::box_blur_xx(d, h, dstBoundsT, t, kernelSizeY, highOffsetY, lowOffsetY, h, w);
217 SkOpts::box_blur_xy(t, h, dstBoundsT, d, kernelSizeY3, highOffsetY, highOffsetY, h, w);
218 } else if (kernelSizeX > 0) {
219 SkOpts::box_blur_xx(s, sw, inputBounds, d, kernelSizeX, lowOffsetX, highOffsetX, w, h);
220 SkOpts::box_blur_xx(d, w, dstBounds, t, kernelSizeX, highOffsetX, lowOffsetX, w, h);
221 SkOpts::box_blur_xx(t, w, dstBounds, d, kernelSizeX3, highOffsetX, highOffsetX, w, h);
222 } else if (kernelSizeY > 0) {
223 SkOpts::box_blur_yx(s, sw, inputBoundsT, d, kernelSizeY, lowOffsetY, highOffsetY, h, w);
224 SkOpts::box_blur_xx(d, h, dstBoundsT, t, kernelSizeY, highOffsetY, lowOffsetY, h, w);
225 SkOpts::box_blur_xy(t, h, dstBoundsT, d, kernelSizeY3, highOffsetY, highOffsetY, h, w);
226 }
227
228 return SkSpecialImage::MakeFromRaster(SkIRect::MakeWH(dstBounds.width(),
229 dstBounds.height()),
230 dst, &source->props());
231 }
232
233
234 SkRect SkBlurImageFilter::computeFastBounds(const SkRect& src) const {
235 SkRect bounds = this->getInput(0) ? this->getInput(0)->computeFastBounds(src ) : src;
236 bounds.outset(SkScalarMul(fSigma.width(), SkIntToScalar(3)),
237 SkScalarMul(fSigma.height(), SkIntToScalar(3)));
238 return bounds;
239 }
240
241 SkIRect SkBlurImageFilter::onFilterNodeBounds(const SkIRect& src, const SkMatrix & ctm,
242 MapDirection) const {
243 SkVector sigma = map_sigma(fSigma, ctm);
244 return src.makeOutset(SkScalarCeilToInt(SkScalarMul(sigma.x(), SkIntToScalar (3))),
245 SkScalarCeilToInt(SkScalarMul(sigma.y(), SkIntToScalar (3))));
246 }
247
248 #ifndef SK_IGNORE_TO_STRING
249 void SkBlurImageFilter::toString(SkString* str) const {
250 str->appendf("SkBlurImageFilter: (");
251 str->appendf("sigma: (%f, %f) input (", fSigma.fWidth, fSigma.fHeight);
252
253 if (this->getInput(0)) {
254 this->getInput(0)->toString(str);
255 }
256
257 str->append("))");
258 }
259 #endif
OLDNEW
« no previous file with comments | « src/core/SkGpuBlurUtils.cpp ('k') | src/effects/SkGpuBlurUtils.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698