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