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