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/v1/SurfaceDrawContext_v1.h"
9 
10 #include "include/core/SkDrawable.h"
11 #include "include/core/SkLog.h"
12 #include "include/core/SkVertices.h"
13 #include "include/gpu/GrBackendSemaphore.h"
14 #include "include/gpu/GrDirectContext.h"
15 #include "include/gpu/GrRecordingContext.h"
16 #include "include/private/GrImageContext.h"
17 #include "include/private/SkShadowFlags.h"
18 #include "include/private/SkVx.h"
19 #include "include/utils/SkShadowUtils.h"
20 #include "src/core/SkAutoPixmapStorage.h"
21 #include "src/core/SkConvertPixels.h"
22 #include "src/core/SkDrawProcs.h"
23 #include "src/core/SkDrawShadowInfo.h"
24 #include "src/core/SkGlyphRunPainter.h"
25 #include "src/core/SkLatticeIter.h"
26 #include "src/core/SkMatrixPriv.h"
27 #include "src/core/SkMatrixProvider.h"
28 #include "src/core/SkRRectPriv.h"
29 #include "src/gpu/GrAppliedClip.h"
30 #include "src/gpu/GrAttachment.h"
31 #include "src/gpu/GrCaps.h"
32 #include "src/gpu/GrClip.h"
33 #include "src/gpu/GrColor.h"
34 #include "src/gpu/GrDataUtils.h"
35 #include "src/gpu/GrDirectContextPriv.h"
36 #include "src/gpu/GrDrawingManager.h"
37 #include "src/gpu/GrGpuResourcePriv.h"
38 #include "src/gpu/GrImageContextPriv.h"
39 #include "src/gpu/GrImageInfo.h"
40 #include "src/gpu/GrMemoryPool.h"
41 #include "src/gpu/GrProxyProvider.h"
42 #include "src/gpu/GrRenderTarget.h"
43 #include "src/gpu/GrResourceProvider.h"
44 #include "src/gpu/GrSemaphore.h"
45 #include "src/gpu/GrStencilSettings.h"
46 #include "src/gpu/GrStyle.h"
47 #include "src/gpu/GrTracing.h"
48 #include "src/gpu/SkGr.h"
49 #include "src/gpu/effects/GrBicubicEffect.h"
50 #include "src/gpu/effects/GrBlendFragmentProcessor.h"
51 #include "src/gpu/effects/GrDisableColorXP.h"
52 #include "src/gpu/effects/GrRRectEffect.h"
53 #include "src/gpu/effects/GrTextureEffect.h"
54 #include "src/gpu/geometry/GrQuad.h"
55 #include "src/gpu/geometry/GrQuadUtils.h"
56 #include "src/gpu/geometry/GrStyledShape.h"
57 #include "src/gpu/ops/BlurOp.h"
58 #include "src/gpu/ops/ClearOp.h"
59 #include "src/gpu/ops/DrawAtlasOp.h"
60 #include "src/gpu/ops/DrawVerticesOp.h"
61 #include "src/gpu/ops/DrawableOp.h"
62 #include "src/gpu/ops/FillRRectOp.h"
63 #include "src/gpu/ops/FillRectOp.h"
64 #include "src/gpu/ops/GrDrawOp.h"
65 #include "src/gpu/ops/GrOp.h"
66 #include "src/gpu/ops/GrOvalOpFactory.h"
67 #include "src/gpu/ops/LatticeOp.h"
68 #include "src/gpu/ops/RegionOp.h"
69 #include "src/gpu/ops/ShadowRRectOp.h"
70 #include "src/gpu/ops/StrokeRectOp.h"
71 #include "src/gpu/ops/TextureOp.h"
72 #include "src/gpu/text/GrSDFTControl.h"
73 #include "src/gpu/text/GrTextBlobCache.h"
74 #include "src/gpu/v1/PathRenderer.h"
75 
76 #define ASSERT_OWNED_RESOURCE(R) SkASSERT(!(R) || (R)->getContext() == this->drawingManager()->getContext())
77 #define ASSERT_SINGLE_OWNER        GR_ASSERT_SINGLE_OWNER(this->singleOwner())
78 #define RETURN_IF_ABANDONED        if (fContext->abandoned()) { return; }
79 #define RETURN_FALSE_IF_ABANDONED  if (fContext->abandoned()) { return false; }
80 
81 //////////////////////////////////////////////////////////////////////////////
82 
83 namespace {
84 
op_bounds(SkRect* bounds, const GrOp* op)85 void op_bounds(SkRect* bounds, const GrOp* op) {
86     *bounds = op->bounds();
87     if (op->hasZeroArea()) {
88         if (op->hasAABloat()) {
89             bounds->outset(0.5f, 0.5f);
90         } else {
91             // We don't know which way the particular GPU will snap lines or points at integer
92             // coords. So we ensure that the bounds is large enough for either snap.
93             SkRect before = *bounds;
94             bounds->roundOut(bounds);
95             if (bounds->fLeft == before.fLeft) {
96                 bounds->fLeft -= 1;
97             }
98             if (bounds->fTop == before.fTop) {
99                 bounds->fTop -= 1;
100             }
101             if (bounds->fRight == before.fRight) {
102                 bounds->fRight += 1;
103             }
104             if (bounds->fBottom == before.fBottom) {
105                 bounds->fBottom += 1;
106             }
107         }
108     }
109 }
110 
111 } // anonymous namespace
112 
113 namespace skgpu::v1 {
114 
115 using DoSimplify = GrStyledShape::DoSimplify;
116 
117 class AutoCheckFlush {
118 public:
AutoCheckFlush(GrDrawingManager* drawingManager)119     AutoCheckFlush(GrDrawingManager* drawingManager) : fDrawingManager(drawingManager) {
120         SkASSERT(fDrawingManager);
121     }
~AutoCheckFlush()122     ~AutoCheckFlush() { fDrawingManager->flushIfNecessary(); }
123 
124 private:
125     GrDrawingManager* fDrawingManager;
126 };
127 
Make(GrRecordingContext* rContext, GrColorType colorType, sk_sp<GrSurfaceProxy> proxy, sk_sp<SkColorSpace> colorSpace, GrSurfaceOrigin origin, const SkSurfaceProps& surfaceProps, bool flushTimeOpsTask)128 std::unique_ptr<SurfaceDrawContext> SurfaceDrawContext::Make(GrRecordingContext* rContext,
129                                                              GrColorType colorType,
130                                                              sk_sp<GrSurfaceProxy> proxy,
131                                                              sk_sp<SkColorSpace> colorSpace,
132                                                              GrSurfaceOrigin origin,
133                                                              const SkSurfaceProps& surfaceProps,
134                                                              bool flushTimeOpsTask) {
135     if (!rContext || !proxy || colorType == GrColorType::kUnknown) {
136         return nullptr;
137     }
138 
139     const GrBackendFormat& format = proxy->backendFormat();
140     GrSwizzle readSwizzle = rContext->priv().caps()->getReadSwizzle(format, colorType);
141     GrSwizzle writeSwizzle = rContext->priv().caps()->getWriteSwizzle(format, colorType);
142 
143     GrSurfaceProxyView readView (          proxy,  origin, readSwizzle);
144     GrSurfaceProxyView writeView(std::move(proxy), origin, writeSwizzle);
145 
146     return std::make_unique<SurfaceDrawContext>(rContext,
147                                                 std::move(readView),
148                                                 std::move(writeView),
149                                                 colorType,
150                                                 std::move(colorSpace),
151                                                 surfaceProps,
152                                                 flushTimeOpsTask);
153 }
154 
Make( GrRecordingContext* rContext, sk_sp<SkColorSpace> colorSpace, SkBackingFit fit, SkISize dimensions, const GrBackendFormat& format, int sampleCnt, GrMipmapped mipMapped, GrProtected isProtected, GrSwizzle readSwizzle, GrSwizzle writeSwizzle, GrSurfaceOrigin origin, SkBudgeted budgeted, const SkSurfaceProps& surfaceProps)155 std::unique_ptr<SurfaceDrawContext> SurfaceDrawContext::Make(
156         GrRecordingContext* rContext,
157         sk_sp<SkColorSpace> colorSpace,
158         SkBackingFit fit,
159         SkISize dimensions,
160         const GrBackendFormat& format,
161         int sampleCnt,
162         GrMipmapped mipMapped,
163         GrProtected isProtected,
164         GrSwizzle readSwizzle,
165         GrSwizzle writeSwizzle,
166         GrSurfaceOrigin origin,
167         SkBudgeted budgeted,
168         const SkSurfaceProps& surfaceProps) {
169     // It is probably not necessary to check if the context is abandoned here since uses of the
170     // SurfaceDrawContext which need the context will mostly likely fail later on without an
171     // issue. However having this hear adds some reassurance in case there is a path doesn't handle
172     // an abandoned context correctly. It also lets us early out of some extra work.
173     if (rContext->abandoned()) {
174         return nullptr;
175     }
176 
177     sk_sp<GrTextureProxy> proxy = rContext->priv().proxyProvider()->createProxy(
178             format,
179             dimensions,
180             GrRenderable::kYes,
181             sampleCnt,
182             mipMapped,
183             fit,
184             budgeted,
185             isProtected);
186     if (!proxy) {
187         return nullptr;
188     }
189 
190     GrSurfaceProxyView readView (           proxy, origin,  readSwizzle);
191     GrSurfaceProxyView writeView(std::move(proxy), origin, writeSwizzle);
192 
193     auto sdc = std::make_unique<SurfaceDrawContext>(rContext,
194                                                     std::move(readView),
195                                                     std::move(writeView),
196                                                     GrColorType::kUnknown,
197                                                     std::move(colorSpace),
198                                                     surfaceProps);
199     sdc->discard();
200     return sdc;
201 }
202 
Make( GrRecordingContext* rContext, GrColorType colorType, sk_sp<SkColorSpace> colorSpace, SkBackingFit fit, SkISize dimensions, const SkSurfaceProps& surfaceProps, int sampleCnt, GrMipmapped mipMapped, GrProtected isProtected, GrSurfaceOrigin origin, SkBudgeted budgeted)203 std::unique_ptr<SurfaceDrawContext> SurfaceDrawContext::Make(
204         GrRecordingContext* rContext,
205         GrColorType colorType,
206         sk_sp<SkColorSpace> colorSpace,
207         SkBackingFit fit,
208         SkISize dimensions,
209         const SkSurfaceProps& surfaceProps,
210         int sampleCnt,
211         GrMipmapped mipMapped,
212         GrProtected isProtected,
213         GrSurfaceOrigin origin,
214         SkBudgeted budgeted) {
215     if (!rContext) {
216         return nullptr;
217     }
218 
219     auto format = rContext->priv().caps()->getDefaultBackendFormat(colorType, GrRenderable::kYes);
220     if (!format.isValid()) {
221         return nullptr;
222     }
223     sk_sp<GrTextureProxy> proxy = rContext->priv().proxyProvider()->createProxy(format,
224                                                                                 dimensions,
225                                                                                 GrRenderable::kYes,
226                                                                                 sampleCnt,
227                                                                                 mipMapped,
228                                                                                 fit,
229                                                                                 budgeted,
230                                                                                 isProtected);
231     if (!proxy) {
232         return nullptr;
233     }
234 
235     return SurfaceDrawContext::Make(rContext,
236                                     colorType,
237                                     std::move(proxy),
238                                     std::move(colorSpace),
239                                     origin,
240                                     surfaceProps);
241 }
242 
MakeWithFallback( GrRecordingContext* rContext, GrColorType colorType, sk_sp<SkColorSpace> colorSpace, SkBackingFit fit, SkISize dimensions, const SkSurfaceProps& surfaceProps, int sampleCnt, GrMipmapped mipMapped, GrProtected isProtected, GrSurfaceOrigin origin, SkBudgeted budgeted)243 std::unique_ptr<SurfaceDrawContext> SurfaceDrawContext::MakeWithFallback(
244         GrRecordingContext* rContext,
245         GrColorType colorType,
246         sk_sp<SkColorSpace> colorSpace,
247         SkBackingFit fit,
248         SkISize dimensions,
249         const SkSurfaceProps& surfaceProps,
250         int sampleCnt,
251         GrMipmapped mipMapped,
252         GrProtected isProtected,
253         GrSurfaceOrigin origin,
254         SkBudgeted budgeted) {
255     const GrCaps* caps = rContext->priv().caps();
256     auto [ct, _] = caps->getFallbackColorTypeAndFormat(colorType, sampleCnt);
257     if (ct == GrColorType::kUnknown) {
258         return nullptr;
259     }
260     return SurfaceDrawContext::Make(rContext, ct, colorSpace, fit, dimensions, surfaceProps,
261                                     sampleCnt, mipMapped, isProtected, origin, budgeted);
262 }
263 
MakeFromBackendTexture( GrRecordingContext* rContext, GrColorType colorType, sk_sp<SkColorSpace> colorSpace, const GrBackendTexture& tex, int sampleCnt, GrSurfaceOrigin origin, const SkSurfaceProps& surfaceProps, sk_sp<GrRefCntedCallback> releaseHelper)264 std::unique_ptr<SurfaceDrawContext> SurfaceDrawContext::MakeFromBackendTexture(
265         GrRecordingContext* rContext,
266         GrColorType colorType,
267         sk_sp<SkColorSpace> colorSpace,
268         const GrBackendTexture& tex,
269         int sampleCnt,
270         GrSurfaceOrigin origin,
271         const SkSurfaceProps& surfaceProps,
272         sk_sp<GrRefCntedCallback> releaseHelper) {
273     SkASSERT(sampleCnt > 0);
274     sk_sp<GrTextureProxy> proxy(rContext->priv().proxyProvider()->wrapRenderableBackendTexture(
275             tex, sampleCnt, kBorrow_GrWrapOwnership, GrWrapCacheable::kNo,
276             std::move(releaseHelper)));
277     if (!proxy) {
278         return nullptr;
279     }
280 
281     return SurfaceDrawContext::Make(rContext, colorType, std::move(proxy), std::move(colorSpace),
282                                     origin, surfaceProps);
283 }
284 
285 // In MDB mode the reffing of the 'getLastOpsTask' call's result allows in-progress
286 // OpsTask to be picked up and added to by SurfaceDrawContexts lower in the call
287 // stack. When this occurs with a closed OpsTask, a new one will be allocated
288 // when the surfaceDrawContext attempts to use it (via getOpsTask).
SurfaceDrawContext(GrRecordingContext* rContext, GrSurfaceProxyView readView, GrSurfaceProxyView writeView, GrColorType colorType, sk_sp<SkColorSpace> colorSpace, const SkSurfaceProps& surfaceProps, bool flushTimeOpsTask)289 SurfaceDrawContext::SurfaceDrawContext(GrRecordingContext* rContext,
290                                        GrSurfaceProxyView readView,
291                                        GrSurfaceProxyView writeView,
292                                        GrColorType colorType,
293                                        sk_sp<SkColorSpace> colorSpace,
294                                        const SkSurfaceProps& surfaceProps,
295                                        bool flushTimeOpsTask)
296         : SurfaceFillContext(rContext,
297                              std::move(readView),
298                              std::move(writeView),
299                              {colorType, kPremul_SkAlphaType, std::move(colorSpace)},
300                              flushTimeOpsTask)
301         , fSurfaceProps(surfaceProps)
302         , fCanUseDynamicMSAA(
303                 (fSurfaceProps.flags() & SkSurfaceProps::kDynamicMSAA_Flag) &&
304                 rContext->priv().caps()->supportsDynamicMSAA(this->asRenderTargetProxy()))
305         , fGlyphPainter(*this) {
306     SkDEBUGCODE(this->validate();)
307 }
308 
~SurfaceDrawContext()309 SurfaceDrawContext::~SurfaceDrawContext() {
310     ASSERT_SINGLE_OWNER
311 }
312 
willReplaceOpsTask(OpsTask* prevTask, OpsTask* nextTask)313 void SurfaceDrawContext::willReplaceOpsTask(OpsTask* prevTask, OpsTask* nextTask) {
314     if (prevTask && fNeedsStencil) {
315         // Store the stencil values in memory upon completion of fOpsTask.
316         prevTask->setMustPreserveStencil();
317         // Reload the stencil buffer content at the beginning of newOpsTask.
318         // FIXME: Could the topo sort insert a task between these two that modifies the stencil
319         // values?
320         nextTask->setInitialStencilContent(OpsTask::StencilContent::kPreserved);
321     }
322 #if GR_GPU_STATS && GR_TEST_UTILS
323     if (fCanUseDynamicMSAA) {
324         fContext->priv().dmsaaStats().fNumRenderPasses++;
325     }
326 #endif
327 }
328 
drawGlyphRunListNoCache(const GrClip* clip, const SkMatrixProvider& viewMatrix, const SkGlyphRunList& glyphRunList, const SkPaint& paint)329 void SurfaceDrawContext::drawGlyphRunListNoCache(const GrClip* clip,
330                                                  const SkMatrixProvider& viewMatrix,
331                                                  const SkGlyphRunList& glyphRunList,
332                                                  const SkPaint& paint) {
333     GrSDFTControl control =
334             fContext->priv().getSDFTControl(fSurfaceProps.isUseDeviceIndependentFonts());
335     const SkPoint drawOrigin = glyphRunList.origin();
336     SkMatrix drawMatrix = viewMatrix.localToDevice();
337     drawMatrix.preTranslate(drawOrigin.x(), drawOrigin.y());
338     GrSubRunAllocator* const alloc = this->subRunAlloc();
339 
340     GrSubRunNoCachePainter painter{this, alloc, clip, viewMatrix, glyphRunList, paint};
341     for (auto& glyphRun : glyphRunList) {
342         // Make and add the text ops.
343         fGlyphPainter.processGlyphRun(glyphRun,
344                                       drawMatrix,
345                                       paint,
346                                       control,
347                                       &painter);
348     }
349 }
350 
drawGlyphRunListWithCache(const GrClip* clip, const SkMatrixProvider& viewMatrix, const SkGlyphRunList& glyphRunList, const SkPaint& paint)351 void SurfaceDrawContext::drawGlyphRunListWithCache(const GrClip* clip,
352                                                    const SkMatrixProvider& viewMatrix,
353                                                    const SkGlyphRunList& glyphRunList,
354                                                    const SkPaint& paint) {
355     SkMatrix drawMatrix(viewMatrix.localToDevice());
356     drawMatrix.preTranslate(glyphRunList.origin().x(), glyphRunList.origin().y());
357 
358     GrSDFTControl control =
359             this->recordingContext()->priv().getSDFTControl(
360                     this->surfaceProps().isUseDeviceIndependentFonts());
361 
362     auto [canCache, key] = GrTextBlob::Key::Make(glyphRunList,
363                                                  paint,
364                                                  fSurfaceProps,
365                                                  this->colorInfo(),
366                                                  drawMatrix,
367                                                  control);
368 
369     sk_sp<GrTextBlob> blob;
370     GrTextBlobCache* textBlobCache = fContext->priv().getTextBlobCache();
371     if (canCache) {
372         blob = textBlobCache->find(key);
373     }
374 
375     if (blob == nullptr || !blob->canReuse(paint, drawMatrix)) {
376         if (blob != nullptr) {
377             // We have to remake the blob because changes may invalidate our masks.
378             // TODO we could probably get away with reuse most of the time if the pointer is unique,
379             //      but we'd have to clear the SubRun information
380             textBlobCache->remove(blob.get());
381         }
382 
383         blob = GrTextBlob::Make(glyphRunList, paint, drawMatrix, control, &fGlyphPainter);
384 
385         if (canCache) {
386             blob->addKey(key);
387             // The blob may already have been created on a different thread. Use the first one
388             // that was there.
389             blob = textBlobCache->addOrReturnExisting(glyphRunList, blob);
390         }
391     }
392 
393     for (const GrSubRun& subRun : blob->subRunList()) {
394         subRun.draw(clip, viewMatrix, glyphRunList, paint, this);
395     }
396 }
397 
398 // choose to use the GrTextBlob cache or not.
399 bool gGrDrawTextNoCache = false;
drawGlyphRunList(const GrClip* clip, const SkMatrixProvider& viewMatrix, const SkGlyphRunList& glyphRunList, const SkPaint& paint)400 void SurfaceDrawContext::drawGlyphRunList(const GrClip* clip,
401                                           const SkMatrixProvider& viewMatrix,
402                                           const SkGlyphRunList& glyphRunList,
403                                           const SkPaint& paint) {
404     ASSERT_SINGLE_OWNER
405     RETURN_IF_ABANDONED
406     SkDEBUGCODE(this->validate();)
407     GR_CREATE_TRACE_MARKER_CONTEXT("SurfaceDrawContext", "drawGlyphRunList", fContext);
408 
409     // Drawing text can cause us to do inline uploads. This is not supported for wrapped vulkan
410     // secondary command buffers because it would require stopping and starting a render pass which
411     // we don't have access to.
412     if (this->wrapsVkSecondaryCB()) {
413         return;
414     }
415 
416     if (gGrDrawTextNoCache || glyphRunList.blob() == nullptr) {
417         // If the glyphRunList does not have an associated text blob, then it was created by one of
418         // the direct draw APIs (drawGlyphs, etc.). There is no need to create a GrTextBlob just
419         // build the sub run directly and place it in the op.
420         this->drawGlyphRunListNoCache(clip, viewMatrix, glyphRunList, paint);
421     } else {
422         this->drawGlyphRunListWithCache(clip, viewMatrix, glyphRunList, paint);
423     }
424 }
425 
drawPaint(const GrClip* clip, GrPaint&& paint, const SkMatrix& viewMatrix)426 void SurfaceDrawContext::drawPaint(const GrClip* clip,
427                                    GrPaint&& paint,
428                                    const SkMatrix& viewMatrix) {
429     // Start with the render target, since that is the maximum content we could possibly fill.
430     // drawFilledQuad() will automatically restrict it to clip bounds for us if possible.
431     if (!paint.numTotalFragmentProcessors()) {
432         // The paint is trivial so we won't need to use local coordinates, so skip calculating the
433         // inverse view matrix.
434         SkRect r = this->asSurfaceProxy()->getBoundsRect();
435         this->fillRectToRect(clip, std::move(paint), GrAA::kNo, SkMatrix::I(), r, r);
436     } else {
437         // Use the inverse view matrix to arrive at appropriate local coordinates for the paint.
438         SkMatrix localMatrix;
439         if (!viewMatrix.invert(&localMatrix)) {
440             return;
441         }
442         SkIRect bounds = SkIRect::MakeSize(this->asSurfaceProxy()->dimensions());
443         this->fillPixelsWithLocalMatrix(clip, std::move(paint), bounds, localMatrix);
444     }
445 }
446 
447 enum class SurfaceDrawContext::QuadOptimization {
448     // The rect to draw doesn't intersect clip or render target, so no draw op should be added
449     kDiscarded,
450     // The rect to draw was converted to some other op and appended to the oplist, so no additional
451     // op is necessary. Currently this can convert it to a clear op or a rrect op. Only valid if
452     // a constColor is provided.
453     kSubmitted,
454     // The clip was folded into the device quad, with updated edge flags and local coords, and
455     // caller is responsible for adding an appropriate op.
456     kClipApplied,
457     // No change to clip, but quad updated to better fit clip/render target, and caller is
458     // responsible for adding an appropriate op.
459     kCropped
460 };
461 
attemptQuadOptimization( const GrClip* clip, const GrUserStencilSettings* stencilSettings, GrAA* aa, DrawQuad* quad, GrPaint* paint)462 SurfaceDrawContext::QuadOptimization SurfaceDrawContext::attemptQuadOptimization(
463         const GrClip* clip, const GrUserStencilSettings* stencilSettings, GrAA* aa, DrawQuad* quad,
464         GrPaint* paint) {
465     // Optimization requirements:
466     // 1. kDiscard applies when clip bounds and quad bounds do not intersect
467     // 2a. kSubmitted applies when constColor and final geom is pixel aligned rect;
468     //       pixel aligned rect requires rect clip and (rect quad or quad covers clip) OR
469     // 2b. kSubmitted applies when constColor and rrect clip and quad covers clip
470     // 4. kClipApplied applies when rect clip and (rect quad or quad covers clip)
471     // 5. kCropped in all other scenarios (although a crop may be a no-op)
472     const SkPMColor4f* constColor = nullptr;
473     SkPMColor4f paintColor;
474     if (!stencilSettings && paint && !paint->hasCoverageFragmentProcessor() &&
475         paint->isConstantBlendedColor(&paintColor)) {
476         // Only consider clears/rrects when it's easy to guarantee 100% fill with single color
477         constColor = &paintColor;
478     }
479 
480     // Save the old AA flags since CropToRect will modify 'quad' and if kCropped is returned, it's
481     // better to just keep the old flags instead of introducing mixed edge flags.
482     GrQuadAAFlags oldFlags = quad->fEdgeFlags;
483 
484     // Use the logical size of the render target, which allows for "fullscreen" clears even if
485     // the render target has an approximate backing fit
486     SkRect rtRect = this->asSurfaceProxy()->getBoundsRect();
487 
488     // For historical reasons, we assume AA for exact bounds checking in IsOutsideClip.
489     // TODO(michaelludwig) - Hopefully that can be revisited when the clipping optimizations are
490     // refactored to work better with round rects and dmsaa.
491     SkRect drawBounds = quad->fDevice.bounds();
492     if (!quad->fDevice.isFinite() || drawBounds.isEmpty() ||
493         GrClip::IsOutsideClip(SkIRect::MakeSize(this->dimensions()), drawBounds, GrAA::kYes)) {
494         return QuadOptimization::kDiscarded;
495     } else if (GrQuadUtils::WillUseHairline(quad->fDevice, GrAAType::kCoverage, quad->fEdgeFlags)) {
496         // Don't try to apply the clip early if we know rendering will use hairline methods, as this
497         // has an effect on the op bounds not otherwise taken into account in this function.
498         return QuadOptimization::kCropped;
499     }
500 
501     auto conservativeCrop = [&]() {
502         static constexpr int kLargeDrawLimit = 15000;
503         // Crop the quad to the render target. This doesn't change the visual results of drawing but
504         // is meant to help numerical stability for excessively large draws.
505         if (drawBounds.width() > kLargeDrawLimit || drawBounds.height() > kLargeDrawLimit) {
506             GrQuadUtils::CropToRect(rtRect, *aa, quad, /* compute local */ !constColor);
507         }
508     };
509 
510     bool simpleColor = !stencilSettings && constColor;
511     GrClip::PreClipResult result = clip ? clip->preApply(drawBounds, *aa)
512                                         : GrClip::PreClipResult(GrClip::Effect::kUnclipped);
513     switch(result.fEffect) {
514         case GrClip::Effect::kClippedOut:
515             return QuadOptimization::kDiscarded;
516         case GrClip::Effect::kUnclipped:
517             if (!simpleColor) {
518                 conservativeCrop();
519                 return QuadOptimization::kClipApplied;
520             } else {
521                 // Update result to store the render target bounds in order and then fall
522                 // through to attempt the draw->native clear optimization
523                 result = GrClip::PreClipResult(SkRRect::MakeRect(rtRect), *aa);
524             }
525             break;
526         case GrClip::Effect::kClipped:
527             if (!result.fIsRRect || (stencilSettings && result.fAA != *aa) ||
528                 (!result.fRRect.isRect() && !simpleColor)) {
529                 // The clip and draw state are too complicated to try and reduce
530                 conservativeCrop();
531                 return QuadOptimization::kCropped;
532             } // Else fall through to attempt to combine the draw and clip geometry together
533             break;
534         default:
535             SkUNREACHABLE;
536     }
537 
538     // If we reached here, we know we're an axis-aligned clip that is either a rect or a round rect,
539     // so we can potentially combine it with the draw geometry so that no clipping is needed.
540     SkASSERT(result.fEffect == GrClip::Effect::kClipped && result.fIsRRect);
541     SkRect clippedBounds = result.fRRect.getBounds();
542     clippedBounds.intersect(rtRect);
543     if (!drawBounds.intersect(clippedBounds)) {
544         // Our fractional bounds aren't actually inside the clip. GrClip::preApply() can sometimes
545         // think in terms of rounded-out bounds. Discard the draw.
546         return QuadOptimization::kDiscarded;
547     }
548     // Guard against the clipped draw turning into a hairline draw after intersection
549     if (drawBounds.width() < 1.f || drawBounds.height() < 1.f) {
550         return QuadOptimization::kCropped;
551     }
552 
553     if (result.fRRect.isRect()) {
554         // No rounded corners, so we might be able to become a native clear or we might be able to
555         // modify geometry and edge flags to represent intersected shape of clip and draw.
556         if (GrQuadUtils::CropToRect(clippedBounds, result.fAA, quad,
557                                     /*compute local*/ !constColor)) {
558             if (simpleColor && quad->fDevice.quadType() == GrQuad::Type::kAxisAligned) {
559                 // Clear optimization is possible
560                 drawBounds = quad->fDevice.bounds();
561                 if (drawBounds.contains(rtRect)) {
562                     // Fullscreen clear
563                     this->clear(*constColor);
564                     return QuadOptimization::kSubmitted;
565                 } else if (GrClip::IsPixelAligned(drawBounds) &&
566                            drawBounds.width() > 256 && drawBounds.height() > 256) {
567                     // Scissor + clear (round shouldn't do anything since we are pixel aligned)
568                     SkIRect scissorRect;
569                     drawBounds.round(&scissorRect);
570                     this->clear(scissorRect, *constColor);
571                     return QuadOptimization::kSubmitted;
572                 }
573             }
574 
575             // else the draw and clip were combined so just update the AA to reflect combination
576             if (*aa == GrAA::kNo && result.fAA == GrAA::kYes &&
577                 quad->fEdgeFlags != GrQuadAAFlags::kNone) {
578                 // The clip was anti-aliased and now the draw needs to be upgraded to AA to
579                 // properly reflect the smooth edge of the clip.
580                 *aa = GrAA::kYes;
581             }
582             // We intentionally do not downgrade AA here because we don't know if we need to
583             // preserve MSAA (see GrQuadAAFlags docs). But later in the pipeline, the ops can
584             // use GrResolveAATypeForQuad() to turn off coverage AA when all flags are off.
585             // deviceQuad is exactly the intersection of original quad and clip, so it can be
586             // drawn with no clip (submitted by caller)
587             return QuadOptimization::kClipApplied;
588         }
589     } else {
590         // Rounded corners and constant filled color (limit ourselves to solid colors because
591         // there is no way to use custom local coordinates with drawRRect).
592         SkASSERT(simpleColor);
593         if (GrQuadUtils::CropToRect(clippedBounds, result.fAA, quad,
594                                     /* compute local */ false) &&
595             quad->fDevice.quadType() == GrQuad::Type::kAxisAligned &&
596             quad->fDevice.bounds().contains(clippedBounds)) {
597             // Since the cropped quad became a rectangle which covered the bounds of the rrect,
598             // we can draw the rrect directly and ignore the edge flags
599             this->drawRRect(nullptr, std::move(*paint), result.fAA, SkMatrix::I(), result.fRRect,
600                             GrStyle::SimpleFill());
601             return QuadOptimization::kSubmitted;
602         }
603     }
604 
605     // The quads have been updated to better fit the clip bounds, but can't get rid of
606     // the clip entirely
607     quad->fEdgeFlags = oldFlags;
608     return QuadOptimization::kCropped;
609 }
610 
drawFilledQuad(const GrClip* clip, GrPaint&& paint, GrAA aa, DrawQuad* quad, const GrUserStencilSettings* ss)611 void SurfaceDrawContext::drawFilledQuad(const GrClip* clip,
612                                         GrPaint&& paint,
613                                         GrAA aa,
614                                         DrawQuad* quad,
615                                         const GrUserStencilSettings* ss) {
616     ASSERT_SINGLE_OWNER
617     RETURN_IF_ABANDONED
618     SkDEBUGCODE(this->validate();)
619     GR_CREATE_TRACE_MARKER_CONTEXT("SurfaceDrawContext", "drawFilledQuad", fContext);
620 
621     AutoCheckFlush acf(this->drawingManager());
622 
623     QuadOptimization opt = this->attemptQuadOptimization(clip, ss, &aa, quad, &paint);
624     if (opt >= QuadOptimization::kClipApplied) {
625         // These optimizations require caller to add an op themselves
626         const GrClip* finalClip = opt == QuadOptimization::kClipApplied ? nullptr : clip;
627         GrAAType aaType;
628         if (ss) {
629             aaType = (aa == GrAA::kYes) ? GrAAType::kMSAA : GrAAType::kNone;
630         } else if (fCanUseDynamicMSAA && aa == GrAA::kNo) {
631             // The SkGpuDevice ensures GrAA is always kYes when using dmsaa. If the caller calls
632             // into here with GrAA::kNo, trust that they know what they're doing and that the
633             // rendering will be equal with or without msaa.
634             aaType = GrAAType::kNone;
635         } else {
636             aaType = this->chooseAAType(aa);
637         }
638         this->addDrawOp(finalClip, FillRectOp::Make(fContext, std::move(paint), aaType,
639                                                     quad, ss));
640     }
641     // All other optimization levels were completely handled inside attempt(), so no extra op needed
642 }
643 
drawTexture(const GrClip* clip, GrSurfaceProxyView view, SkAlphaType srcAlphaType, GrSamplerState::Filter filter, GrSamplerState::MipmapMode mm, SkBlendMode blendMode, const SkPMColor4f& color, const SkRect& srcRect, const SkRect& dstRect, GrAA aa, GrQuadAAFlags edgeAA, SkCanvas::SrcRectConstraint constraint, const SkMatrix& viewMatrix, sk_sp<GrColorSpaceXform> colorSpaceXform)644 void SurfaceDrawContext::drawTexture(const GrClip* clip,
645                                      GrSurfaceProxyView view,
646                                      SkAlphaType srcAlphaType,
647                                      GrSamplerState::Filter filter,
648                                      GrSamplerState::MipmapMode mm,
649                                      SkBlendMode blendMode,
650                                      const SkPMColor4f& color,
651                                      const SkRect& srcRect,
652                                      const SkRect& dstRect,
653                                      GrAA aa,
654                                      GrQuadAAFlags edgeAA,
655                                      SkCanvas::SrcRectConstraint constraint,
656                                      const SkMatrix& viewMatrix,
657                                      sk_sp<GrColorSpaceXform> colorSpaceXform) {
658     // If we are using dmsaa then go through FillRRectOp (via fillRectToRect).
659     if ((this->alwaysAntialias() || this->caps()->reducedShaderMode()) && aa == GrAA::kYes) {
660         GrPaint paint;
661         paint.setColor4f(color);
662         std::unique_ptr<GrFragmentProcessor> fp;
663         if (constraint == SkCanvas::kStrict_SrcRectConstraint) {
664             fp = GrTextureEffect::MakeSubset(view, srcAlphaType, SkMatrix::I(),
665                                              GrSamplerState(filter, mm), srcRect,
666                                              *this->caps());
667         } else {
668             fp = GrTextureEffect::Make(view, srcAlphaType, SkMatrix::I(), filter, mm);
669         }
670         if (colorSpaceXform) {
671             fp = GrColorSpaceXformEffect::Make(std::move(fp), std::move(colorSpaceXform));
672         }
673         fp = GrBlendFragmentProcessor::Make(std::move(fp), nullptr, SkBlendMode::kModulate);
674         paint.setColorFragmentProcessor(std::move(fp));
675         if (blendMode != SkBlendMode::kSrcOver) {
676             paint.setXPFactory(SkBlendMode_AsXPFactory(blendMode));
677         }
678         this->fillRectToRect(clip, std::move(paint), GrAA::kYes, viewMatrix, dstRect, srcRect);
679         return;
680     }
681 
682     const SkRect* subset = constraint == SkCanvas::kStrict_SrcRectConstraint ?
683             &srcRect : nullptr;
684     DrawQuad quad{GrQuad::MakeFromRect(dstRect, viewMatrix), GrQuad(srcRect), edgeAA};
685 
686     this->drawTexturedQuad(clip, std::move(view), srcAlphaType, std::move(colorSpaceXform), filter,
687                            mm, color, blendMode, aa, &quad, subset);
688 }
689 
drawTexturedQuad(const GrClip* clip, GrSurfaceProxyView proxyView, SkAlphaType srcAlphaType, sk_sp<GrColorSpaceXform> textureXform, GrSamplerState::Filter filter, GrSamplerState::MipmapMode mm, const SkPMColor4f& color, SkBlendMode blendMode, GrAA aa, DrawQuad* quad, const SkRect* subset)690 void SurfaceDrawContext::drawTexturedQuad(const GrClip* clip,
691                                           GrSurfaceProxyView proxyView,
692                                           SkAlphaType srcAlphaType,
693                                           sk_sp<GrColorSpaceXform> textureXform,
694                                           GrSamplerState::Filter filter,
695                                           GrSamplerState::MipmapMode mm,
696                                           const SkPMColor4f& color,
697                                           SkBlendMode blendMode,
698                                           GrAA aa,
699                                           DrawQuad* quad,
700                                           const SkRect* subset) {
701     ASSERT_SINGLE_OWNER
702     RETURN_IF_ABANDONED
703     SkDEBUGCODE(this->validate();)
704     SkASSERT(proxyView.asTextureProxy());
705     GR_CREATE_TRACE_MARKER_CONTEXT("SurfaceDrawContext", "drawTexturedQuad", fContext);
706 
707     AutoCheckFlush acf(this->drawingManager());
708 
709     // Functionally this is very similar to drawFilledQuad except that there's no constColor to
710     // enable the kSubmitted optimizations, no stencil settings support, and its a TextureOp.
711     QuadOptimization opt = this->attemptQuadOptimization(clip, nullptr/*stencil*/, &aa, quad,
712                                                          nullptr/*paint*/);
713 
714     SkASSERT(opt != QuadOptimization::kSubmitted);
715     if (opt != QuadOptimization::kDiscarded) {
716         // And the texture op if not discarded
717         const GrClip* finalClip = opt == QuadOptimization::kClipApplied ? nullptr : clip;
718         GrAAType aaType = this->chooseAAType(aa);
719         auto clampType = GrColorTypeClampType(this->colorInfo().colorType());
720         auto saturate = clampType == GrClampType::kManual ? TextureOp::Saturate::kYes
721                                                           : TextureOp::Saturate::kNo;
722         // Use the provided subset, although hypothetically we could detect that the cropped local
723         // quad is sufficiently inside the subset and the constraint could be dropped.
724         this->addDrawOp(finalClip,
725                         TextureOp::Make(fContext, std::move(proxyView), srcAlphaType,
726                                         std::move(textureXform), filter, mm, color, saturate,
727                                         blendMode, aaType, quad, subset));
728     }
729 }
730 
drawRect(const GrClip* clip, GrPaint&& paint, GrAA aa, const SkMatrix& viewMatrix, const SkRect& rect, const GrStyle* style)731 void SurfaceDrawContext::drawRect(const GrClip* clip,
732                                   GrPaint&& paint,
733                                   GrAA aa,
734                                   const SkMatrix& viewMatrix,
735                                   const SkRect& rect,
736                                   const GrStyle* style) {
737     if (!style) {
738         style = &GrStyle::SimpleFill();
739     }
740     ASSERT_SINGLE_OWNER
741     RETURN_IF_ABANDONED
742     SkDEBUGCODE(this->validate();)
743     GR_CREATE_TRACE_MARKER_CONTEXT("SurfaceDrawContext", "drawRect", fContext);
744 
745     // Path effects should've been devolved to a path in SkGpuDevice
746     SkASSERT(!style->pathEffect());
747 
748     AutoCheckFlush acf(this->drawingManager());
749 
750     const SkStrokeRec& stroke = style->strokeRec();
751     if (stroke.getStyle() == SkStrokeRec::kFill_Style) {
752         // Fills the rect, using rect as its own local coordinates
753         this->fillRectToRect(clip, std::move(paint), aa, viewMatrix, rect, rect);
754         return;
755     } else if ((stroke.getStyle() == SkStrokeRec::kStroke_Style ||
756                 stroke.getStyle() == SkStrokeRec::kHairline_Style) &&
757                rect.width()                                        &&
758                rect.height()                                       &&
759                !this->caps()->reducedShaderMode()) {
760         // Only use the StrokeRectOp for non-empty rectangles. Empty rectangles will be processed by
761         // GrStyledShape to handle stroke caps and dashing properly.
762         //
763         // http://skbug.com/12206 -- there is a double-blend issue with the bevel version of
764         // AAStrokeRectOp, and if we increase the AA bloat for MSAA it becomes more pronounced.
765         // Don't use the bevel version with DMSAA.
766         GrAAType aaType = (fCanUseDynamicMSAA &&
767                            stroke.getJoin() == SkPaint::kMiter_Join &&
768                            stroke.getMiter() >= SK_ScalarSqrt2) ? GrAAType::kCoverage
769                                                                 : this->chooseAAType(aa);
770         GrOp::Owner op = StrokeRectOp::Make(fContext, std::move(paint), aaType, viewMatrix,
771                                             rect, stroke);
772         // op may be null if the stroke is not supported or if using coverage aa and the view matrix
773         // does not preserve rectangles.
774         if (op) {
775             this->addDrawOp(clip, std::move(op));
776             return;
777         }
778     }
779     assert_alive(paint);
780     this->drawShapeUsingPathRenderer(clip, std::move(paint), aa, viewMatrix,
781                                      GrStyledShape(rect, *style, DoSimplify::kNo));
782 }
783 
fillRectToRect(const GrClip* clip, GrPaint&& paint, GrAA aa, const SkMatrix& viewMatrix, const SkRect& rectToDraw, const SkRect& localRect)784 void SurfaceDrawContext::fillRectToRect(const GrClip* clip,
785                                         GrPaint&& paint,
786                                         GrAA aa,
787                                         const SkMatrix& viewMatrix,
788                                         const SkRect& rectToDraw,
789                                         const SkRect& localRect) {
790     DrawQuad quad{GrQuad::MakeFromRect(rectToDraw, viewMatrix), GrQuad(localRect),
791                   aa == GrAA::kYes ? GrQuadAAFlags::kAll : GrQuadAAFlags::kNone};
792 
793     // If we are using dmsaa then attempt to draw the rect with FillRRectOp.
794     if ((fContext->priv().caps()->reducedShaderMode() || this->alwaysAntialias()) &&
795         this->caps()->drawInstancedSupport()                                      &&
796         aa == GrAA::kYes) {  // If aa is kNo when using dmsaa, the rect is axis aligned. Don't use
797                              // FillRRectOp because it might require dual source blending.
798                              // http://skbug.com/11756
799         QuadOptimization opt = this->attemptQuadOptimization(clip, nullptr/*stencil*/, &aa, &quad,
800                                                              &paint);
801         if (opt < QuadOptimization::kClipApplied) {
802             // The optimization was completely handled inside attempt().
803             return;
804         }
805 
806         SkRect croppedRect, croppedLocal{};
807         const GrClip* optimizedClip = clip;
808         if (clip && viewMatrix.isScaleTranslate() && quad.fDevice.asRect(&croppedRect) &&
809             (!paint.usesLocalCoords() || quad.fLocal.asRect(&croppedLocal))) {
810             // The cropped quad is still a rect, and our view matrix preserves rects. Map it back
811             // to pre-matrix space.
812             SkMatrix inverse;
813             if (!viewMatrix.invert(&inverse)) {
814                 return;
815             }
816             SkASSERT(inverse.rectStaysRect());
817             inverse.mapRect(&croppedRect);
818             if (opt == QuadOptimization::kClipApplied) {
819                 optimizedClip = nullptr;
820             }
821         } else {
822             // Even if attemptQuadOptimization gave us an optimized quad, FillRRectOp needs a rect
823             // in pre-matrix space, so use the original rect. Also preserve the original clip.
824             croppedRect = rectToDraw;
825             croppedLocal = localRect;
826         }
827 
828         if (auto op = FillRRectOp::Make(fContext, this->arenaAlloc(), std::move(paint),
829                                         viewMatrix, SkRRect::MakeRect(croppedRect), croppedLocal,
830                                         GrAA::kYes)) {
831             this->addDrawOp(optimizedClip, std::move(op));
832             return;
833         }
834     }
835 
836     assert_alive(paint);
837     this->drawFilledQuad(clip, std::move(paint), aa, &quad);
838 }
839 
drawQuadSet(const GrClip* clip, GrPaint&& paint, GrAA aa, const SkMatrix& viewMatrix, const GrQuadSetEntry quads[], int cnt)840 void SurfaceDrawContext::drawQuadSet(const GrClip* clip,
841                                      GrPaint&& paint,
842                                      GrAA aa,
843                                      const SkMatrix& viewMatrix,
844                                      const GrQuadSetEntry quads[],
845                                      int cnt) {
846     GrAAType aaType = this->chooseAAType(aa);
847 
848     FillRectOp::AddFillRectOps(this, clip, fContext, std::move(paint), aaType, viewMatrix,
849                                quads, cnt);
850 }
851 
maxWindowRectangles() const852 int SurfaceDrawContext::maxWindowRectangles() const {
853     return this->asRenderTargetProxy()->maxWindowRectangles(*this->caps());
854 }
855 
canDiscardPreviousOpsOnFullClear() const856 OpsTask::CanDiscardPreviousOps SurfaceDrawContext::canDiscardPreviousOpsOnFullClear() const {
857 #if GR_TEST_UTILS
858     if (fPreserveOpsOnFullClear_TestingOnly) {
859         return OpsTask::CanDiscardPreviousOps::kNo;
860     }
861 #endif
862     // Regardless of how the clear is implemented (native clear or a fullscreen quad), all prior ops
863     // would normally be overwritten. The one exception is if the render target context is marked as
864     // needing a stencil buffer then there may be a prior op that writes to the stencil buffer.
865     // Although the clear will ignore the stencil buffer, following draw ops may not so we can't get
866     // rid of all the preceding ops. Beware! If we ever add any ops that have a side effect beyond
867     // modifying the stencil buffer we will need a more elaborate tracking system (skbug.com/7002).
868     return OpsTask::CanDiscardPreviousOps(!fNeedsStencil);
869 }
870 
setNeedsStencil()871 void SurfaceDrawContext::setNeedsStencil() {
872     // Don't clear stencil until after we've set fNeedsStencil. This ensures we don't loop forever
873     // in the event that there are driver bugs and we need to clear as a draw.
874     bool hasInitializedStencil = fNeedsStencil;
875     fNeedsStencil = true;
876     if (!hasInitializedStencil) {
877         this->asRenderTargetProxy()->setNeedsStencil();
878         if (this->caps()->performStencilClearsAsDraws()) {
879             // There is a driver bug with clearing stencil. We must use an op to manually clear the
880             // stencil buffer before the op that required 'setNeedsStencil'.
881             this->internalStencilClear(nullptr, /* inside mask */ false);
882         } else {
883             this->getOpsTask()->setInitialStencilContent(
884                     OpsTask::StencilContent::kUserBitsCleared);
885         }
886     }
887 }
888 
internalStencilClear(const SkIRect* scissor, bool insideStencilMask)889 void SurfaceDrawContext::internalStencilClear(const SkIRect* scissor, bool insideStencilMask) {
890     this->setNeedsStencil();
891 
892     GrScissorState scissorState(this->asSurfaceProxy()->backingStoreDimensions());
893     if (scissor && !scissorState.set(*scissor)) {
894         // The requested clear region is off screen, so nothing to do.
895         return;
896     }
897 
898     bool clearWithDraw = this->caps()->performStencilClearsAsDraws() ||
899                          (scissorState.enabled() && this->caps()->performPartialClearsAsDraws());
900     if (clearWithDraw) {
901         const GrUserStencilSettings* ss = GrStencilSettings::SetClipBitSettings(insideStencilMask);
902 
903         // Configure the paint to have no impact on the color buffer
904         GrPaint paint;
905         paint.setXPFactory(GrDisableColorXPFactory::Get());
906         this->addDrawOp(nullptr,
907                         FillRectOp::MakeNonAARect(fContext, std::move(paint), SkMatrix::I(),
908                                                   SkRect::Make(scissorState.rect()), ss));
909     } else {
910         this->addOp(ClearOp::MakeStencilClip(fContext, scissorState, insideStencilMask));
911     }
912 }
913 
stencilPath(const GrHardClip* clip, GrAA doStencilMSAA, const SkMatrix& viewMatrix, const SkPath& path)914 bool SurfaceDrawContext::stencilPath(const GrHardClip* clip,
915                                      GrAA doStencilMSAA,
916                                      const SkMatrix& viewMatrix,
917                                      const SkPath& path) {
918     SkIRect clipBounds = clip ? clip->getConservativeBounds()
919                               : SkIRect::MakeSize(this->dimensions());
920     GrStyledShape shape(path, GrStyledShape::DoSimplify::kNo);
921 
922     PathRenderer::CanDrawPathArgs canDrawArgs;
923     canDrawArgs.fCaps = fContext->priv().caps();
924     canDrawArgs.fProxy = this->asRenderTargetProxy();
925     canDrawArgs.fClipConservativeBounds = &clipBounds;
926     canDrawArgs.fViewMatrix = &viewMatrix;
927     canDrawArgs.fShape = &shape;
928     canDrawArgs.fPaint = nullptr;
929     canDrawArgs.fSurfaceProps = &fSurfaceProps;
930     canDrawArgs.fAAType = (doStencilMSAA == GrAA::kYes) ? GrAAType::kMSAA : GrAAType::kNone;
931     canDrawArgs.fHasUserStencilSettings = false;
932     auto pr = this->drawingManager()->getPathRenderer(canDrawArgs,
933                                                       false,
934                                                       PathRendererChain::DrawType::kStencil);
935     if (!pr) {
936         SkDebugf("WARNING: No path renderer to stencil path.\n");
937         return false;
938     }
939 
940     PathRenderer::StencilPathArgs args;
941     args.fContext = fContext;
942     args.fSurfaceDrawContext = this;
943     args.fClip = clip;
944     args.fClipConservativeBounds = &clipBounds;
945     args.fViewMatrix = &viewMatrix;
946     args.fShape = &shape;
947     args.fDoStencilMSAA = doStencilMSAA;
948     pr->stencilPath(args);
949     return true;
950 }
951 
drawTextureSet(const GrClip* clip, GrTextureSetEntry set[], int cnt, int proxyRunCnt, GrSamplerState::Filter filter, GrSamplerState::MipmapMode mm, SkBlendMode mode, GrAA aa, SkCanvas::SrcRectConstraint constraint, const SkMatrix& viewMatrix, sk_sp<GrColorSpaceXform> texXform)952 void SurfaceDrawContext::drawTextureSet(const GrClip* clip,
953                                         GrTextureSetEntry set[],
954                                         int cnt,
955                                         int proxyRunCnt,
956                                         GrSamplerState::Filter filter,
957                                         GrSamplerState::MipmapMode mm,
958                                         SkBlendMode mode,
959                                         GrAA aa,
960                                         SkCanvas::SrcRectConstraint constraint,
961                                         const SkMatrix& viewMatrix,
962                                         sk_sp<GrColorSpaceXform> texXform) {
963     ASSERT_SINGLE_OWNER
964     RETURN_IF_ABANDONED
965     SkDEBUGCODE(this->validate();)
966     GR_CREATE_TRACE_MARKER_CONTEXT("SurfaceDrawContext", "drawTextureSet", fContext);
967 
968     // Create the minimum number of GrTextureOps needed to draw this set. Individual
969     // GrTextureOps can rebind the texture between draws thus avoiding GrPaint (re)creation.
970     AutoCheckFlush acf(this->drawingManager());
971     GrAAType aaType = this->chooseAAType(aa);
972     auto clampType = GrColorTypeClampType(this->colorInfo().colorType());
973     auto saturate = clampType == GrClampType::kManual ? TextureOp::Saturate::kYes
974                                                       : TextureOp::Saturate::kNo;
975     TextureOp::AddTextureSetOps(this, clip, fContext, set, cnt, proxyRunCnt, filter, mm, saturate,
976                                 mode, aaType, constraint, viewMatrix, std::move(texXform));
977 }
978 
drawVertices(const GrClip* clip, GrPaint&& paint, const SkMatrixProvider& matrixProvider, sk_sp<SkVertices> vertices, GrPrimitiveType* overridePrimType)979 void SurfaceDrawContext::drawVertices(const GrClip* clip,
980                                       GrPaint&& paint,
981                                       const SkMatrixProvider& matrixProvider,
982                                       sk_sp<SkVertices> vertices,
983                                       GrPrimitiveType* overridePrimType) {
984     ASSERT_SINGLE_OWNER
985     RETURN_IF_ABANDONED
986     SkDEBUGCODE(this->validate();)
987     GR_CREATE_TRACE_MARKER_CONTEXT("SurfaceDrawContext", "drawVertices", fContext);
988 
989     AutoCheckFlush acf(this->drawingManager());
990 
991     SkASSERT(vertices);
992     GrAAType aaType = fCanUseDynamicMSAA ? GrAAType::kMSAA : this->chooseAAType(GrAA::kNo);
993     GrOp::Owner op = DrawVerticesOp::Make(fContext,
994                                           std::move(paint),
995                                           std::move(vertices),
996                                           matrixProvider,
997                                           aaType,
998                                           this->colorInfo().refColorSpaceXformFromSRGB(),
999                                           overridePrimType);
1000     this->addDrawOp(clip, std::move(op));
1001 }
1002 
1003 ///////////////////////////////////////////////////////////////////////////////
1004 
drawAtlas(const GrClip* clip, GrPaint&& paint, const SkMatrix& viewMatrix, int spriteCount, const SkRSXform xform[], const SkRect texRect[], const SkColor colors[])1005 void SurfaceDrawContext::drawAtlas(const GrClip* clip,
1006                                    GrPaint&& paint,
1007                                    const SkMatrix& viewMatrix,
1008                                    int spriteCount,
1009                                    const SkRSXform xform[],
1010                                    const SkRect texRect[],
1011                                    const SkColor colors[]) {
1012     ASSERT_SINGLE_OWNER
1013     RETURN_IF_ABANDONED
1014     SkDEBUGCODE(this->validate();)
1015     GR_CREATE_TRACE_MARKER_CONTEXT("SurfaceDrawContext", "drawAtlas", fContext);
1016 
1017     AutoCheckFlush acf(this->drawingManager());
1018 
1019     GrAAType aaType = this->chooseAAType(GrAA::kNo);
1020     GrOp::Owner op = DrawAtlasOp::Make(fContext, std::move(paint), viewMatrix,
1021                                        aaType, spriteCount, xform, texRect, colors);
1022     this->addDrawOp(clip, std::move(op));
1023 }
1024 
1025 ///////////////////////////////////////////////////////////////////////////////
1026 
drawRRect(const GrClip* origClip, GrPaint&& paint, GrAA aa, const SkMatrix& viewMatrix, const SkRRect& rrect, const GrStyle& style)1027 void SurfaceDrawContext::drawRRect(const GrClip* origClip,
1028                                    GrPaint&& paint,
1029                                    GrAA aa,
1030                                    const SkMatrix& viewMatrix,
1031                                    const SkRRect& rrect,
1032                                    const GrStyle& style) {
1033     ASSERT_SINGLE_OWNER
1034     RETURN_IF_ABANDONED
1035     SkDEBUGCODE(this->validate();)
1036     GR_CREATE_TRACE_MARKER_CONTEXT("SurfaceDrawContext", "drawRRect", fContext);
1037 
1038     SkASSERT(!style.pathEffect()); // this should've been devolved to a path in SkGpuDevice
1039 
1040     const SkStrokeRec& stroke = style.strokeRec();
1041     if (stroke.getStyle() == SkStrokeRec::kFill_Style && rrect.isEmpty()) {
1042        return;
1043     }
1044 
1045     const GrClip* clip = origClip;
1046     // It is not uncommon to clip to a round rect and then draw that same round rect. Since our
1047     // lower level clip code works from op bounds, which are SkRects, it doesn't detect that the
1048     // clip can be ignored. The following test attempts to mitigate the stencil clip cost but only
1049     // works for axis-aligned round rects. This also only works for filled rrects since the stroke
1050     // width outsets beyond the rrect itself.
1051     // TODO: skbug.com/10462 - There was mixed performance wins and regressions when this
1052     // optimization was turned on outside of Android Framework. I (michaelludwig) believe this is
1053     // do to the overhead in determining if an SkClipStack is just a rrect. Once that is improved,
1054     // re-enable this and see if we avoid the regressions.
1055 #ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
1056     SkRRect devRRect;
1057     if (clip && stroke.getStyle() == SkStrokeRec::kFill_Style &&
1058         rrect.transform(viewMatrix, &devRRect)) {
1059         GrClip::PreClipResult result = clip->preApply(devRRect.getBounds(), aa);
1060         switch(result.fEffect) {
1061             case GrClip::Effect::kClippedOut:
1062                 return;
1063             case GrClip::Effect::kUnclipped:
1064                 clip = nullptr;
1065                 break;
1066             case GrClip::Effect::kClipped:
1067                 // Currently there's no general-purpose rrect-to-rrect contains function, and if we
1068                 // got here, we know the devRRect's bounds aren't fully contained by the clip.
1069                 // Testing for equality between the two is a reasonable stop-gap for now.
1070                 if (result.fIsRRect && result.fRRect == devRRect) {
1071                     // NOTE: On the android framework, we allow this optimization even when the clip
1072                     // is non-AA and the draw is AA.
1073                     if (result.fAA == aa || (result.fAA == GrAA::kNo && aa == GrAA::kYes)) {
1074                         clip = nullptr;
1075                     }
1076                 }
1077                 break;
1078             default:
1079                 SkUNREACHABLE;
1080         }
1081     }
1082 #endif
1083 
1084     AutoCheckFlush acf(this->drawingManager());
1085 
1086     GrAAType aaType = this->chooseAAType(aa);
1087 
1088     GrOp::Owner op;
1089     if (aaType == GrAAType::kCoverage                          &&
1090         !fCanUseDynamicMSAA                                    &&
1091         !this->caps()->reducedShaderMode()                     &&
1092         rrect.isSimple()                                       &&
1093         rrect.getSimpleRadii().fX == rrect.getSimpleRadii().fY &&
1094         viewMatrix.rectStaysRect() && viewMatrix.isSimilarity()) {
1095         // In specific cases we use a dedicated circular round rect op to try and get better perf.
1096         assert_alive(paint);
1097         op = GrOvalOpFactory::MakeCircularRRectOp(fContext, std::move(paint), viewMatrix, rrect,
1098                                                   stroke, this->caps()->shaderCaps());
1099     }
1100     if (!op && style.isSimpleFill()) {
1101         assert_alive(paint);
1102         op = FillRRectOp::Make(fContext, this->arenaAlloc(), std::move(paint), viewMatrix, rrect,
1103                                rrect.rect(), GrAA(aaType != GrAAType::kNone));
1104     }
1105     if (!op && (aaType == GrAAType::kCoverage || fCanUseDynamicMSAA)) {
1106         assert_alive(paint);
1107         op = GrOvalOpFactory::MakeRRectOp(
1108                 fContext, std::move(paint), viewMatrix, rrect, stroke, this->caps()->shaderCaps());
1109     }
1110     if (op) {
1111         this->addDrawOp(clip, std::move(op));
1112         return;
1113     }
1114 
1115     assert_alive(paint);
1116     this->drawShapeUsingPathRenderer(clip, std::move(paint), aa, viewMatrix,
1117                                      GrStyledShape(rrect, style, DoSimplify::kNo));
1118 }
1119 
1120 ///////////////////////////////////////////////////////////////////////////////
1121 
drawFastShadow(const GrClip* clip, const SkMatrix& viewMatrix, const SkPath& path, const SkDrawShadowRec& rec)1122 bool SurfaceDrawContext::drawFastShadow(const GrClip* clip,
1123                                         const SkMatrix& viewMatrix,
1124                                         const SkPath& path,
1125                                         const SkDrawShadowRec& rec) {
1126     ASSERT_SINGLE_OWNER
1127     if (fContext->abandoned()) {
1128         return true;
1129     }
1130     SkDEBUGCODE(this->validate();)
1131     GR_CREATE_TRACE_MARKER_CONTEXT("SurfaceDrawContext", "drawFastShadow", fContext);
1132 
1133     // check z plane
1134     bool tiltZPlane = SkToBool(!SkScalarNearlyZero(rec.fZPlaneParams.fX) ||
1135                                !SkScalarNearlyZero(rec.fZPlaneParams.fY));
1136     bool skipAnalytic = SkToBool(rec.fFlags & SkShadowFlags::kGeometricOnly_ShadowFlag);
1137     if (tiltZPlane || skipAnalytic || !viewMatrix.rectStaysRect() || !viewMatrix.isSimilarity()) {
1138         return false;
1139     }
1140 
1141     SkRRect rrect;
1142     SkRect rect;
1143     // we can only handle rects, circles, and simple rrects with circular corners
1144     bool isRRect = path.isRRect(&rrect) && SkRRectPriv::IsNearlySimpleCircular(rrect) &&
1145                    rrect.getSimpleRadii().fX > SK_ScalarNearlyZero;
1146     if (!isRRect &&
1147         path.isOval(&rect) && SkScalarNearlyEqual(rect.width(), rect.height()) &&
1148         rect.width() > SK_ScalarNearlyZero) {
1149         rrect.setOval(rect);
1150         isRRect = true;
1151     }
1152     if (!isRRect && path.isRect(&rect)) {
1153         rrect.setRect(rect);
1154         isRRect = true;
1155     }
1156 
1157     if (!isRRect) {
1158         return false;
1159     }
1160 
1161     if (rrect.isEmpty()) {
1162         return true;
1163     }
1164 
1165     AutoCheckFlush acf(this->drawingManager());
1166 
1167     SkPoint3 devLightPos = rec.fLightPos;
1168     bool directional = SkToBool(rec.fFlags & kDirectionalLight_ShadowFlag);
1169     if (!directional) {
1170         // transform light
1171         viewMatrix.mapPoints((SkPoint*)&devLightPos.fX, 1);
1172     }
1173 
1174     // 1/scale
1175     SkScalar devToSrcScale = viewMatrix.isScaleTranslate() ?
1176         SkScalarInvert(SkScalarAbs(viewMatrix[SkMatrix::kMScaleX])) :
1177         sk_float_rsqrt(viewMatrix[SkMatrix::kMScaleX] * viewMatrix[SkMatrix::kMScaleX] +
1178                        viewMatrix[SkMatrix::kMSkewX] * viewMatrix[SkMatrix::kMSkewX]);
1179 
1180     SkScalar occluderHeight = rec.fZPlaneParams.fZ;
1181     bool transparent = SkToBool(rec.fFlags & SkShadowFlags::kTransparentOccluder_ShadowFlag);
1182 
1183     if (SkColorGetA(rec.fAmbientColor) > 0) {
1184         SkScalar devSpaceInsetWidth = SkDrawShadowMetrics::AmbientBlurRadius(occluderHeight);
1185         const SkScalar umbraRecipAlpha = SkDrawShadowMetrics::AmbientRecipAlpha(occluderHeight);
1186         const SkScalar devSpaceAmbientBlur = devSpaceInsetWidth * umbraRecipAlpha;
1187 
1188         // Outset the shadow rrect to the border of the penumbra
1189         SkScalar ambientPathOutset = devSpaceInsetWidth * devToSrcScale;
1190         SkRRect ambientRRect;
1191         SkRect outsetRect = rrect.rect().makeOutset(ambientPathOutset, ambientPathOutset);
1192         // If the rrect was an oval then its outset will also be one.
1193         // We set it explicitly to avoid errors.
1194         if (rrect.isOval()) {
1195             ambientRRect = SkRRect::MakeOval(outsetRect);
1196         } else {
1197             SkScalar outsetRad = SkRRectPriv::GetSimpleRadii(rrect).fX + ambientPathOutset;
1198             ambientRRect = SkRRect::MakeRectXY(outsetRect, outsetRad, outsetRad);
1199         }
1200 
1201         GrColor ambientColor = SkColorToPremulGrColor(rec.fAmbientColor);
1202         if (transparent) {
1203             // set a large inset to force a fill
1204             devSpaceInsetWidth = ambientRRect.width();
1205         }
1206 
1207         GrOp::Owner op = ShadowRRectOp::Make(fContext,
1208                                              ambientColor,
1209                                              viewMatrix,
1210                                              ambientRRect,
1211                                              devSpaceAmbientBlur,
1212                                              devSpaceInsetWidth);
1213         if (op) {
1214             this->addDrawOp(clip, std::move(op));
1215         }
1216     }
1217 
1218     if (SkColorGetA(rec.fSpotColor) > 0) {
1219         SkScalar devSpaceSpotBlur;
1220         SkScalar spotScale;
1221         SkVector spotOffset;
1222         if (directional) {
1223             SkDrawShadowMetrics::GetDirectionalParams(occluderHeight, devLightPos.fX,
1224                                                       devLightPos.fY, devLightPos.fZ,
1225                                                       rec.fLightRadius, &devSpaceSpotBlur,
1226                                                       &spotScale, &spotOffset);
1227         } else {
1228             SkDrawShadowMetrics::GetSpotParams(occluderHeight, devLightPos.fX, devLightPos.fY,
1229                                                devLightPos.fZ, rec.fLightRadius,
1230                                                &devSpaceSpotBlur, &spotScale, &spotOffset, rec.isLimitElevation);
1231         }
1232         // handle scale of radius due to CTM
1233         const SkScalar srcSpaceSpotBlur = devSpaceSpotBlur * devToSrcScale;
1234 
1235         // Adjust translate for the effect of the scale.
1236         spotOffset.fX += spotScale*viewMatrix[SkMatrix::kMTransX];
1237         spotOffset.fY += spotScale*viewMatrix[SkMatrix::kMTransY];
1238         // This offset is in dev space, need to transform it into source space.
1239         SkMatrix ctmInverse;
1240         if (viewMatrix.invert(&ctmInverse)) {
1241             ctmInverse.mapPoints(&spotOffset, 1);
1242         } else {
1243             // Since the matrix is a similarity, this should never happen, but just in case...
1244             SkDebugf("Matrix is degenerate. Will not render spot shadow correctly!\n");
1245             SkASSERT(false);
1246         }
1247 
1248         // Compute the transformed shadow rrect
1249         SkRRect spotShadowRRect;
1250         SkMatrix shadowTransform;
1251         shadowTransform.setScaleTranslate(spotScale, spotScale, spotOffset.fX, spotOffset.fY);
1252         rrect.transform(shadowTransform, &spotShadowRRect);
1253         SkScalar spotRadius = spotShadowRRect.getSimpleRadii().fX;
1254 
1255         // Compute the insetWidth
1256         SkScalar blurOutset = srcSpaceSpotBlur;
1257         SkScalar insetWidth = blurOutset;
1258         if (transparent) {
1259             // If transparent, just do a fill
1260             insetWidth += spotShadowRRect.width();
1261         } else {
1262             // For shadows, instead of using a stroke we specify an inset from the penumbra
1263             // border. We want to extend this inset area so that it meets up with the caster
1264             // geometry. The inset geometry will by default already be inset by the blur width.
1265             //
1266             // We compare the min and max corners inset by the radius between the original
1267             // rrect and the shadow rrect. The distance between the two plus the difference
1268             // between the scaled radius and the original radius gives the distance from the
1269             // transformed shadow shape to the original shape in that corner. The max
1270             // of these gives the maximum distance we need to cover.
1271             //
1272             // Since we are outsetting by 1/2 the blur distance, we just add the maxOffset to
1273             // that to get the full insetWidth.
1274             SkScalar maxOffset;
1275             if (rrect.isRect()) {
1276                 // Manhattan distance works better for rects
1277                 maxOffset = std::max(std::max(SkTAbs(spotShadowRRect.rect().fLeft -
1278                                                  rrect.rect().fLeft),
1279                                           SkTAbs(spotShadowRRect.rect().fTop -
1280                                                  rrect.rect().fTop)),
1281                                    std::max(SkTAbs(spotShadowRRect.rect().fRight -
1282                                                  rrect.rect().fRight),
1283                                           SkTAbs(spotShadowRRect.rect().fBottom -
1284                                                  rrect.rect().fBottom)));
1285             } else {
1286                 SkScalar dr = spotRadius - SkRRectPriv::GetSimpleRadii(rrect).fX;
1287                 SkPoint upperLeftOffset = SkPoint::Make(spotShadowRRect.rect().fLeft -
1288                                                         rrect.rect().fLeft + dr,
1289                                                         spotShadowRRect.rect().fTop -
1290                                                         rrect.rect().fTop + dr);
1291                 SkPoint lowerRightOffset = SkPoint::Make(spotShadowRRect.rect().fRight -
1292                                                          rrect.rect().fRight - dr,
1293                                                          spotShadowRRect.rect().fBottom -
1294                                                          rrect.rect().fBottom - dr);
1295                 maxOffset = SkScalarSqrt(std::max(SkPointPriv::LengthSqd(upperLeftOffset),
1296                                                   SkPointPriv::LengthSqd(lowerRightOffset))) + dr;
1297             }
1298             insetWidth += std::max(blurOutset, maxOffset);
1299         }
1300 
1301         // Outset the shadow rrect to the border of the penumbra
1302         SkRect outsetRect = spotShadowRRect.rect().makeOutset(blurOutset, blurOutset);
1303         if (spotShadowRRect.isOval()) {
1304             spotShadowRRect = SkRRect::MakeOval(outsetRect);
1305         } else {
1306             SkScalar outsetRad = spotRadius + blurOutset;
1307             spotShadowRRect = SkRRect::MakeRectXY(outsetRect, outsetRad, outsetRad);
1308         }
1309 
1310         GrColor spotColor = SkColorToPremulGrColor(rec.fSpotColor);
1311 
1312         GrOp::Owner op = ShadowRRectOp::Make(fContext,
1313                                              spotColor,
1314                                              viewMatrix,
1315                                              spotShadowRRect,
1316                                              2.0f * devSpaceSpotBlur,
1317                                              insetWidth);
1318         if (op) {
1319             this->addDrawOp(clip, std::move(op));
1320         }
1321     }
1322 
1323     return true;
1324 }
1325 
1326 ///////////////////////////////////////////////////////////////////////////////
1327 
drawRegion(const GrClip* clip, GrPaint&& paint, GrAA aa, const SkMatrix& viewMatrix, const SkRegion& region, const GrStyle& style, const GrUserStencilSettings* ss)1328 void SurfaceDrawContext::drawRegion(const GrClip* clip,
1329                                     GrPaint&& paint,
1330                                     GrAA aa,
1331                                     const SkMatrix& viewMatrix,
1332                                     const SkRegion& region,
1333                                     const GrStyle& style,
1334                                     const GrUserStencilSettings* ss) {
1335     ASSERT_SINGLE_OWNER
1336     RETURN_IF_ABANDONED
1337     SkDEBUGCODE(this->validate();)
1338     GR_CREATE_TRACE_MARKER_CONTEXT("SurfaceDrawContext", "drawRegion", fContext);
1339 
1340     if (GrAA::kYes == aa) {
1341         // GrRegionOp performs no antialiasing but is much faster, so here we check the matrix
1342         // to see whether aa is really required.
1343         if (!SkToBool(viewMatrix.getType() & ~(SkMatrix::kTranslate_Mask)) &&
1344             SkScalarIsInt(viewMatrix.getTranslateX()) &&
1345             SkScalarIsInt(viewMatrix.getTranslateY())) {
1346             aa = GrAA::kNo;
1347         }
1348     }
1349     bool complexStyle = !style.isSimpleFill();
1350     if (complexStyle || GrAA::kYes == aa) {
1351         SkPath path;
1352         region.getBoundaryPath(&path);
1353         path.setIsVolatile(true);
1354 
1355         return this->drawPath(clip, std::move(paint), aa, viewMatrix, path, style);
1356     }
1357 
1358     GrAAType aaType = (this->numSamples() > 1) ? GrAAType::kMSAA : GrAAType::kNone;
1359     GrOp::Owner op = RegionOp::Make(fContext, std::move(paint), viewMatrix, region, aaType, ss);
1360     this->addDrawOp(clip, std::move(op));
1361 }
1362 
drawOval(const GrClip* clip, GrPaint&& paint, GrAA aa, const SkMatrix& viewMatrix, const SkRect& oval, const GrStyle& style)1363 void SurfaceDrawContext::drawOval(const GrClip* clip,
1364                                   GrPaint&& paint,
1365                                   GrAA aa,
1366                                   const SkMatrix& viewMatrix,
1367                                   const SkRect& oval,
1368                                   const GrStyle& style) {
1369     ASSERT_SINGLE_OWNER
1370     RETURN_IF_ABANDONED
1371     SkDEBUGCODE(this->validate();)
1372     GR_CREATE_TRACE_MARKER_CONTEXT("SurfaceDrawContext", "drawOval", fContext);
1373 
1374     const SkStrokeRec& stroke = style.strokeRec();
1375 
1376     if (oval.isEmpty() && !style.pathEffect()) {
1377         if (stroke.getStyle() == SkStrokeRec::kFill_Style) {
1378             return;
1379         }
1380 
1381         this->drawRect(clip, std::move(paint), aa, viewMatrix, oval, &style);
1382         return;
1383     }
1384 
1385     AutoCheckFlush acf(this->drawingManager());
1386 
1387     GrAAType aaType = this->chooseAAType(aa);
1388 
1389     GrOp::Owner op;
1390     if (aaType == GrAAType::kCoverage      &&
1391         !fCanUseDynamicMSAA                &&
1392         !this->caps()->reducedShaderMode() &&
1393         oval.width() > SK_ScalarNearlyZero &&
1394         oval.width() == oval.height()      &&
1395         viewMatrix.isSimilarity()) {
1396         // In specific cases we use a dedicated circle op to try and get better perf.
1397         assert_alive(paint);
1398         op = GrOvalOpFactory::MakeCircleOp(fContext, std::move(paint), viewMatrix, oval, style,
1399                                            this->caps()->shaderCaps());
1400     }
1401     if (!op && style.isSimpleFill()) {
1402         // FillRRectOp has special geometry and a fragment-shader branch to conditionally evaluate
1403         // the arc equation. This same special geometry and fragment branch also turn out to be a
1404         // substantial optimization for drawing ovals (namely, by not evaluating the arc equation
1405         // inside the oval's inner diamond). Given these optimizations, it's a clear win to draw
1406         // ovals the exact same way we do round rects.
1407         assert_alive(paint);
1408         op = FillRRectOp::Make(fContext, this->arenaAlloc(), std::move(paint), viewMatrix,
1409                                SkRRect::MakeOval(oval), oval, GrAA(aaType != GrAAType::kNone));
1410     }
1411     if (!op && (aaType == GrAAType::kCoverage || fCanUseDynamicMSAA)) {
1412         assert_alive(paint);
1413         op = GrOvalOpFactory::MakeOvalOp(fContext, std::move(paint), viewMatrix, oval, style,
1414                                          this->caps()->shaderCaps());
1415     }
1416     if (op) {
1417         this->addDrawOp(clip, std::move(op));
1418         return;
1419     }
1420 
1421     assert_alive(paint);
1422     this->drawShapeUsingPathRenderer(clip, std::move(paint), aa, viewMatrix,
1423                                      GrStyledShape(SkRRect::MakeOval(oval), SkPathDirection::kCW, 2,
1424                                                    false, style, DoSimplify::kNo));
1425 }
1426 
drawArc(const GrClip* clip, GrPaint&& paint, GrAA aa, const SkMatrix& viewMatrix, const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle, bool useCenter, const GrStyle& style)1427 void SurfaceDrawContext::drawArc(const GrClip* clip,
1428                                  GrPaint&& paint,
1429                                  GrAA aa,
1430                                  const SkMatrix& viewMatrix,
1431                                  const SkRect& oval,
1432                                  SkScalar startAngle,
1433                                  SkScalar sweepAngle,
1434                                  bool useCenter,
1435                                  const GrStyle& style) {
1436     ASSERT_SINGLE_OWNER
1437     RETURN_IF_ABANDONED
1438     SkDEBUGCODE(this->validate();)
1439             GR_CREATE_TRACE_MARKER_CONTEXT("SurfaceDrawContext", "drawArc", fContext);
1440 
1441     AutoCheckFlush acf(this->drawingManager());
1442 
1443     GrAAType aaType = this->chooseAAType(aa);
1444     if (aaType == GrAAType::kCoverage) {
1445         const GrShaderCaps* shaderCaps = this->caps()->shaderCaps();
1446         GrOp::Owner op = GrOvalOpFactory::MakeArcOp(fContext,
1447                                                     std::move(paint),
1448                                                     viewMatrix,
1449                                                     oval,
1450                                                     startAngle,
1451                                                     sweepAngle,
1452                                                     useCenter,
1453                                                     style,
1454                                                     shaderCaps);
1455         if (op) {
1456             this->addDrawOp(clip, std::move(op));
1457             return;
1458         }
1459         assert_alive(paint);
1460     }
1461     this->drawShapeUsingPathRenderer(clip, std::move(paint), aa, viewMatrix,
1462                                      GrStyledShape::MakeArc(oval, startAngle, sweepAngle, useCenter,
1463                                                             style, DoSimplify::kNo));
1464 }
1465 
drawImageLattice(const GrClip* clip, GrPaint&& paint, const SkMatrix& viewMatrix, GrSurfaceProxyView view, SkAlphaType alphaType, sk_sp<GrColorSpaceXform> csxf, GrSamplerState::Filter filter, std::unique_ptr<SkLatticeIter> iter, const SkRect& dst)1466 void SurfaceDrawContext::drawImageLattice(const GrClip* clip,
1467                                           GrPaint&& paint,
1468                                           const SkMatrix& viewMatrix,
1469                                           GrSurfaceProxyView view,
1470                                           SkAlphaType alphaType,
1471                                           sk_sp<GrColorSpaceXform> csxf,
1472                                           GrSamplerState::Filter filter,
1473                                           std::unique_ptr<SkLatticeIter> iter,
1474                                           const SkRect& dst) {
1475     ASSERT_SINGLE_OWNER
1476     RETURN_IF_ABANDONED
1477     SkDEBUGCODE(this->validate();)
1478     GR_CREATE_TRACE_MARKER_CONTEXT("SurfaceDrawContext", "drawImageLattice", fContext);
1479 
1480     AutoCheckFlush acf(this->drawingManager());
1481 
1482     GrOp::Owner op =
1483               LatticeOp::MakeNonAA(fContext, std::move(paint), viewMatrix, std::move(view),
1484                                    alphaType, std::move(csxf), filter, std::move(iter), dst);
1485     this->addDrawOp(clip, std::move(op));
1486 }
1487 
drawDrawable(std::unique_ptr<SkDrawable::GpuDrawHandler> drawable, const SkRect& bounds)1488 void SurfaceDrawContext::drawDrawable(std::unique_ptr<SkDrawable::GpuDrawHandler> drawable,
1489                                       const SkRect& bounds) {
1490     GrOp::Owner op(DrawableOp::Make(fContext, std::move(drawable), bounds));
1491     SkASSERT(op);
1492     this->addOp(std::move(op));
1493 }
1494 
setLastClip(uint32_t clipStackGenID, const SkIRect& devClipBounds, int numClipAnalyticElements)1495 void SurfaceDrawContext::setLastClip(uint32_t clipStackGenID,
1496                                      const SkIRect& devClipBounds,
1497                                      int numClipAnalyticElements) {
1498     auto opsTask = this->getOpsTask();
1499     opsTask->fLastClipStackGenID = clipStackGenID;
1500     opsTask->fLastDevClipBounds = devClipBounds;
1501     opsTask->fLastClipNumAnalyticElements = numClipAnalyticElements;
1502 }
1503 
mustRenderClip(uint32_t clipStackGenID, const SkIRect& devClipBounds, int numClipAnalyticElements)1504 bool SurfaceDrawContext::mustRenderClip(uint32_t clipStackGenID,
1505                                         const SkIRect& devClipBounds,
1506                                         int numClipAnalyticElements) {
1507     auto opsTask = this->getOpsTask();
1508     return opsTask->fLastClipStackGenID != clipStackGenID ||
1509            !opsTask->fLastDevClipBounds.contains(devClipBounds) ||
1510            opsTask->fLastClipNumAnalyticElements != numClipAnalyticElements;
1511 }
1512 
waitOnSemaphores(int numSemaphores, const GrBackendSemaphore waitSemaphores[], bool deleteSemaphoresAfterWait)1513 bool SurfaceDrawContext::waitOnSemaphores(int numSemaphores,
1514                                           const GrBackendSemaphore waitSemaphores[],
1515                                           bool deleteSemaphoresAfterWait) {
1516     ASSERT_SINGLE_OWNER
1517     RETURN_FALSE_IF_ABANDONED
1518     SkDEBUGCODE(this->validate();)
1519     GR_CREATE_TRACE_MARKER_CONTEXT("SurfaceDrawContext", "waitOnSemaphores", fContext);
1520 
1521     AutoCheckFlush acf(this->drawingManager());
1522 
1523     if (numSemaphores && !this->caps()->semaphoreSupport()) {
1524         return false;
1525     }
1526 
1527     auto direct = fContext->asDirectContext();
1528     if (!direct) {
1529         return false;
1530     }
1531 
1532     auto resourceProvider = direct->priv().resourceProvider();
1533 
1534     GrWrapOwnership ownership =
1535             deleteSemaphoresAfterWait ? kAdopt_GrWrapOwnership : kBorrow_GrWrapOwnership;
1536 
1537     std::unique_ptr<std::unique_ptr<GrSemaphore>[]> grSemaphores(
1538             new std::unique_ptr<GrSemaphore>[numSemaphores]);
1539     for (int i = 0; i < numSemaphores; ++i) {
1540         grSemaphores[i] = resourceProvider->wrapBackendSemaphore(waitSemaphores[i],
1541                                                                  GrSemaphoreWrapType::kWillWait,
1542                                                                  ownership);
1543     }
1544     this->drawingManager()->newWaitRenderTask(this->asSurfaceProxyRef(), std::move(grSemaphores),
1545                                               numSemaphores);
1546     return true;
1547 }
1548 
drawPath(const GrClip* clip, GrPaint&& paint, GrAA aa, const SkMatrix& viewMatrix, const SkPath& path, const GrStyle& style)1549 void SurfaceDrawContext::drawPath(const GrClip* clip,
1550                                   GrPaint&& paint,
1551                                   GrAA aa,
1552                                   const SkMatrix& viewMatrix,
1553                                   const SkPath& path,
1554                                   const GrStyle& style) {
1555     ASSERT_SINGLE_OWNER
1556     RETURN_IF_ABANDONED
1557     SkDEBUGCODE(this->validate();)
1558     GR_CREATE_TRACE_MARKER_CONTEXT("SurfaceDrawContext", "drawPath", fContext);
1559 
1560     GrStyledShape shape(path, style, DoSimplify::kNo);
1561     this->drawShape(clip, std::move(paint), aa, viewMatrix, std::move(shape));
1562 }
1563 
drawShape(const GrClip* clip, GrPaint&& paint, GrAA aa, const SkMatrix& viewMatrix, GrStyledShape&& shape)1564 void SurfaceDrawContext::drawShape(const GrClip* clip,
1565                                    GrPaint&& paint,
1566                                    GrAA aa,
1567                                    const SkMatrix& viewMatrix,
1568                                    GrStyledShape&& shape) {
1569     ASSERT_SINGLE_OWNER
1570     RETURN_IF_ABANDONED
1571     SkDEBUGCODE(this->validate();)
1572     GR_CREATE_TRACE_MARKER_CONTEXT("SurfaceDrawContext", "drawShape", fContext);
1573 
1574     if (shape.isEmpty()) {
1575         if (shape.inverseFilled()) {
1576             this->drawPaint(clip, std::move(paint), viewMatrix);
1577         }
1578         return;
1579     }
1580 
1581     AutoCheckFlush acf(this->drawingManager());
1582 
1583     // If we get here in drawShape(), we definitely need to use path rendering
1584     this->drawShapeUsingPathRenderer(clip, std::move(paint), aa, viewMatrix, std::move(shape),
1585                                      /* attemptDrawSimple */ true);
1586 }
1587 
get_clip_bounds(const SurfaceDrawContext* sdc, const GrClip* clip)1588 static SkIRect get_clip_bounds(const SurfaceDrawContext* sdc, const GrClip* clip) {
1589     return clip ? clip->getConservativeBounds() : SkIRect::MakeWH(sdc->width(), sdc->height());
1590 }
1591 
drawAndStencilPath(const GrHardClip* clip, const GrUserStencilSettings* ss, SkRegion::Op op, bool invert, GrAA aa, const SkMatrix& viewMatrix, const SkPath& path)1592 bool SurfaceDrawContext::drawAndStencilPath(const GrHardClip* clip,
1593                                             const GrUserStencilSettings* ss,
1594                                             SkRegion::Op op,
1595                                             bool invert,
1596                                             GrAA aa,
1597                                             const SkMatrix& viewMatrix,
1598                                             const SkPath& path) {
1599     ASSERT_SINGLE_OWNER
1600     RETURN_FALSE_IF_ABANDONED
1601     SkDEBUGCODE(this->validate();)
1602     GR_CREATE_TRACE_MARKER_CONTEXT("SurfaceDrawContext", "drawAndStencilPath", fContext);
1603 
1604     if (path.isEmpty() && path.isInverseFillType()) {
1605         GrPaint paint;
1606         paint.setCoverageSetOpXPFactory(op, invert);
1607         this->stencilRect(clip, ss, std::move(paint), GrAA::kNo, SkMatrix::I(),
1608                           SkRect::Make(this->dimensions()));
1609         return true;
1610     }
1611 
1612     AutoCheckFlush acf(this->drawingManager());
1613 
1614     // An Assumption here is that path renderer would use some form of tweaking
1615     // the src color (either the input alpha or in the frag shader) to implement
1616     // aa. If we have some future driver-mojo path AA that can do the right
1617     // thing WRT to the blend then we'll need some query on the PR.
1618     GrAAType aaType = this->chooseAAType(aa);
1619     bool hasUserStencilSettings = !ss->isUnused();
1620 
1621     SkIRect clipConservativeBounds = get_clip_bounds(this, clip);
1622 
1623     GrPaint paint;
1624     paint.setCoverageSetOpXPFactory(op, invert);
1625 
1626     GrStyledShape shape(path, GrStyle::SimpleFill());
1627     PathRenderer::CanDrawPathArgs canDrawArgs;
1628     canDrawArgs.fCaps = this->caps();
1629     canDrawArgs.fProxy = this->asRenderTargetProxy();
1630     canDrawArgs.fViewMatrix = &viewMatrix;
1631     canDrawArgs.fShape = &shape;
1632     canDrawArgs.fPaint = &paint;
1633     canDrawArgs.fSurfaceProps = &fSurfaceProps;
1634     canDrawArgs.fClipConservativeBounds = &clipConservativeBounds;
1635     canDrawArgs.fAAType = aaType;
1636     canDrawArgs.fHasUserStencilSettings = hasUserStencilSettings;
1637 
1638     using DrawType = PathRendererChain::DrawType;
1639 
1640     // Don't allow the SW renderer
1641     auto pr = this->drawingManager()->getPathRenderer(canDrawArgs,
1642                                                       false,
1643                                                       DrawType::kStencilAndColor);
1644     if (!pr) {
1645         return false;
1646     }
1647 
1648     PathRenderer::DrawPathArgs args{this->drawingManager()->getContext(),
1649                                     std::move(paint),
1650                                     ss,
1651                                     this,
1652                                     clip,
1653                                     &clipConservativeBounds,
1654                                     &viewMatrix,
1655                                     &shape,
1656                                     aaType,
1657                                     this->colorInfo().isLinearlyBlended()};
1658     pr->drawPath(args);
1659     return true;
1660 }
1661 
isBudgeted() const1662 SkBudgeted SurfaceDrawContext::isBudgeted() const {
1663     ASSERT_SINGLE_OWNER
1664 
1665     if (fContext->abandoned()) {
1666         return SkBudgeted::kNo;
1667     }
1668 
1669     SkDEBUGCODE(this->validate();)
1670 
1671     return this->asSurfaceProxy()->isBudgeted();
1672 }
1673 
drawStrokedLine(const GrClip* clip, GrPaint&& paint, GrAA aa, const SkMatrix& viewMatrix, const SkPoint points[2], const SkStrokeRec& stroke)1674 void SurfaceDrawContext::drawStrokedLine(const GrClip* clip,
1675                                          GrPaint&& paint,
1676                                          GrAA aa,
1677                                          const SkMatrix& viewMatrix,
1678                                          const SkPoint points[2],
1679                                          const SkStrokeRec& stroke) {
1680     ASSERT_SINGLE_OWNER
1681 
1682     SkASSERT(stroke.getStyle() == SkStrokeRec::kStroke_Style);
1683     SkASSERT(stroke.getWidth() > 0);
1684     // Adding support for round capping would require a
1685     // SurfaceDrawContext::fillRRectWithLocalMatrix entry point
1686     SkASSERT(SkPaint::kRound_Cap != stroke.getCap());
1687 
1688     const SkScalar halfWidth = 0.5f * stroke.getWidth();
1689     if (halfWidth <= 0.f) {
1690         // Prevents underflow when stroke width is epsilon > 0 (so technically not a hairline).
1691         // The CTM would need to have a scale near 1/epsilon in order for this to have meaningful
1692         // coverage (although that would likely overflow elsewhere and cause the draw to drop due
1693         // to non-finite bounds). At any other scale, this line is so thin, it's coverage is
1694         // negligible, so discarding the draw is visually equivalent.
1695         return;
1696     }
1697 
1698     SkVector parallel = points[1] - points[0];
1699 
1700     if (!SkPoint::Normalize(&parallel)) {
1701         parallel.fX = 1.0f;
1702         parallel.fY = 0.0f;
1703     }
1704     parallel *= halfWidth;
1705 
1706     SkVector ortho = { parallel.fY, -parallel.fX };
1707     if (SkPaint::kButt_Cap == stroke.getCap()) {
1708         // No extra extension for butt caps
1709         parallel = {0.f, 0.f};
1710     }
1711     // Order is TL, TR, BR, BL where arbitrarily "down" is p0 to p1 and "right" is positive
1712     SkPoint corners[4] = { points[0] - ortho - parallel,
1713                            points[0] + ortho - parallel,
1714                            points[1] + ortho + parallel,
1715                            points[1] - ortho + parallel };
1716 
1717     GrQuadAAFlags edgeAA = (aa == GrAA::kYes) ? GrQuadAAFlags::kAll : GrQuadAAFlags::kNone;
1718     this->fillQuadWithEdgeAA(clip, std::move(paint), aa, edgeAA, viewMatrix, corners, nullptr);
1719 }
1720 
drawSimpleShape(const GrClip* clip, GrPaint* paint, GrAA aa, const SkMatrix& viewMatrix, const GrStyledShape& shape)1721 bool SurfaceDrawContext::drawSimpleShape(const GrClip* clip,
1722                                          GrPaint* paint,
1723                                          GrAA aa,
1724                                          const SkMatrix& viewMatrix,
1725                                          const GrStyledShape& shape) {
1726     if (!shape.style().hasPathEffect()) {
1727         GrAAType aaType = this->chooseAAType(aa);
1728         SkPoint linePts[2];
1729         SkRRect rrect;
1730         // We can ignore the starting point and direction since there is no path effect.
1731         bool inverted;
1732         if (shape.asLine(linePts, &inverted) && !inverted &&
1733             shape.style().strokeRec().getStyle() == SkStrokeRec::kStroke_Style &&
1734             shape.style().strokeRec().getCap() != SkPaint::kRound_Cap) {
1735             // The stroked line is an oriented rectangle, which looks the same or better (if
1736             // perspective) compared to path rendering. The exception is subpixel/hairline lines
1737             // that are non-AA or MSAA, in which case the default path renderer achieves higher
1738             // quality.
1739             // FIXME(michaelludwig): If the fill rect op could take an external coverage, or checks
1740             // for and outsets thin non-aa rects to 1px, the path renderer could be skipped.
1741             SkScalar coverage;
1742             if (aaType == GrAAType::kCoverage ||
1743                 !SkDrawTreatAAStrokeAsHairline(shape.style().strokeRec().getWidth(), viewMatrix,
1744                                                &coverage)) {
1745                 this->drawStrokedLine(clip, std::move(*paint), aa, viewMatrix, linePts,
1746                                       shape.style().strokeRec());
1747                 return true;
1748             }
1749         } else if (shape.asRRect(&rrect, nullptr, nullptr, &inverted) && !inverted) {
1750             if (rrect.isRect()) {
1751                 this->drawRect(clip, std::move(*paint), aa, viewMatrix, rrect.rect(),
1752                                &shape.style());
1753                 return true;
1754             } else if (rrect.isOval()) {
1755                 this->drawOval(clip, std::move(*paint), aa, viewMatrix, rrect.rect(),
1756                                shape.style());
1757                 return true;
1758             }
1759             this->drawRRect(clip, std::move(*paint), aa, viewMatrix, rrect, shape.style());
1760             return true;
1761         } else if (GrAAType::kCoverage == aaType &&
1762                    shape.style().isSimpleFill()  &&
1763                    viewMatrix.rectStaysRect()    &&
1764                    !this->caps()->reducedShaderMode()) {
1765             // TODO: the rectStaysRect restriction could be lifted if we were willing to apply the
1766             // matrix to all the points individually rather than just to the rect
1767             SkRect rects[2];
1768             if (shape.asNestedRects(rects)) {
1769                 // Concave AA paths are expensive - try to avoid them for special cases
1770                 GrOp::Owner op = StrokeRectOp::MakeNested(fContext, std::move(*paint),
1771                                                           viewMatrix, rects);
1772                 if (op) {
1773                     this->addDrawOp(clip, std::move(op));
1774                     return true;
1775                 }
1776                 // Fall through to let path renderer handle subpixel nested rects with unequal
1777                 // stroke widths along X/Y.
1778             }
1779         }
1780     }
1781     return false;
1782 }
1783 
drawShapeUsingPathRenderer(const GrClip* clip, GrPaint&& paint, GrAA aa, const SkMatrix& viewMatrix, GrStyledShape&& shape, bool attemptDrawSimple)1784 void SurfaceDrawContext::drawShapeUsingPathRenderer(const GrClip* clip,
1785                                                     GrPaint&& paint,
1786                                                     GrAA aa,
1787                                                     const SkMatrix& viewMatrix,
1788                                                     GrStyledShape&& shape,
1789                                                     bool attemptDrawSimple) {
1790     ASSERT_SINGLE_OWNER
1791     RETURN_IF_ABANDONED
1792     GR_CREATE_TRACE_MARKER_CONTEXT("SurfaceDrawContext", "internalDrawPath", fContext);
1793 
1794     if (!viewMatrix.isFinite() || !shape.bounds().isFinite()) {
1795         return;
1796     }
1797 
1798     SkIRect clipConservativeBounds = get_clip_bounds(this, clip);
1799 
1800     // Always allow paths to trigger DMSAA.
1801     GrAAType aaType = fCanUseDynamicMSAA ? GrAAType::kMSAA : this->chooseAAType(aa);
1802 
1803     PathRenderer::CanDrawPathArgs canDrawArgs;
1804     canDrawArgs.fCaps = this->caps();
1805     canDrawArgs.fProxy = this->asRenderTargetProxy();
1806     canDrawArgs.fViewMatrix = &viewMatrix;
1807     canDrawArgs.fShape = &shape;
1808     canDrawArgs.fPaint = &paint;
1809     canDrawArgs.fSurfaceProps = &fSurfaceProps;
1810     canDrawArgs.fClipConservativeBounds = &clipConservativeBounds;
1811     canDrawArgs.fHasUserStencilSettings = false;
1812     canDrawArgs.fAAType = aaType;
1813 
1814     constexpr static bool kDisallowSWPathRenderer = false;
1815     constexpr static bool kAllowSWPathRenderer = true;
1816     using DrawType = PathRendererChain::DrawType;
1817 
1818     PathRenderer* pr = nullptr;
1819 
1820     if (!shape.style().strokeRec().isFillStyle() && !shape.isEmpty()) {
1821         // Give the tessellation path renderer a chance to claim this stroke before we simplify it.
1822         PathRenderer* tess = this->drawingManager()->getTessellationPathRenderer();
1823         if (tess && tess->canDrawPath(canDrawArgs) == PathRenderer::CanDrawPath::kYes) {
1824             pr = tess;
1825         }
1826     }
1827 
1828     if (!pr) {
1829         // The shape isn't a stroke that can be drawn directly. Simplify if possible.
1830         shape.simplify();
1831 
1832         if (shape.isEmpty() && !shape.inverseFilled()) {
1833             return;
1834         }
1835 
1836         if (attemptDrawSimple || shape.simplified()) {
1837             // Usually we enter drawShapeUsingPathRenderer() because the shape+style was too complex
1838             // for dedicated draw ops. However, if GrStyledShape was able to reduce something we
1839             // ought to try again instead of going right to path rendering.
1840             if (this->drawSimpleShape(clip, &paint, aa, viewMatrix, shape)) {
1841                 return;
1842             }
1843         }
1844 
1845         // Try a 1st time without applying any of the style to the geometry (and barring sw)
1846         pr = this->drawingManager()->getPathRenderer(canDrawArgs, kDisallowSWPathRenderer,
1847                                                      DrawType::kColor);
1848     }
1849 
1850     SkScalar styleScale =  GrStyle::MatrixToScaleFactor(viewMatrix);
1851     if (styleScale == 0.0f) {
1852         return;
1853     }
1854 
1855     if (!pr && shape.style().pathEffect()) {
1856         // It didn't work above, so try again with the path effect applied.
1857         shape = shape.applyStyle(GrStyle::Apply::kPathEffectOnly, styleScale);
1858         if (shape.isEmpty()) {
1859             return;
1860         }
1861         pr = this->drawingManager()->getPathRenderer(canDrawArgs, kDisallowSWPathRenderer,
1862                                                      DrawType::kColor);
1863     }
1864     if (!pr) {
1865         if (shape.style().applies()) {
1866             shape = shape.applyStyle(GrStyle::Apply::kPathEffectAndStrokeRec, styleScale);
1867             if (shape.isEmpty()) {
1868                 return;
1869             }
1870             // This time, allow SW renderer
1871             pr = this->drawingManager()->getPathRenderer(canDrawArgs, kAllowSWPathRenderer,
1872                                                          DrawType::kColor);
1873         } else {
1874             pr = this->drawingManager()->getSoftwarePathRenderer();
1875 #if GR_PATH_RENDERER_SPEW
1876             SkDebugf("falling back to: %s\n", pr->name());
1877 #endif
1878         }
1879     }
1880 
1881     if (!pr) {
1882 #ifdef SK_DEBUG
1883         SkDebugf("Unable to find path renderer compatible with path.\n");
1884 #endif
1885         return;
1886     }
1887 
1888     PathRenderer::DrawPathArgs args{this->drawingManager()->getContext(),
1889                                     std::move(paint),
1890                                     &GrUserStencilSettings::kUnused,
1891                                     this,
1892                                     clip,
1893                                     &clipConservativeBounds,
1894                                     &viewMatrix,
1895                                     canDrawArgs.fShape,
1896                                     aaType,
1897                                     this->colorInfo().isLinearlyBlended()};
1898     pr->drawPath(args);
1899 }
1900 
addDrawOp(const GrClip* clip, GrOp::Owner op, const std::function<WillAddOpFn>& willAddFn)1901 void SurfaceDrawContext::addDrawOp(const GrClip* clip,
1902                                    GrOp::Owner op,
1903                                    const std::function<WillAddOpFn>& willAddFn) {
1904     ASSERT_SINGLE_OWNER
1905     if (fContext->abandoned()) {
1906         return;
1907     }
1908     GrDrawOp* drawOp = (GrDrawOp*)op.get();
1909     SkDEBUGCODE(this->validate();)
1910     SkDEBUGCODE(drawOp->fAddDrawOpCalled = true;)
1911     GR_CREATE_TRACE_MARKER_CONTEXT("SurfaceDrawContext", "addDrawOp", fContext);
1912 
1913     // Setup clip
1914     SkRect bounds;
1915     op_bounds(&bounds, op.get());
1916     GrAppliedClip appliedClip(this->dimensions(), this->asSurfaceProxy()->backingStoreDimensions());
1917     const bool opUsesMSAA = drawOp->usesMSAA();
1918     bool skipDraw = false;
1919     if (clip) {
1920         // Have a complex clip, so defer to its early clip culling
1921         GrAAType aaType;
1922         if (opUsesMSAA) {
1923             aaType = GrAAType::kMSAA;
1924         } else {
1925             aaType = op->hasAABloat() ? GrAAType::kCoverage : GrAAType::kNone;
1926         }
1927         skipDraw = clip->apply(fContext, this, drawOp, aaType,
1928                                &appliedClip, &bounds) == GrClip::Effect::kClippedOut;
1929     } else {
1930         // No clipping, so just clip the bounds against the logical render target dimensions
1931         skipDraw = !bounds.intersect(this->asSurfaceProxy()->getBoundsRect());
1932     }
1933 
1934     if (skipDraw) {
1935         return;
1936     }
1937 
1938     GrClampType clampType = GrColorTypeClampType(this->colorInfo().colorType());
1939     GrProcessorSet::Analysis analysis = drawOp->finalize(*this->caps(), &appliedClip, clampType);
1940 
1941     const bool opUsesStencil = drawOp->usesStencil();
1942 
1943     // Always trigger DMSAA when there is stencil. This ensures stencil contents get properly
1944     // preserved between render passes, if needed.
1945     const bool drawNeedsMSAA = opUsesMSAA || (fCanUseDynamicMSAA && opUsesStencil);
1946 
1947     // Must be called before setDstProxyView so that it sees the final bounds of the op.
1948     op->setClippedBounds(bounds);
1949 
1950     // Determine if the Op will trigger the use of a separate DMSAA attachment that requires manual
1951     // resolves.
1952     // TODO: Currently usesAttachmentIfDMSAA checks if this is a textureProxy or not. This check is
1953     // really only for GL which uses a normal texture sampling when using barriers. For Vulkan it
1954     // is possible to use the msaa buffer as an input attachment even if this is not a texture.
1955     // However, support for that is not fully implemented yet in Vulkan. Once it is, this check
1956     // should change to a virtual caps check that returns whether we need to break up an OpsTask
1957     // if it has barriers and we are about to promote to MSAA.
1958     bool usesAttachmentIfDMSAA =
1959             fCanUseDynamicMSAA &&
1960             (!this->caps()->msaaResolvesAutomatically() || !this->asTextureProxy());
1961     bool opRequiresDMSAAAttachment = usesAttachmentIfDMSAA && drawNeedsMSAA;
1962     bool opTriggersDMSAAAttachment =
1963             opRequiresDMSAAAttachment && !this->getOpsTask()->usesMSAASurface();
1964     if (opTriggersDMSAAAttachment) {
1965         // This will be the op that actually triggers use of a DMSAA attachment. Texture barriers
1966         // can't be moved to a DMSAA attachment, so if there already are any on the current opsTask
1967         // then we need to split.
1968         if (this->getOpsTask()->renderPassXferBarriers() & GrXferBarrierFlags::kTexture) {
1969             SkASSERT(!this->getOpsTask()->isColorNoOp());
1970             this->replaceOpsTask()->setCannotMergeBackward();
1971         }
1972     }
1973 
1974     GrDstProxyView dstProxyView;
1975     if (analysis.requiresDstTexture()) {
1976         if (!this->setupDstProxyView(drawOp->bounds(), drawNeedsMSAA, &dstProxyView)) {
1977             return;
1978         }
1979 #ifdef SK_DEBUG
1980         if (fCanUseDynamicMSAA && drawNeedsMSAA && !this->caps()->msaaResolvesAutomatically()) {
1981             // Since we aren't literally writing to the render target texture while using a DMSAA
1982             // attachment, we need to resolve that texture before sampling it. Ensure the current
1983             // opsTask got closed off in order to initiate an implicit resolve.
1984             SkASSERT(this->getOpsTask()->isEmpty());
1985         }
1986 #endif
1987     }
1988 
1989     auto opsTask = this->getOpsTask();
1990     if (willAddFn) {
1991         willAddFn(op.get(), opsTask->uniqueID());
1992     }
1993 
1994     // Note if the op needs stencil. Stencil clipping already called setNeedsStencil for itself, if
1995     // needed.
1996     if (opUsesStencil) {
1997         this->setNeedsStencil();
1998     }
1999 
2000 #if GR_GPU_STATS && GR_TEST_UTILS
2001     if (fCanUseDynamicMSAA && drawNeedsMSAA) {
2002         if (!opsTask->usesMSAASurface()) {
2003             fContext->priv().dmsaaStats().fNumMultisampleRenderPasses++;
2004         }
2005         fContext->priv().dmsaaStats().fTriggerCounts[op->name()]++;
2006     }
2007 #endif
2008     auto direct = fContext->priv().asDirectContext();
2009     if (direct && op) {
2010         op->setGrOpTag(direct->getCurrentGrResourceTag());
2011     }
2012     opsTask->addDrawOp(this->drawingManager(), std::move(op), drawNeedsMSAA, analysis,
2013                        std::move(appliedClip), dstProxyView,
2014                        GrTextureResolveManager(this->drawingManager()), *this->caps());
2015 
2016 #ifdef SK_DEBUG
2017     if (fCanUseDynamicMSAA && drawNeedsMSAA) {
2018         SkASSERT(opsTask->usesMSAASurface());
2019     }
2020 #endif
2021 }
2022 
setupDstProxyView(const SkRect& opBounds, bool opRequiresMSAA, GrDstProxyView* dstProxyView)2023 bool SurfaceDrawContext::setupDstProxyView(const SkRect& opBounds,
2024                                            bool opRequiresMSAA,
2025                                            GrDstProxyView* dstProxyView) {
2026     // If we are wrapping a vulkan secondary command buffer, we can't make a dst copy because we
2027     // don't actually have a VkImage to make a copy of. Additionally we don't have the power to
2028     // start and stop the render pass in order to make the copy.
2029     if (this->asRenderTargetProxy()->wrapsVkSecondaryCB()) {
2030         return false;
2031     }
2032 
2033     // First get the dstSampleFlags as if we will put the draw into the current OpsTask
2034     auto dstSampleFlags = this->caps()->getDstSampleFlagsForProxy(
2035             this->asRenderTargetProxy(), this->getOpsTask()->usesMSAASurface() || opRequiresMSAA);
2036 
2037     // If we don't have barriers for this draw then we will definitely be breaking up the OpsTask.
2038     // However, if using dynamic MSAA, the new OpsTask will not have MSAA already enabled on it
2039     // and that may allow us to use texture barriers. So we check if we can use barriers on the new
2040     // ops task and then break it up if so.
2041     if (!(dstSampleFlags & GrDstSampleFlags::kRequiresTextureBarrier) &&
2042         fCanUseDynamicMSAA && this->getOpsTask()->usesMSAASurface() && !opRequiresMSAA) {
2043         auto newFlags =
2044                 this->caps()->getDstSampleFlagsForProxy(this->asRenderTargetProxy(),
2045                                                         false/*=opRequiresMSAA*/);
2046         if (newFlags & GrDstSampleFlags::kRequiresTextureBarrier) {
2047             // We can't have an empty ops task if we are in DMSAA and the ops task already returns
2048             // true for usesMSAASurface.
2049             SkASSERT(!this->getOpsTask()->isColorNoOp());
2050             this->replaceOpsTask()->setCannotMergeBackward();
2051             dstSampleFlags = newFlags;
2052         }
2053     }
2054 
2055     if (dstSampleFlags & GrDstSampleFlags::kRequiresTextureBarrier) {
2056         // If we require a barrier to sample the dst it means we are sampling the RT itself
2057         // either as a texture or input attachment. In this case we don't need to break up the
2058         // OpsTask.
2059         dstProxyView->setProxyView(this->readSurfaceView());
2060         dstProxyView->setOffset(0, 0);
2061         dstProxyView->setDstSampleFlags(dstSampleFlags);
2062         return true;
2063     }
2064     SkASSERT(dstSampleFlags == GrDstSampleFlags::kNone);
2065 
2066     // We are using a different surface from the main color attachment to sample the dst from. If we
2067     // are in DMSAA we can just use the single sampled RT texture itself. Otherwise, we must do a
2068     // copy.
2069     // We do have to check if we ended up here becasue we don't have texture barriers but do have
2070     // msaaResolvesAutomatically (i.e. render-to-msaa-texture). In that case there will be no op or
2071     // barrier between draws to flush the render target before being used as a texture in the next
2072     // draw. So in that case we just fall through to doing a copy.
2073     if (fCanUseDynamicMSAA && opRequiresMSAA && this->asTextureProxy() &&
2074         !this->caps()->msaaResolvesAutomatically() &&
2075         this->caps()->dmsaaResolveCanBeUsedAsTextureInSameRenderPass()) {
2076         this->replaceOpsTaskIfModifiesColor()->setCannotMergeBackward();
2077         dstProxyView->setProxyView(this->readSurfaceView());
2078         dstProxyView->setOffset(0, 0);
2079         dstProxyView->setDstSampleFlags(dstSampleFlags);
2080         return true;
2081     }
2082 
2083     // Now we fallback to doing a copy.
2084 
2085     GrColorType colorType = this->colorInfo().colorType();
2086     // MSAA consideration: When there is support for reading MSAA samples in the shader we could
2087     // have per-sample dst values by making the copy multisampled.
2088     GrCaps::DstCopyRestrictions restrictions = this->caps()->getDstCopyRestrictions(
2089             this->asRenderTargetProxy(), colorType);
2090 
2091     SkIRect copyRect = SkIRect::MakeSize(this->asSurfaceProxy()->backingStoreDimensions());
2092     if (!restrictions.fMustCopyWholeSrc) {
2093         // If we don't need the whole source, restrict to the op's bounds. We add an extra pixel
2094         // of padding to account for AA bloat and the unpredictable rounding of coords near pixel
2095         // centers during rasterization.
2096         SkIRect conservativeDrawBounds = opBounds.roundOut();
2097         conservativeDrawBounds.outset(1, 1);
2098         SkAssertResult(copyRect.intersect(conservativeDrawBounds));
2099     }
2100 
2101     SkIPoint dstOffset;
2102     SkBackingFit fit;
2103     if (restrictions.fRectsMustMatch == GrSurfaceProxy::RectsMustMatch::kYes) {
2104         dstOffset = {0, 0};
2105         fit = SkBackingFit::kExact;
2106     } else {
2107         dstOffset = {copyRect.fLeft, copyRect.fTop};
2108         fit = SkBackingFit::kApprox;
2109     }
2110     auto copy = GrSurfaceProxy::Copy(fContext,
2111                                      this->asSurfaceProxyRef(),
2112                                      this->origin(),
2113                                      GrMipmapped::kNo,
2114                                      copyRect,
2115                                      fit,
2116                                      SkBudgeted::kYes,
2117                                      restrictions.fRectsMustMatch);
2118     SkASSERT(copy);
2119 
2120     dstProxyView->setProxyView({std::move(copy), this->origin(), this->readSwizzle()});
2121     dstProxyView->setOffset(dstOffset);
2122     dstProxyView->setDstSampleFlags(dstSampleFlags);
2123     return true;
2124 }
2125 
replaceOpsTaskIfModifiesColor()2126 OpsTask* SurfaceDrawContext::replaceOpsTaskIfModifiesColor() {
2127     if (!this->getOpsTask()->isColorNoOp()) {
2128         this->replaceOpsTask();
2129     }
2130     return this->getOpsTask();
2131 }
2132 
drawBlurImage(GrSurfaceProxyView proxyView, const SkBlurArg& blurArg)2133 bool SurfaceDrawContext::drawBlurImage(GrSurfaceProxyView proxyView, const SkBlurArg& blurArg)
2134 {
2135     if (!this->caps()->supportsHpsBlur(&proxyView)) {
2136         SK_LOGD("ERROR: check HpsBlur fail.\n");
2137         return false;
2138     }
2139     this->addOp(GrOp::Make<BlurOp>(fContext, std::move(proxyView), blurArg));
2140     return true;
2141 }
2142 
2143 } // namespace skgpu::v1
2144