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