OLD | NEW |
1 /* | 1 /* |
2 * Copyright 2015 Google Inc. | 2 * Copyright 2015 Google Inc. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
6 */ | 6 */ |
7 | 7 |
8 #include "GrBlurUtils.h" | 8 #include "GrBlurUtils.h" |
9 #include "GrDrawContext.h" | 9 #include "GrDrawContext.h" |
10 #include "GrCaps.h" | 10 #include "GrCaps.h" |
11 #include "GrContext.h" | 11 #include "GrContext.h" |
12 #include "effects/GrSimpleTextureEffect.h" | 12 #include "effects/GrSimpleTextureEffect.h" |
13 #include "GrStrokeInfo.h" | 13 #include "GrStyle.h" |
14 #include "GrTexture.h" | 14 #include "GrTexture.h" |
15 #include "GrTextureProvider.h" | 15 #include "GrTextureProvider.h" |
16 #include "SkDraw.h" | 16 #include "SkDraw.h" |
17 #include "SkGrPriv.h" | 17 #include "SkGrPriv.h" |
18 #include "SkMaskFilter.h" | 18 #include "SkMaskFilter.h" |
19 #include "SkPaint.h" | 19 #include "SkPaint.h" |
20 | 20 |
21 static bool clip_bounds_quick_reject(const SkIRect& clipBounds, const SkIRect& r
ect) { | 21 static bool clip_bounds_quick_reject(const SkIRect& clipBounds, const SkIRect& r
ect) { |
22 return clipBounds.isEmpty() || rect.isEmpty() || !SkIRect::Intersects(clipBo
unds, rect); | 22 return clipBounds.isEmpty() || rect.isEmpty() || !SkIRect::Intersects(clipBo
unds, rect); |
23 } | 23 } |
(...skipping 23 matching lines...) Expand all Loading... |
47 } | 47 } |
48 | 48 |
49 static bool sw_draw_with_mask_filter(GrDrawContext* drawContext, | 49 static bool sw_draw_with_mask_filter(GrDrawContext* drawContext, |
50 GrTextureProvider* textureProvider, | 50 GrTextureProvider* textureProvider, |
51 const GrClip& clipData, | 51 const GrClip& clipData, |
52 const SkMatrix& viewMatrix, | 52 const SkMatrix& viewMatrix, |
53 const SkPath& devPath, | 53 const SkPath& devPath, |
54 const SkMaskFilter* filter, | 54 const SkMaskFilter* filter, |
55 const SkIRect& clipBounds, | 55 const SkIRect& clipBounds, |
56 GrPaint* grp, | 56 GrPaint* grp, |
57 SkStrokeRec::InitStyle style) { | 57 SkStrokeRec::InitStyle fillOrHairline) { |
58 SkMask srcM, dstM; | 58 SkMask srcM, dstM; |
59 | |
60 if (!SkDraw::DrawToMask(devPath, &clipBounds, filter, &viewMatrix, &srcM, | 59 if (!SkDraw::DrawToMask(devPath, &clipBounds, filter, &viewMatrix, &srcM, |
61 SkMask::kComputeBoundsAndRenderImage_CreateMode, sty
le)) { | 60 SkMask::kComputeBoundsAndRenderImage_CreateMode, fil
lOrHairline)) { |
62 return false; | 61 return false; |
63 } | 62 } |
64 SkAutoMaskFreeImage autoSrc(srcM.fImage); | 63 SkAutoMaskFreeImage autoSrc(srcM.fImage); |
65 | 64 |
66 if (!filter->filterMask(&dstM, srcM, viewMatrix, nullptr)) { | 65 if (!filter->filterMask(&dstM, srcM, viewMatrix, nullptr)) { |
67 return false; | 66 return false; |
68 } | 67 } |
69 // this will free-up dstM when we're done (allocated in filterMask()) | 68 // this will free-up dstM when we're done (allocated in filterMask()) |
70 SkAutoMaskFreeImage autoDst(dstM.fImage); | 69 SkAutoMaskFreeImage autoDst(dstM.fImage); |
71 | 70 |
(...skipping 17 matching lines...) Expand all Loading... |
89 | 88 |
90 SkRect maskRect = SkRect::Make(dstM.fBounds); | 89 SkRect maskRect = SkRect::Make(dstM.fBounds); |
91 | 90 |
92 return draw_mask(drawContext, clipData, viewMatrix, maskRect, grp, texture); | 91 return draw_mask(drawContext, clipData, viewMatrix, maskRect, grp, texture); |
93 } | 92 } |
94 | 93 |
95 // Create a mask of 'devPath' and place the result in 'mask'. | 94 // Create a mask of 'devPath' and place the result in 'mask'. |
96 static sk_sp<GrTexture> create_mask_GPU(GrContext* context, | 95 static sk_sp<GrTexture> create_mask_GPU(GrContext* context, |
97 SkRect* maskRect, | 96 SkRect* maskRect, |
98 const SkPath& devPath, | 97 const SkPath& devPath, |
99 SkStrokeRec::InitStyle style, | 98 SkStrokeRec::InitStyle fillOrHairline, |
100 bool doAA, | 99 bool doAA, |
101 int sampleCnt) { | 100 int sampleCnt) { |
102 // This mask will ultimately be drawn as a non-AA rect (see draw_mask). | 101 // This mask will ultimately be drawn as a non-AA rect (see draw_mask). |
103 // Non-AA rects have a bad habit of snapping arbitrarily. Integerize here | 102 // Non-AA rects have a bad habit of snapping arbitrarily. Integerize here |
104 // so the mask draws in a reproducible manner. | 103 // so the mask draws in a reproducible manner. |
105 *maskRect = SkRect::Make(maskRect->roundOut()); | 104 *maskRect = SkRect::Make(maskRect->roundOut()); |
106 | 105 |
107 if (!doAA) { | 106 if (!doAA) { |
108 // Don't need MSAA if mask isn't AA | 107 // Don't need MSAA if mask isn't AA |
109 sampleCnt = 0; | 108 sampleCnt = 0; |
(...skipping 22 matching lines...) Expand all Loading... |
132 tempPaint.setCoverageSetOpXPFactory(SkRegion::kReplace_Op); | 131 tempPaint.setCoverageSetOpXPFactory(SkRegion::kReplace_Op); |
133 | 132 |
134 // setup new clip | 133 // setup new clip |
135 const SkRect clipRect = SkRect::MakeWH(maskRect->width(), maskRect->height()
); | 134 const SkRect clipRect = SkRect::MakeWH(maskRect->width(), maskRect->height()
); |
136 GrClip clip(clipRect); | 135 GrClip clip(clipRect); |
137 | 136 |
138 // Draw the mask into maskTexture with the path's integerized top-left at | 137 // Draw the mask into maskTexture with the path's integerized top-left at |
139 // the origin using tempPaint. | 138 // the origin using tempPaint. |
140 SkMatrix translate; | 139 SkMatrix translate; |
141 translate.setTranslate(-maskRect->fLeft, -maskRect->fTop); | 140 translate.setTranslate(-maskRect->fLeft, -maskRect->fTop); |
142 drawContext->drawPath(clip, tempPaint, translate, devPath, GrStrokeInfo(styl
e)); | 141 drawContext->drawPath(clip, tempPaint, translate, devPath, GrStyle(fillOrHai
rline)); |
143 return drawContext->asTexture();; | 142 return drawContext->asTexture();; |
144 } | 143 } |
145 | 144 |
146 static void draw_path_with_mask_filter(GrContext* context, | 145 static void draw_path_with_mask_filter(GrContext* context, |
147 GrDrawContext* drawContext, | 146 GrDrawContext* drawContext, |
148 const GrClip& clip, | 147 const GrClip& clip, |
149 GrPaint* paint, | 148 GrPaint* paint, |
150 const SkMatrix& viewMatrix, | 149 const SkMatrix& viewMatrix, |
151 const SkMaskFilter* maskFilter, | 150 const SkMaskFilter* maskFilter, |
152 const SkPathEffect* pathEffect, | 151 const GrStyle& style, |
153 const GrStrokeInfo& strokeInfo, | 152 const SkPath* path, |
154 SkPath* pathPtr, | |
155 bool pathIsMutable) { | 153 bool pathIsMutable) { |
156 SkASSERT(maskFilter); | 154 SkASSERT(maskFilter); |
157 | 155 |
158 SkIRect clipBounds; | 156 SkIRect clipBounds; |
159 clip.getConservativeBounds(drawContext->width(), drawContext->height(), &cli
pBounds); | 157 clip.getConservativeBounds(drawContext->width(), drawContext->height(), &cli
pBounds); |
160 SkTLazy<SkPath> tmpPath; | 158 SkTLazy<SkPath> tmpPath; |
| 159 SkStrokeRec::InitStyle fillOrHairline; |
161 | 160 |
162 static const SkRect* cullRect = nullptr; // TODO: what is our bounds? | 161 // We just fully apply the style here. |
163 | 162 if (style.applies()) { |
164 SkASSERT(strokeInfo.isDashed() || !pathEffect); | 163 if (!style.applyToPath(tmpPath.init(), &fillOrHairline, *path, |
165 SkStrokeRec::InitStyle maskStyle; | 164 GrStyle::MatrixToScaleFactor(viewMatrix))) { |
166 if (strokeInfo.isHairlineStyle()) { | 165 return; |
167 maskStyle = SkStrokeRec::kHairline_InitStyle; | 166 } |
| 167 pathIsMutable = true; |
| 168 path = tmpPath.get(); |
| 169 } else if (style.isSimpleHairline()) { |
| 170 fillOrHairline = SkStrokeRec::kHairline_InitStyle; |
168 } else { | 171 } else { |
169 SkPath* strokedPath = pathIsMutable ? pathPtr : tmpPath.init(); | 172 SkASSERT(style.isSimpleFill()); |
170 SkStrokeRec rec = strokeInfo; | 173 fillOrHairline = SkStrokeRec::kFill_InitStyle; |
171 if (strokeInfo.isDashed()) { | |
172 if (pathEffect->filterPath(strokedPath, *pathPtr, &rec, cullRect)) { | |
173 pathPtr = strokedPath; | |
174 pathPtr->setIsVolatile(true); | |
175 pathIsMutable = true; | |
176 } | |
177 } | |
178 if (rec.applyToPath(strokedPath, *pathPtr)) { | |
179 // Apply the stroke to the path if there is one | |
180 pathPtr = strokedPath; | |
181 pathPtr->setIsVolatile(true); | |
182 pathIsMutable = true; | |
183 } | |
184 maskStyle = SkStrokeRec::kFill_InitStyle; | |
185 } | |
186 | |
187 // avoid possibly allocating a new path in transform if we can | |
188 SkPath* devPathPtr = pathIsMutable ? pathPtr : tmpPath.init(); | |
189 if (!pathIsMutable) { | |
190 devPathPtr->setIsVolatile(true); | |
191 } | 174 } |
192 | 175 |
193 // transform the path into device space | 176 // transform the path into device space |
194 pathPtr->transform(viewMatrix, devPathPtr); | 177 if (!viewMatrix.isIdentity()) { |
| 178 SkPath* result; |
| 179 if (pathIsMutable) { |
| 180 result = const_cast<SkPath*>(path); |
| 181 } else { |
| 182 if (!tmpPath.isValid()) { |
| 183 tmpPath.init(); |
| 184 } |
| 185 result = tmpPath.get(); |
| 186 } |
| 187 path->transform(viewMatrix, result); |
| 188 path = result; |
| 189 result->setIsVolatile(true); |
| 190 pathIsMutable = true; |
| 191 } |
195 | 192 |
196 SkRect maskRect; | 193 SkRect maskRect; |
197 if (maskFilter->canFilterMaskGPU(SkRRect::MakeRect(devPathPtr->getBounds()), | 194 if (maskFilter->canFilterMaskGPU(SkRRect::MakeRect(path->getBounds()), |
198 clipBounds, | 195 clipBounds, |
199 viewMatrix, | 196 viewMatrix, |
200 &maskRect)) { | 197 &maskRect)) { |
201 SkIRect finalIRect; | 198 SkIRect finalIRect; |
202 maskRect.roundOut(&finalIRect); | 199 maskRect.roundOut(&finalIRect); |
203 if (clip_bounds_quick_reject(clipBounds, finalIRect)) { | 200 if (clip_bounds_quick_reject(clipBounds, finalIRect)) { |
204 // clipped out | 201 // clipped out |
205 return; | 202 return; |
206 } | 203 } |
207 | 204 |
208 if (maskFilter->directFilterMaskGPU(context->textureProvider(), | 205 if (maskFilter->directFilterMaskGPU(context->textureProvider(), |
209 drawContext, | 206 drawContext, |
210 paint, | 207 paint, |
211 clip, | 208 clip, |
212 viewMatrix, | 209 viewMatrix, |
213 SkStrokeRec(maskStyle), | 210 SkStrokeRec(fillOrHairline), |
214 *devPathPtr)) { | 211 *path)) { |
215 // the mask filter was able to draw itself directly, so there's noth
ing | 212 // the mask filter was able to draw itself directly, so there's noth
ing |
216 // left to do. | 213 // left to do. |
217 return; | 214 return; |
218 } | 215 } |
219 | 216 |
220 sk_sp<GrTexture> mask(create_mask_GPU(context, | 217 sk_sp<GrTexture> mask(create_mask_GPU(context, |
221 &maskRect, | 218 &maskRect, |
222 *devPathPtr, | 219 *path, |
223 maskStyle, | 220 fillOrHairline, |
224 paint->isAntiAlias(), | 221 paint->isAntiAlias(), |
225 drawContext->numColorSamples())); | 222 drawContext->numColorSamples())); |
226 if (mask) { | 223 if (mask) { |
227 GrTexture* filtered; | 224 GrTexture* filtered; |
228 | 225 |
229 if (maskFilter->filterMaskGPU(mask.get(), viewMatrix, maskRect, &fil
tered, true)) { | 226 if (maskFilter->filterMaskGPU(mask.get(), viewMatrix, maskRect, &fil
tered, true)) { |
230 // filterMaskGPU gives us ownership of a ref to the result | 227 // filterMaskGPU gives us ownership of a ref to the result |
231 SkAutoTUnref<GrTexture> atu(filtered); | 228 SkAutoTUnref<GrTexture> atu(filtered); |
232 if (draw_mask(drawContext, clip, viewMatrix, maskRect, paint, fi
ltered)) { | 229 if (draw_mask(drawContext, clip, viewMatrix, maskRect, paint, fi
ltered)) { |
233 // This path is completely drawn | 230 // This path is completely drawn |
234 return; | 231 return; |
235 } | 232 } |
236 } | 233 } |
237 } | 234 } |
238 } | 235 } |
239 | 236 |
240 sw_draw_with_mask_filter(drawContext, context->textureProvider(), | 237 sw_draw_with_mask_filter(drawContext, context->textureProvider(), |
241 clip, viewMatrix, *devPathPtr, | 238 clip, viewMatrix, *path, |
242 maskFilter, clipBounds, paint, maskStyle); | 239 maskFilter, clipBounds, paint, fillOrHairline); |
| 240 } |
| 241 |
| 242 void GrBlurUtils::drawPathWithMaskFilter(GrContext* context, |
| 243 GrDrawContext* drawContext, |
| 244 const GrClip& clip, |
| 245 const SkPath& path, |
| 246 GrPaint* paint, |
| 247 const SkMatrix& viewMatrix, |
| 248 const SkMaskFilter* mf, |
| 249 const GrStyle& style, |
| 250 bool pathIsMutable) { |
| 251 draw_path_with_mask_filter(context, drawContext, clip, paint, viewMatrix, mf
, |
| 252 style, &path, pathIsMutable); |
243 } | 253 } |
244 | 254 |
245 void GrBlurUtils::drawPathWithMaskFilter(GrContext* context, | 255 void GrBlurUtils::drawPathWithMaskFilter(GrContext* context, |
246 GrDrawContext* drawContext, | 256 GrDrawContext* drawContext, |
247 const GrClip& clip, | 257 const GrClip& clip, |
248 const SkPath& origPath, | 258 const SkPath& origPath, |
249 GrPaint* paint, | |
250 const SkMatrix& viewMatrix, | |
251 const SkMaskFilter* mf, | |
252 const SkPathEffect* pathEffect, | |
253 const GrStrokeInfo& origStrokeInfo, | |
254 bool pathIsMutable) { | |
255 SkPath* pathPtr = const_cast<SkPath*>(&origPath); | |
256 | |
257 SkTLazy<SkPath> tmpPath; | |
258 GrStrokeInfo strokeInfo(origStrokeInfo); | |
259 | |
260 if (!strokeInfo.isDashed() && pathEffect && pathEffect->filterPath(tmpPath.i
nit(), *pathPtr, | |
261 &strokeIn
fo, nullptr)) { | |
262 pathPtr = tmpPath.get(); | |
263 pathPtr->setIsVolatile(true); | |
264 pathIsMutable = true; | |
265 pathEffect = nullptr; | |
266 } | |
267 | |
268 draw_path_with_mask_filter(context, drawContext, clip, paint, viewMatrix, mf
, pathEffect, | |
269 strokeInfo, pathPtr, pathIsMutable); | |
270 } | |
271 | |
272 void GrBlurUtils::drawPathWithMaskFilter(GrContext* context, | |
273 GrDrawContext* drawContext, | |
274 const GrClip& clip, | |
275 const SkPath& origSrcPath, | |
276 const SkPaint& paint, | 259 const SkPaint& paint, |
277 const SkMatrix& origViewMatrix, | 260 const SkMatrix& origViewMatrix, |
278 const SkMatrix* prePathMatrix, | 261 const SkMatrix* prePathMatrix, |
279 const SkIRect& clipBounds, | 262 const SkIRect& clipBounds, |
280 bool pathIsMutable) { | 263 bool pathIsMutable) { |
281 SkASSERT(!pathIsMutable || origSrcPath.isVolatile()); | 264 SkASSERT(!pathIsMutable || origPath.isVolatile()); |
282 | 265 |
283 GrStrokeInfo strokeInfo(paint); | 266 GrStyle style(paint); |
284 // comment out the line below to determine if it is the reason that the chro
me mac perf bot | |
285 // has begun crashing | |
286 // strokeInfo.setResScale(SkDraw::ComputeResScaleForStroking(origViewMatrix)
); | |
287 | |
288 // If we have a prematrix, apply it to the path, optimizing for the case | 267 // If we have a prematrix, apply it to the path, optimizing for the case |
289 // where the original path can in fact be modified in place (even though | 268 // where the original path can in fact be modified in place (even though |
290 // its parameter type is const). | 269 // its parameter type is const). |
291 SkPath* pathPtr = const_cast<SkPath*>(&origSrcPath); | 270 |
| 271 const SkPath* path = &origPath; |
292 SkTLazy<SkPath> tmpPath; | 272 SkTLazy<SkPath> tmpPath; |
293 SkTLazy<SkPath> effectPath; | |
294 SkPathEffect* pathEffect = paint.getPathEffect(); | |
295 | 273 |
296 SkMatrix viewMatrix = origViewMatrix; | 274 SkMatrix viewMatrix = origViewMatrix; |
297 | 275 |
298 if (prePathMatrix) { | 276 if (prePathMatrix) { |
299 // stroking, path effects, and blurs are supposed to be applied *after*
the prePathMatrix. | 277 // Styling, blurs, and shading are supposed to be applied *after* the pr
ePathMatrix. |
300 // The pre-path-matrix also should not affect shading. | 278 if (!paint.getMaskFilter() && !paint.getShader() && !style.applies()) { |
301 if (!paint.getMaskFilter() && !pathEffect && !paint.getShader() && | |
302 (strokeInfo.isFillStyle() || strokeInfo.isHairlineStyle())) { | |
303 viewMatrix.preConcat(*prePathMatrix); | 279 viewMatrix.preConcat(*prePathMatrix); |
304 } else { | 280 } else { |
305 SkPath* result = pathPtr; | 281 SkPath* result = pathIsMutable ? const_cast<SkPath*>(path) : tmpPath
.init(); |
306 | 282 pathIsMutable = true; |
307 if (!pathIsMutable) { | 283 path->transform(*prePathMatrix, result); |
308 result = tmpPath.init(); | 284 path = result; |
309 result->setIsVolatile(true); | 285 result->setIsVolatile(true); |
310 pathIsMutable = true; | |
311 } | |
312 // should I push prePathMatrix on our MV stack temporarily, instead | |
313 // of applying it here? See SkDraw.cpp | |
314 pathPtr->transform(*prePathMatrix, result); | |
315 pathPtr = result; | |
316 } | 286 } |
317 } | 287 } |
318 // at this point we're done with prePathMatrix | 288 // at this point we're done with prePathMatrix |
319 SkDEBUGCODE(prePathMatrix = (const SkMatrix*)0x50FF8001;) | 289 SkDEBUGCODE(prePathMatrix = (const SkMatrix*)0x50FF8001;) |
320 | 290 |
321 SkTLazy<SkPath> tmpPath2; | |
322 | |
323 if (!strokeInfo.isDashed() && pathEffect && | |
324 pathEffect->filterPath(tmpPath2.init(), *pathPtr, &strokeInfo, nullptr))
{ | |
325 pathPtr = tmpPath2.get(); | |
326 pathPtr->setIsVolatile(true); | |
327 pathIsMutable = true; | |
328 pathEffect = nullptr; | |
329 } | |
330 | |
331 GrPaint grPaint; | 291 GrPaint grPaint; |
332 if (!SkPaintToGrPaint(context, paint, viewMatrix, drawContext->isGammaCorrec
t(), | 292 if (!SkPaintToGrPaint(context, paint, viewMatrix, drawContext->isGammaCorrec
t(), |
333 &grPaint)) { | 293 &grPaint)) { |
334 return; | 294 return; |
335 } | 295 } |
336 | 296 |
337 if (paint.getMaskFilter()) { | 297 if (paint.getMaskFilter()) { |
338 draw_path_with_mask_filter(context, drawContext, clip, &grPaint, viewMat
rix, | 298 draw_path_with_mask_filter(context, drawContext, clip, &grPaint, viewMat
rix, |
339 paint.getMaskFilter(), pathEffect, strokeInfo
, | 299 paint.getMaskFilter(), style, |
340 pathPtr, pathIsMutable); | 300 path, pathIsMutable); |
341 } else { | 301 } else { |
342 drawContext->drawPath(clip, grPaint, viewMatrix, *pathPtr, strokeInfo); | 302 drawContext->drawPath(clip, grPaint, viewMatrix, *path, style); |
343 } | 303 } |
344 } | 304 } |
OLD | NEW |