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