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