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