• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2015 Google Inc.
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 "src/gpu/GrBlurUtils.h"
9 
10 #if SK_GPU_V1
11 
12 #include "include/gpu/GrDirectContext.h"
13 #include "include/gpu/GrRecordingContext.h"
14 #include "src/gpu/GrCaps.h"
15 #include "src/gpu/GrDirectContextPriv.h"
16 #include "src/gpu/GrFixedClip.h"
17 #include "src/gpu/GrProxyProvider.h"
18 #include "src/gpu/GrRecordingContextPriv.h"
19 #include "src/gpu/GrResourceProvider.h"
20 #include "src/gpu/GrStyle.h"
21 #include "src/gpu/GrTextureProxy.h"
22 #include "src/gpu/GrThreadSafeCache.h"
23 #include "src/gpu/GrUtil.h"
24 #include "src/gpu/SkGr.h"
25 #include "src/gpu/effects/GrTextureEffect.h"
26 #include "src/gpu/geometry/GrStyledShape.h"
27 #include "src/gpu/v1/SurfaceDrawContext_v1.h"
28 
29 #include "include/core/SkPaint.h"
30 #include "src/core/SkDraw.h"
31 #include "src/core/SkMaskFilterBase.h"
32 #include "src/core/SkMatrixProvider.h"
33 #ifdef SKIA_OHOS
34 #include "src/core/SkSDFFilter.h"
35 #endif
36 #include "src/core/SkTLazy.h"
37 #include "src/gpu/SkGr.h"
38 
clip_bounds_quick_reject(const SkIRect & clipBounds,const SkIRect & rect)39 static bool clip_bounds_quick_reject(const SkIRect& clipBounds, const SkIRect& rect) {
40     return clipBounds.isEmpty() || rect.isEmpty() || !SkIRect::Intersects(clipBounds, rect);
41 }
42 
43 static constexpr auto kMaskOrigin = kTopLeft_GrSurfaceOrigin;
44 
45 // Draw a mask using the supplied paint. Since the coverage/geometry
46 // is already burnt into the mask this boils down to a rect draw.
47 // Return true if the mask was successfully drawn.
draw_mask(skgpu::v1::SurfaceDrawContext * sdc,const GrClip * clip,const SkMatrix & viewMatrix,const SkIRect & maskBounds,GrPaint && paint,GrSurfaceProxyView mask)48 static bool draw_mask(skgpu::v1::SurfaceDrawContext* sdc,
49                       const GrClip* clip,
50                       const SkMatrix& viewMatrix,
51                       const SkIRect& maskBounds,
52                       GrPaint&& paint,
53                       GrSurfaceProxyView mask) {
54     SkMatrix inverse;
55     if (!viewMatrix.invert(&inverse)) {
56         return false;
57     }
58 
59     mask.concatSwizzle(GrSwizzle("aaaa"));
60 
61     SkMatrix matrix = SkMatrix::Translate(-SkIntToScalar(maskBounds.fLeft),
62                                           -SkIntToScalar(maskBounds.fTop));
63     matrix.preConcat(viewMatrix);
64     paint.setCoverageFragmentProcessor(
65             GrTextureEffect::Make(std::move(mask), kUnknown_SkAlphaType, matrix));
66 
67     sdc->fillPixelsWithLocalMatrix(clip, std::move(paint), maskBounds, inverse);
68     return true;
69 }
70 
mask_release_proc(void * addr,void *)71 static void mask_release_proc(void* addr, void* /*context*/) {
72     SkMask::FreeImage(addr);
73 }
74 
75 // This stores the mapping from an unclipped, integerized, device-space, shape bounds to
76 // the filtered mask's draw rect.
77 struct DrawRectData {
78     SkIVector fOffset;
79     SkISize   fSize;
80 };
81 
create_data(const SkIRect & drawRect,const SkIRect & origDevBounds)82 static sk_sp<SkData> create_data(const SkIRect& drawRect, const SkIRect& origDevBounds) {
83 
84     DrawRectData drawRectData { {drawRect.fLeft - origDevBounds.fLeft,
85                                  drawRect.fTop - origDevBounds.fTop},
86                                 drawRect.size() };
87 
88     return SkData::MakeWithCopy(&drawRectData, sizeof(drawRectData));
89 }
90 
extract_draw_rect_from_data(SkData * data,const SkIRect & origDevBounds)91 static SkIRect extract_draw_rect_from_data(SkData* data, const SkIRect& origDevBounds) {
92     auto drawRectData = static_cast<const DrawRectData*>(data->data());
93 
94     return SkIRect::MakeXYWH(origDevBounds.fLeft + drawRectData->fOffset.fX,
95                              origDevBounds.fTop + drawRectData->fOffset.fY,
96                              drawRectData->fSize.fWidth,
97                              drawRectData->fSize.fHeight);
98 }
99 
sw_create_filtered_mask(GrRecordingContext * rContext,const SkMatrix & viewMatrix,const GrStyledShape & shape,const SkMaskFilter * filter,const SkIRect & unclippedDevShapeBounds,const SkIRect & clipBounds,SkIRect * drawRect,GrUniqueKey * key)100 static GrSurfaceProxyView sw_create_filtered_mask(GrRecordingContext* rContext,
101                                                   const SkMatrix& viewMatrix,
102                                                   const GrStyledShape& shape,
103                                                   const SkMaskFilter* filter,
104                                                   const SkIRect& unclippedDevShapeBounds,
105                                                   const SkIRect& clipBounds,
106                                                   SkIRect* drawRect,
107                                                   GrUniqueKey* key) {
108     SkASSERT(filter);
109     SkASSERT(!shape.style().applies());
110 
111     auto threadSafeCache = rContext->priv().threadSafeCache();
112 
113     GrSurfaceProxyView filteredMaskView;
114     sk_sp<SkData> data;
115 
116     if (key->isValid()) {
117         std::tie(filteredMaskView, data) = threadSafeCache->findWithData(*key);
118     }
119 
120     if (filteredMaskView) {
121         SkASSERT(data);
122         SkASSERT(kMaskOrigin == filteredMaskView.origin());
123 
124         *drawRect = extract_draw_rect_from_data(data.get(), unclippedDevShapeBounds);
125     } else {
126         SkStrokeRec::InitStyle fillOrHairline = shape.style().isSimpleHairline()
127                                                         ? SkStrokeRec::kHairline_InitStyle
128                                                         : SkStrokeRec::kFill_InitStyle;
129 
130         // TODO: it seems like we could create an SkDraw here and set its fMatrix field rather
131         // than explicitly transforming the path to device space.
132         SkPath devPath;
133 
134         shape.asPath(&devPath);
135 
136         devPath.transform(viewMatrix);
137 
138         SkMask srcM, dstM;
139         if (!SkDraw::DrawToMask(devPath, &clipBounds, filter, &viewMatrix, &srcM,
140                                 SkMask::kComputeBoundsAndRenderImage_CreateMode, fillOrHairline)) {
141             return {};
142         }
143         SkAutoMaskFreeImage autoSrc(srcM.fImage);
144 
145         SkASSERT(SkMask::kA8_Format == srcM.fFormat);
146 
147         if (!as_MFB(filter)->filterMask(&dstM, srcM, viewMatrix, nullptr)) {
148             return {};
149         }
150         // this will free-up dstM when we're done (allocated in filterMask())
151         SkAutoMaskFreeImage autoDst(dstM.fImage);
152 
153         if (clip_bounds_quick_reject(clipBounds, dstM.fBounds)) {
154             return {};
155         }
156 
157         // we now have a device-aligned 8bit mask in dstM, ready to be drawn using
158         // the current clip (and identity matrix) and GrPaint settings
159         SkBitmap bm;
160         if (!bm.installPixels(SkImageInfo::MakeA8(dstM.fBounds.width(), dstM.fBounds.height()),
161                               autoDst.release(), dstM.fRowBytes, mask_release_proc, nullptr)) {
162             return {};
163         }
164         bm.setImmutable();
165 
166         std::tie(filteredMaskView, std::ignore) = GrMakeUncachedBitmapProxyView(
167                 rContext,
168                 bm,
169                 GrMipmapped::kNo,
170                 SkBackingFit::kApprox);
171         if (!filteredMaskView) {
172             return {};
173         }
174 
175         SkASSERT(kMaskOrigin == filteredMaskView.origin());
176 
177         *drawRect = dstM.fBounds;
178 
179         if (key->isValid()) {
180             key->setCustomData(create_data(*drawRect, unclippedDevShapeBounds));
181             std::tie(filteredMaskView, data) = threadSafeCache->addWithData(*key, filteredMaskView);
182             // If we got a different view back from 'addWithData' it could have a different drawRect
183             *drawRect = extract_draw_rect_from_data(data.get(), unclippedDevShapeBounds);
184         }
185     }
186 
187     return filteredMaskView;
188 }
189 
190 // Create a mask of 'shape' and return the resulting surfaceDrawContext
create_mask_GPU(GrRecordingContext * rContext,const SkIRect & maskRect,const SkMatrix & origViewMatrix,const GrStyledShape & shape,int sampleCnt)191 static std::unique_ptr<skgpu::v1::SurfaceDrawContext> create_mask_GPU(
192         GrRecordingContext* rContext,
193         const SkIRect& maskRect,
194         const SkMatrix& origViewMatrix,
195         const GrStyledShape& shape,
196         int sampleCnt) {
197     // We cache blur masks. Use default surface props here so we can use the same cached mask
198     // regardless of the final dst surface.
199     SkSurfaceProps defaultSurfaceProps;
200 
201     // Use GrResourceProvider::MakeApprox to implement our own approximate size matching, but demand
202     // a "SkBackingFit::kExact" size match on the actual render target. We do this because the
203     // filter will reach outside the src bounds, so we need to pre-clear these values to ensure a
204     // "decal" sampling effect (i.e., ensure reads outside the src bounds return alpha=0).
205     //
206     // FIXME: Reads outside the left and top edges will actually clamp to the edge pixel. And in the
207     // event that MakeApprox does not change the size, reads outside the right and/or bottom will do
208     // the same. We should offset our filter within the render target and expand the size as needed
209     // to guarantee at least 1px of padding on all sides.
210     auto approxSize = GrResourceProvider::MakeApprox(maskRect.size());
211     auto sdc = skgpu::v1::SurfaceDrawContext::MakeWithFallback(rContext,
212                                                                GrColorType::kAlpha_8,
213                                                                nullptr,
214                                                                SkBackingFit::kExact,
215                                                                approxSize,
216                                                                defaultSurfaceProps,
217                                                                sampleCnt,
218                                                                GrMipmapped::kNo,
219                                                                GrProtected::kNo,
220                                                                kMaskOrigin);
221     if (!sdc) {
222         return nullptr;
223     }
224 
225     sdc->clear(SK_PMColor4fTRANSPARENT);
226 
227     GrPaint maskPaint;
228     maskPaint.setCoverageSetOpXPFactory(SkRegion::kReplace_Op);
229 
230     // setup new clip
231     GrFixedClip clip(sdc->dimensions(), SkIRect::MakeWH(maskRect.width(), maskRect.height()));
232 
233     // Draw the mask into maskTexture with the path's integerized top-left at the origin using
234     // maskPaint.
235     SkMatrix viewMatrix = origViewMatrix;
236     viewMatrix.postTranslate(-SkIntToScalar(maskRect.fLeft), -SkIntToScalar(maskRect.fTop));
237     sdc->drawShape(&clip, std::move(maskPaint), GrAA::kYes, viewMatrix, GrStyledShape(shape));
238     return sdc;
239 }
240 
get_unclipped_shape_dev_bounds(const GrStyledShape & shape,const SkMatrix & matrix,SkIRect * devBounds)241 static bool get_unclipped_shape_dev_bounds(const GrStyledShape& shape, const SkMatrix& matrix,
242                                            SkIRect* devBounds) {
243     SkRect shapeBounds = shape.styledBounds();
244     if (shapeBounds.isEmpty()) {
245         return false;
246     }
247     SkRect shapeDevBounds;
248     matrix.mapRect(&shapeDevBounds, shapeBounds);
249     // Even though these are "unclipped" bounds we still clip to the int32_t range.
250     // This is the largest int32_t that is representable exactly as a float. The next 63 larger ints
251     // would round down to this value when cast to a float, but who really cares.
252     // INT32_MIN is exactly representable.
253     static constexpr int32_t kMaxInt = 2147483520;
254     if (!shapeDevBounds.intersect(SkRect::MakeLTRB(INT32_MIN, INT32_MIN, kMaxInt, kMaxInt))) {
255         return false;
256     }
257     // Make sure that the resulting SkIRect can have representable width and height
258     if (SkScalarRoundToInt(shapeDevBounds.width()) > kMaxInt ||
259         SkScalarRoundToInt(shapeDevBounds.height()) > kMaxInt) {
260         return false;
261     }
262     shapeDevBounds.roundOut(devBounds);
263     return true;
264 }
265 
266 // Gets the shape bounds, the clip bounds, and the intersection (if any). Returns false if there
267 // is no intersection.
get_shape_and_clip_bounds(skgpu::v1::SurfaceDrawContext * sdc,const GrClip * clip,const GrStyledShape & shape,const SkMatrix & matrix,SkIRect * unclippedDevShapeBounds,SkIRect * devClipBounds)268 static bool get_shape_and_clip_bounds(skgpu::v1::SurfaceDrawContext* sdc,
269                                       const GrClip* clip,
270                                       const GrStyledShape& shape,
271                                       const SkMatrix& matrix,
272                                       SkIRect* unclippedDevShapeBounds,
273                                       SkIRect* devClipBounds) {
274     // compute bounds as intersection of rt size, clip, and path
275     *devClipBounds = clip ? clip->getConservativeBounds()
276                           : SkIRect::MakeWH(sdc->width(), sdc->height());
277 
278     if (!get_unclipped_shape_dev_bounds(shape, matrix, unclippedDevShapeBounds)) {
279         *unclippedDevShapeBounds = SkIRect::MakeEmpty();
280         return false;
281     }
282 
283     return true;
284 }
285 
286 // The key and clip-bounds are computed together because the caching decision can impact the
287 // clip-bound - since we only cache un-clipped masks the clip can be removed entirely.
288 // A 'false' return value indicates that the shape is known to be clipped away.
compute_key_and_clip_bounds(GrUniqueKey * maskKey,SkIRect * boundsForClip,const GrCaps * caps,const SkMatrix & viewMatrix,bool inverseFilled,const SkMaskFilterBase * maskFilter,const GrStyledShape & shape,const SkIRect & unclippedDevShapeBounds,const SkIRect & devClipBounds)289 static bool compute_key_and_clip_bounds(GrUniqueKey* maskKey,
290                                         SkIRect* boundsForClip,
291                                         const GrCaps* caps,
292                                         const SkMatrix& viewMatrix,
293                                         bool inverseFilled,
294                                         const SkMaskFilterBase* maskFilter,
295                                         const GrStyledShape& shape,
296                                         const SkIRect& unclippedDevShapeBounds,
297                                         const SkIRect& devClipBounds) {
298     *boundsForClip = devClipBounds;
299 
300 #ifndef SK_DISABLE_MASKFILTERED_MASK_CACHING
301     // To prevent overloading the cache with entries during animations we limit the cache of masks
302     // to cases where the matrix preserves axis alignment.
303     bool useCache = !inverseFilled && viewMatrix.preservesAxisAlignment() &&
304                     shape.hasUnstyledKey() && as_MFB(maskFilter)->asABlur(nullptr);
305 
306     if (useCache) {
307         SkIRect clippedMaskRect, unClippedMaskRect;
308         maskFilter->canFilterMaskGPU(shape, unclippedDevShapeBounds, devClipBounds,
309                                      viewMatrix, &clippedMaskRect);
310         maskFilter->canFilterMaskGPU(shape, unclippedDevShapeBounds, unclippedDevShapeBounds,
311                                      viewMatrix, &unClippedMaskRect);
312         if (clippedMaskRect.isEmpty()) {
313             return false;
314         }
315 
316         // Use the cache only if >50% of the filtered mask is visible.
317         int unclippedWidth = unClippedMaskRect.width();
318         int unclippedHeight = unClippedMaskRect.height();
319         int64_t unclippedArea = sk_64_mul(unclippedWidth, unclippedHeight);
320         int64_t clippedArea = sk_64_mul(clippedMaskRect.width(), clippedMaskRect.height());
321         int maxTextureSize = caps->maxTextureSize();
322         if (unclippedArea > 2 * clippedArea || unclippedWidth > maxTextureSize ||
323             unclippedHeight > maxTextureSize) {
324             useCache = false;
325         } else {
326             // Make the clip not affect the mask
327             *boundsForClip = unclippedDevShapeBounds;
328         }
329     }
330 
331     if (useCache) {
332         static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain();
333         GrUniqueKey::Builder builder(maskKey, kDomain, 5 + 2 + shape.unstyledKeySize(),
334                                      "Mask Filtered Masks");
335 
336         // We require the upper left 2x2 of the matrix to match exactly for a cache hit.
337         SkScalar sx = viewMatrix.get(SkMatrix::kMScaleX);
338         SkScalar sy = viewMatrix.get(SkMatrix::kMScaleY);
339         SkScalar kx = viewMatrix.get(SkMatrix::kMSkewX);
340         SkScalar ky = viewMatrix.get(SkMatrix::kMSkewY);
341         SkScalar tx = viewMatrix.get(SkMatrix::kMTransX);
342         SkScalar ty = viewMatrix.get(SkMatrix::kMTransY);
343         // Allow 8 bits each in x and y of subpixel positioning. But, note that we're allowing
344         // reuse for integer translations.
345         SkFixed fracX = SkScalarToFixed(SkScalarFraction(tx)) & 0x0000FF00;
346         SkFixed fracY = SkScalarToFixed(SkScalarFraction(ty)) & 0x0000FF00;
347 
348 #ifdef SKIA_OHOS
349         builder[0] = SkFloat2Bits(roundf(sx * 100) / 100.f);
350         builder[1] = SkFloat2Bits(roundf(sy * 100) / 100.f);
351         builder[2] = SkFloat2Bits(roundf(kx * 100) / 100.f);
352         builder[3] = SkFloat2Bits(roundf(ky * 100) / 100.f);
353 #else
354         builder[0] = SkFloat2Bits(sx);
355         builder[1] = SkFloat2Bits(sy);
356         builder[2] = SkFloat2Bits(kx);
357         builder[3] = SkFloat2Bits(ky);
358 #endif // SKIA_OHOS
359         // Distinguish between hairline and filled paths. For hairlines, we also need to include
360         // the cap. (SW grows hairlines by 0.5 pixel with round and square caps). Note that
361         // stroke-and-fill of hairlines is turned into pure fill by SkStrokeRec, so this covers
362         // all cases we might see.
363         uint32_t styleBits = shape.style().isSimpleHairline()
364                                     ? ((shape.style().strokeRec().getCap() << 1) | 1)
365                                     : 0;
366         builder[4] = fracX | (fracY >> 8) | (styleBits << 16);
367 
368         SkMaskFilterBase::BlurRec rec;
369         SkAssertResult(as_MFB(maskFilter)->asABlur(&rec));
370 
371         builder[5] = rec.fStyle;  // TODO: we could put this with the other style bits
372 #ifdef SKIA_OHOS
373         builder[6] = SkFloat2Bits(roundf(rec.fSigma * 100) / 100.f);
374 #else
375         builder[6] = SkFloat2Bits(rec.fSigma);
376 #endif // SKIA_OHOS
377         shape.writeUnstyledKey(&builder[7]);
378     }
379 #endif
380 
381     return true;
382 }
383 
hw_create_filtered_mask(GrDirectContext * dContext,skgpu::v1::SurfaceDrawContext * sdc,const SkMatrix & viewMatrix,const GrStyledShape & shape,const SkMaskFilterBase * filter,const SkIRect & unclippedDevShapeBounds,const SkIRect & clipBounds,SkIRect * maskRect,GrUniqueKey * key)384 static GrSurfaceProxyView hw_create_filtered_mask(GrDirectContext* dContext,
385                                                   skgpu::v1::SurfaceDrawContext* sdc,
386                                                   const SkMatrix& viewMatrix,
387                                                   const GrStyledShape& shape,
388                                                   const SkMaskFilterBase* filter,
389                                                   const SkIRect& unclippedDevShapeBounds,
390                                                   const SkIRect& clipBounds,
391                                                   SkIRect* maskRect,
392                                                   GrUniqueKey* key) {
393     if (!filter->canFilterMaskGPU(shape,
394                                   unclippedDevShapeBounds,
395                                   clipBounds,
396                                   viewMatrix,
397                                   maskRect)) {
398         return {};
399     }
400 
401     if (clip_bounds_quick_reject(clipBounds, *maskRect)) {
402         // clipped out
403         return {};
404     }
405 
406     auto threadSafeCache = dContext->priv().threadSafeCache();
407 
408     GrSurfaceProxyView lazyView;
409     sk_sp<GrThreadSafeCache::Trampoline> trampoline;
410 
411     if (key->isValid()) {
412         // In this case, we want GPU-filtered masks to have priority over SW-generated ones so
413         // we pre-emptively add a lazy-view to the cache and fill it in later.
414         std::tie(lazyView, trampoline) = GrThreadSafeCache::CreateLazyView(
415                 dContext, GrColorType::kAlpha_8, maskRect->size(),
416                 kMaskOrigin, SkBackingFit::kApprox);
417         if (!lazyView) {
418             return {}; // fall back to a SW-created mask - 'create_mask_GPU' probably won't succeed
419         }
420 
421         key->setCustomData(create_data(*maskRect, unclippedDevShapeBounds));
422         auto [cachedView, data] = threadSafeCache->findOrAddWithData(*key, lazyView);
423         if (cachedView != lazyView) {
424             // In this case, the gpu-thread lost out to a recording thread - use its result.
425             SkASSERT(data);
426             SkASSERT(cachedView.asTextureProxy());
427             SkASSERT(cachedView.origin() == kMaskOrigin);
428 
429             *maskRect = extract_draw_rect_from_data(data.get(), unclippedDevShapeBounds);
430             return cachedView;
431         }
432     }
433 
434     std::unique_ptr<skgpu::v1::SurfaceDrawContext> maskSDC(create_mask_GPU(dContext,
435                                                                            *maskRect,
436                                                                            viewMatrix,
437                                                                            shape,
438                                                                            sdc->numSamples()));
439     if (!maskSDC) {
440         if (key->isValid()) {
441             // It is very unlikely that 'create_mask_GPU' will fail after 'CreateLazyView'
442             // succeeded but, if it does, remove the lazy-view from the cache and fallback to
443             // a SW-created mask. Note that any recording threads that glommed onto the
444             // lazy-view will have to, later, drop those draws.
445             threadSafeCache->remove(*key);
446         }
447         return {};
448     }
449 
450     auto filteredMaskView = filter->filterMaskGPU(dContext,
451                                                   maskSDC->readSurfaceView(),
452                                                   maskSDC->colorInfo().colorType(),
453                                                   maskSDC->colorInfo().alphaType(),
454                                                   viewMatrix,
455                                                   *maskRect);
456     if (!filteredMaskView) {
457         if (key->isValid()) {
458             // Remove the lazy-view from the cache and fallback to a SW-created mask. Note that
459             // any recording threads that glommed onto the lazy-view will have to, later, drop
460             // those draws.
461             threadSafeCache->remove(*key);
462         }
463         return {};
464     }
465 
466     if (key->isValid()) {
467         SkASSERT(filteredMaskView.dimensions() == lazyView.dimensions());
468         SkASSERT(filteredMaskView.swizzle() == lazyView.swizzle());
469         SkASSERT(filteredMaskView.origin() == lazyView.origin());
470 
471         trampoline->fProxy = filteredMaskView.asTextureProxyRef();
472         return lazyView;
473     }
474 
475     return filteredMaskView;
476 }
477 
draw_shape_with_mask_filter(GrRecordingContext * rContext,skgpu::v1::SurfaceDrawContext * sdc,const GrClip * clip,GrPaint && paint,const SkMatrix & viewMatrix,const SkMaskFilterBase * maskFilter,const GrStyledShape & origShape)478 static void draw_shape_with_mask_filter(GrRecordingContext* rContext,
479                                         skgpu::v1::SurfaceDrawContext* sdc,
480                                         const GrClip* clip,
481                                         GrPaint&& paint,
482                                         const SkMatrix& viewMatrix,
483                                         const SkMaskFilterBase* maskFilter,
484                                         const GrStyledShape& origShape) {
485     SkASSERT(maskFilter);
486 
487     const GrStyledShape* shape = &origShape;
488     SkTLazy<GrStyledShape> tmpShape;
489 
490     if (origShape.style().applies()) {
491         SkScalar styleScale =  GrStyle::MatrixToScaleFactor(viewMatrix);
492         if (styleScale == 0) {
493             return;
494         }
495 
496         tmpShape.init(origShape.applyStyle(GrStyle::Apply::kPathEffectAndStrokeRec, styleScale));
497         if (tmpShape->isEmpty()) {
498             return;
499         }
500 
501         shape = tmpShape.get();
502     }
503 
504 #ifdef SKIA_OHOS
505     SkIRect devSpaceShapeBounds;
506     if (get_unclipped_shape_dev_bounds(*shape, viewMatrix, &devSpaceShapeBounds) &&
507         maskFilter->quick_check_gpu_draw(viewMatrix, devSpaceShapeBounds)) {
508         SkRRect srcRRect;
509         bool inverted;
510         bool canUseSDFShadow = SDFBlur::GetSDFBlurEnabled() &&
511                                shape->asRRect(&srcRRect, nullptr, nullptr, &inverted) && !inverted &&
512                                (paint.numTotalFragmentProcessors() == 0);
513         if (canUseSDFShadow &&
514             maskFilter->directFilterRRectMaskGPU(rContext, sdc, std::move(paint), clip, viewMatrix, *shape, srcRRect)) {
515             return;
516         }
517     }
518     if (SDFBlur::GetSDFBlurDebugTraceEnabled()) {
519         HITRACE_OHOS_NAME_ALWAYS("directFilterRRectMaskGPU doSDF fail!");
520     }
521 #endif // SKIA_OHOS
522 
523     if (maskFilter->directFilterMaskGPU(rContext, sdc, std::move(paint), clip, viewMatrix, *shape)) {
524         // the mask filter was able to draw itself directly, so there's nothing
525         // left to do.
526         return;
527     }
528     assert_alive(paint);
529 
530     // If the path is hairline, ignore inverse fill.
531     bool inverseFilled = shape->inverseFilled() &&
532                          !GrIsStrokeHairlineOrEquivalent(shape->style(), viewMatrix, nullptr);
533 
534     SkIRect unclippedDevShapeBounds, devClipBounds;
535     if (!get_shape_and_clip_bounds(sdc, clip, *shape, viewMatrix,
536                                    &unclippedDevShapeBounds, &devClipBounds)) {
537         // TODO: just cons up an opaque mask here
538         if (!inverseFilled) {
539             return;
540         }
541     }
542 
543     GrUniqueKey maskKey;
544     SkIRect boundsForClip;
545     if (!compute_key_and_clip_bounds(&maskKey, &boundsForClip,
546                                      sdc->caps(),
547                                      viewMatrix, inverseFilled,
548                                      maskFilter, *shape,
549                                      unclippedDevShapeBounds,
550                                      devClipBounds)) {
551         return; // 'shape' was entirely clipped out
552     }
553 
554     GrSurfaceProxyView filteredMaskView;
555     SkIRect maskRect;
556 
557     if (auto dContext = rContext->asDirectContext()) {
558         filteredMaskView = hw_create_filtered_mask(dContext, sdc,
559                                                    viewMatrix, *shape, maskFilter,
560                                                    unclippedDevShapeBounds, boundsForClip,
561                                                    &maskRect, &maskKey);
562         if (filteredMaskView) {
563             if (draw_mask(sdc, clip, viewMatrix, maskRect, std::move(paint), std::move(filteredMaskView))) {
564                 // This path is completely drawn
565                 return;
566             }
567             assert_alive(paint);
568         }
569     }
570 
571     // Either HW mask rendering failed or we're in a DDL recording thread
572     filteredMaskView = sw_create_filtered_mask(rContext,
573                                                viewMatrix, *shape, maskFilter,
574                                                unclippedDevShapeBounds, boundsForClip,
575                                                &maskRect, &maskKey);
576     if (filteredMaskView) {
577         if (draw_mask(sdc, clip, viewMatrix, maskRect, std::move(paint), std::move(filteredMaskView))) {
578             return;
579         }
580         assert_alive(paint);
581     }
582 }
583 
drawShapeWithMaskFilter(GrRecordingContext * rContext,skgpu::v1::SurfaceDrawContext * sdc,const GrClip * clip,const GrStyledShape & shape,GrPaint && paint,const SkMatrix & viewMatrix,const SkMaskFilter * mf)584 void GrBlurUtils::drawShapeWithMaskFilter(GrRecordingContext* rContext,
585                                           skgpu::v1::SurfaceDrawContext* sdc,
586                                           const GrClip* clip,
587                                           const GrStyledShape& shape,
588                                           GrPaint&& paint,
589                                           const SkMatrix& viewMatrix,
590                                           const SkMaskFilter* mf) {
591     draw_shape_with_mask_filter(rContext, sdc, clip, std::move(paint),
592                                 viewMatrix, as_MFB(mf), shape);
593 }
594 
drawShapeWithMaskFilter(GrRecordingContext * rContext,skgpu::v1::SurfaceDrawContext * sdc,const GrClip * clip,const SkPaint & paint,const SkMatrixProvider & matrixProvider,const GrStyledShape & shape)595 void GrBlurUtils::drawShapeWithMaskFilter(GrRecordingContext* rContext,
596                                           skgpu::v1::SurfaceDrawContext* sdc,
597                                           const GrClip* clip,
598                                           const SkPaint& paint,
599                                           const SkMatrixProvider& matrixProvider,
600                                           const GrStyledShape& shape) {
601     if (rContext->abandoned()) {
602         return;
603     }
604 
605     GrPaint grPaint;
606     if (!SkPaintToGrPaint(rContext, sdc->colorInfo(), paint, matrixProvider, &grPaint)) {
607         return;
608     }
609 
610     const SkMatrix& viewMatrix(matrixProvider.localToDevice());
611     SkMaskFilterBase* mf = as_MFB(paint.getMaskFilter());
612     if (mf && !mf->hasFragmentProcessor()) {
613         // The MaskFilter wasn't already handled in SkPaintToGrPaint
614         draw_shape_with_mask_filter(rContext, sdc, clip, std::move(grPaint), viewMatrix, mf, shape);
615     } else {
616         sdc->drawShape(clip, std::move(grPaint), sdc->chooseAA(paint), viewMatrix,
617                        GrStyledShape(shape));
618     }
619 }
620 
621 #else // SK_GPU_V1
622 
drawShapeWithMaskFilter(GrRecordingContext *,skgpu::v1::SurfaceDrawContext *,const GrClip *,const GrStyledShape &,GrPaint &&,const SkMatrix & viewMatrix,const SkMaskFilter *)623 void GrBlurUtils::drawShapeWithMaskFilter(GrRecordingContext*,
624                                           skgpu::v1::SurfaceDrawContext*,
625                                           const GrClip*,
626                                           const GrStyledShape&,
627                                           GrPaint&&,
628                                           const SkMatrix& viewMatrix,
629                                           const SkMaskFilter*) {
630 }
631 
drawShapeWithMaskFilter(GrRecordingContext *,skgpu::v1::SurfaceDrawContext *,const GrClip *,const SkPaint &,const SkMatrixProvider &,const GrStyledShape &)632 void GrBlurUtils::drawShapeWithMaskFilter(GrRecordingContext*,
633                                           skgpu::v1::SurfaceDrawContext*,
634                                           const GrClip*,
635                                           const SkPaint&,
636                                           const SkMatrixProvider&,
637                                           const GrStyledShape&) {
638 }
639 
640 #endif // SK_GPU_V1
641