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