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 "GrRenderTargetContext.h"
9 #include "../private/GrAuditTrail.h"
10 #include "../private/SkShadowFlags.h"
11 #include "GrAppliedClip.h"
12 #include "GrBackendSemaphore.h"
13 #include "GrBlurUtils.h"
14 #include "GrCaps.h"
15 #include "GrColor.h"
16 #include "GrContextPriv.h"
17 #include "GrDrawingManager.h"
18 #include "GrFixedClip.h"
19 #include "GrGpuResourcePriv.h"
20 #include "GrMemoryPool.h"
21 #include "GrOpList.h"
22 #include "GrPathRenderer.h"
23 #include "GrQuad.h"
24 #include "GrRecordingContext.h"
25 #include "GrRecordingContextPriv.h"
26 #include "GrRenderTarget.h"
27 #include "GrRenderTargetContextPriv.h"
28 #include "GrResourceProvider.h"
29 #include "GrShape.h"
30 #include "GrStencilAttachment.h"
31 #include "GrStyle.h"
32 #include "GrTracing.h"
33 #include "SkDrawable.h"
34 #include "SkDrawShadowInfo.h"
35 #include "SkGlyphRunPainter.h"
36 #include "SkGr.h"
37 #include "SkLatticeIter.h"
38 #include "SkMatrixPriv.h"
39 #include "SkRRectPriv.h"
40 #include "SkShadowUtils.h"
41 #include "SkSurfacePriv.h"
42 #include "effects/GrRRectEffect.h"
43 #include "effects/GrTextureDomain.h"
44 #include "ops/GrAtlasTextOp.h"
45 #include "ops/GrClearOp.h"
46 #include "ops/GrClearStencilClipOp.h"
47 #include "ops/GrDebugMarkerOp.h"
48 #include "ops/GrDrawableOp.h"
49 #include "ops/GrDrawAtlasOp.h"
50 #include "ops/GrDrawOp.h"
51 #include "ops/GrDrawVerticesOp.h"
52 #include "ops/GrFillRectOp.h"
53 #include "ops/GrAAFillRRectOp.h"
54 #include "ops/GrLatticeOp.h"
55 #include "ops/GrOp.h"
56 #include "ops/GrOvalOpFactory.h"
57 #include "ops/GrRegionOp.h"
58 #include "ops/GrSemaphoreOp.h"
59 #include "ops/GrShadowRRectOp.h"
60 #include "ops/GrStencilPathOp.h"
61 #include "ops/GrStrokeRectOp.h"
62 #include "ops/GrTextureOp.h"
63 #include "text/GrTextContext.h"
64 #include "text/GrTextTarget.h"
65 
66 class GrRenderTargetContext::TextTarget : public GrTextTarget {
67 public:
TextTarget(GrRenderTargetContext * renderTargetContext)68     TextTarget(GrRenderTargetContext* renderTargetContext)
69             : GrTextTarget(renderTargetContext->width(), renderTargetContext->height(),
70                            renderTargetContext->colorSpaceInfo())
71             , fRenderTargetContext(renderTargetContext)
72             , fGlyphPainter{*renderTargetContext}{}
73 
addDrawOp(const GrClip & clip,std::unique_ptr<GrAtlasTextOp> op)74     void addDrawOp(const GrClip& clip, std::unique_ptr<GrAtlasTextOp> op) override {
75         fRenderTargetContext->addDrawOp(clip, std::move(op));
76     }
77 
drawShape(const GrClip & clip,const SkPaint & paint,const SkMatrix & viewMatrix,const GrShape & shape)78     void drawShape(const GrClip& clip, const SkPaint& paint,
79                   const SkMatrix& viewMatrix, const GrShape& shape) override {
80         GrBlurUtils::drawShapeWithMaskFilter(fRenderTargetContext->fContext, fRenderTargetContext,
81                                              clip, paint, viewMatrix, shape);
82     }
83 
makeGrPaint(GrMaskFormat maskFormat,const SkPaint & skPaint,const SkMatrix & viewMatrix,GrPaint * grPaint)84     void makeGrPaint(GrMaskFormat maskFormat, const SkPaint& skPaint, const SkMatrix& viewMatrix,
85                      GrPaint* grPaint) override {
86         auto context = fRenderTargetContext->fContext;
87         const GrColorSpaceInfo& colorSpaceInfo = fRenderTargetContext->colorSpaceInfo();
88         if (kARGB_GrMaskFormat == maskFormat) {
89             SkPaintToGrPaintWithPrimitiveColor(context, colorSpaceInfo, skPaint, grPaint);
90         } else {
91             SkPaintToGrPaint(context, colorSpaceInfo, skPaint, viewMatrix, grPaint);
92         }
93     }
94 
getContext()95     GrRecordingContext* getContext() override {
96         return fRenderTargetContext->fContext;
97     }
98 
glyphPainter()99     SkGlyphRunListPainter* glyphPainter() override {
100         return &fGlyphPainter;
101     }
102 
103 private:
104     GrRenderTargetContext* fRenderTargetContext;
105     SkGlyphRunListPainter fGlyphPainter;
106 
107 };
108 
109 #define ASSERT_OWNED_RESOURCE(R) SkASSERT(!(R) || (R)->getContext() == this->drawingManager()->getContext())
110 #define ASSERT_SINGLE_OWNER \
111     SkDEBUGCODE(GrSingleOwner::AutoEnforce debug_SingleOwner(this->singleOwner());)
112 #define ASSERT_SINGLE_OWNER_PRIV \
113     SkDEBUGCODE(GrSingleOwner::AutoEnforce debug_SingleOwner(fRenderTargetContext->singleOwner());)
114 #define RETURN_IF_ABANDONED        if (fContext->priv().abandoned()) { return; }
115 #define RETURN_IF_ABANDONED_PRIV   if (fRenderTargetContext->fContext->priv().abandoned()) { return; }
116 #define RETURN_FALSE_IF_ABANDONED  if (fContext->priv().abandoned()) { return false; }
117 #define RETURN_FALSE_IF_ABANDONED_PRIV  if (fRenderTargetContext->fContext->priv().abandoned()) { return false; }
118 #define RETURN_NULL_IF_ABANDONED   if (fContext->priv().abandoned()) { return nullptr; }
119 
120 //////////////////////////////////////////////////////////////////////////////
121 
GrChooseAAType(GrAA aa,GrFSAAType fsaaType,GrAllowMixedSamples allowMixedSamples,const GrCaps & caps)122 GrAAType GrChooseAAType(GrAA aa, GrFSAAType fsaaType, GrAllowMixedSamples allowMixedSamples,
123                         const GrCaps& caps) {
124     if (GrAA::kNo == aa) {
125         // On some devices we cannot disable MSAA if it is enabled so we make the AA type reflect
126         // that.
127         if (fsaaType == GrFSAAType::kUnifiedMSAA && !caps.multisampleDisableSupport()) {
128             return GrAAType::kMSAA;
129         }
130         return GrAAType::kNone;
131     }
132     switch (fsaaType) {
133         case GrFSAAType::kNone:
134             return GrAAType::kCoverage;
135         case GrFSAAType::kUnifiedMSAA:
136             return GrAAType::kMSAA;
137         case GrFSAAType::kMixedSamples:
138             return GrAllowMixedSamples::kYes == allowMixedSamples ? GrAAType::kMixedSamples
139                                                                   : GrAAType::kCoverage;
140     }
141     SK_ABORT("Unexpected fsaa type");
142     return GrAAType::kNone;
143 }
144 
145 //////////////////////////////////////////////////////////////////////////////
146 
147 class AutoCheckFlush {
148 public:
AutoCheckFlush(GrDrawingManager * drawingManager)149     AutoCheckFlush(GrDrawingManager* drawingManager) : fDrawingManager(drawingManager) {
150         SkASSERT(fDrawingManager);
151     }
~AutoCheckFlush()152     ~AutoCheckFlush() { fDrawingManager->flushIfNecessary(); }
153 
154 private:
155     GrDrawingManager* fDrawingManager;
156 };
157 
158 // In MDB mode the reffing of the 'getLastOpList' call's result allows in-progress
159 // GrOpLists to be picked up and added to by renderTargetContexts lower in the call
160 // stack. When this occurs with a closed GrOpList, a new one will be allocated
161 // when the renderTargetContext attempts to use it (via getOpList).
GrRenderTargetContext(GrRecordingContext * context,sk_sp<GrRenderTargetProxy> rtp,sk_sp<SkColorSpace> colorSpace,const SkSurfaceProps * surfaceProps,bool managedOpList)162 GrRenderTargetContext::GrRenderTargetContext(GrRecordingContext* context,
163                                              sk_sp<GrRenderTargetProxy> rtp,
164                                              sk_sp<SkColorSpace> colorSpace,
165                                              const SkSurfaceProps* surfaceProps,
166                                              bool managedOpList)
167         : GrSurfaceContext(context, rtp->config(), std::move(colorSpace))
168         , fRenderTargetProxy(std::move(rtp))
169         , fOpList(sk_ref_sp(fRenderTargetProxy->getLastRenderTargetOpList()))
170         , fSurfaceProps(SkSurfacePropsCopyOrDefault(surfaceProps))
171         , fManagedOpList(managedOpList) {
172     if (!context->priv().explicitlyAllocateGPUResources()) {
173         // MDB TODO: to ensure all resources still get allocated in the correct order in the hybrid
174         // world we need to get the correct opList here so that it, in turn, can grab and hold
175         // its rendertarget.
176         this->getRTOpList();
177     }
178 
179     fTextTarget.reset(new TextTarget(this));
180     SkDEBUGCODE(this->validate();)
181 }
182 
183 #ifdef SK_DEBUG
validate() const184 void GrRenderTargetContext::validate() const {
185     SkASSERT(fRenderTargetProxy);
186     fRenderTargetProxy->validate(fContext);
187 
188     if (fOpList && !fOpList->isClosed()) {
189         SkASSERT(fRenderTargetProxy->getLastOpList() == fOpList.get());
190     }
191 }
192 #endif
193 
~GrRenderTargetContext()194 GrRenderTargetContext::~GrRenderTargetContext() {
195     ASSERT_SINGLE_OWNER
196 }
197 
asTextureProxy()198 GrTextureProxy* GrRenderTargetContext::asTextureProxy() {
199     return fRenderTargetProxy->asTextureProxy();
200 }
201 
asTextureProxy() const202 const GrTextureProxy* GrRenderTargetContext::asTextureProxy() const {
203     return fRenderTargetProxy->asTextureProxy();
204 }
205 
asTextureProxyRef()206 sk_sp<GrTextureProxy> GrRenderTargetContext::asTextureProxyRef() {
207     return sk_ref_sp(fRenderTargetProxy->asTextureProxy());
208 }
209 
mipMapped() const210 GrMipMapped GrRenderTargetContext::mipMapped() const {
211     if (const GrTextureProxy* proxy = this->asTextureProxy()) {
212         return proxy->mipMapped();
213     }
214     return GrMipMapped::kNo;
215 }
216 
getRTOpList()217 GrRenderTargetOpList* GrRenderTargetContext::getRTOpList() {
218     ASSERT_SINGLE_OWNER
219     SkDEBUGCODE(this->validate();)
220 
221     if (!fOpList || fOpList->isClosed()) {
222         fOpList = this->drawingManager()->newRTOpList(fRenderTargetProxy.get(), fManagedOpList);
223     }
224 
225     return fOpList.get();
226 }
227 
getOpList()228 GrOpList* GrRenderTargetContext::getOpList() {
229     return this->getRTOpList();
230 }
231 
drawGlyphRunList(const GrClip & clip,const SkMatrix & viewMatrix,const SkGlyphRunList & blob)232 void GrRenderTargetContext::drawGlyphRunList(
233         const GrClip& clip, const SkMatrix& viewMatrix,
234         const SkGlyphRunList& blob) {
235     ASSERT_SINGLE_OWNER
236     RETURN_IF_ABANDONED
237     SkDEBUGCODE(this->validate();)
238     GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "drawGlyphRunList", fContext);
239 
240     // Drawing text can cause us to do inline uploads. This is not supported for wrapped vulkan
241     // secondary command buffers because it would require stopping and starting a render pass which
242     // we don't have access to.
243     if (this->wrapsVkSecondaryCB()) {
244         return;
245     }
246 
247     GrTextContext* atlasTextContext = this->drawingManager()->getTextContext();
248     atlasTextContext->drawGlyphRunList(fContext, fTextTarget.get(), clip, viewMatrix,
249                                        fSurfaceProps, blob);
250 }
251 
discard()252 void GrRenderTargetContext::discard() {
253     ASSERT_SINGLE_OWNER
254     RETURN_IF_ABANDONED
255     SkDEBUGCODE(this->validate();)
256     GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "discard", fContext);
257 
258     AutoCheckFlush acf(this->drawingManager());
259 
260     this->getRTOpList()->discard();
261 }
262 
clear(const SkIRect * rect,const SkPMColor4f & color,CanClearFullscreen canClearFullscreen)263 void GrRenderTargetContext::clear(const SkIRect* rect,
264                                   const SkPMColor4f& color,
265                                   CanClearFullscreen canClearFullscreen) {
266     ASSERT_SINGLE_OWNER
267     RETURN_IF_ABANDONED
268     SkDEBUGCODE(this->validate();)
269     GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "clear", fContext);
270 
271     AutoCheckFlush acf(this->drawingManager());
272     this->internalClear(rect ? GrFixedClip(*rect) : GrFixedClip::Disabled(), color,
273                         canClearFullscreen);
274 }
275 
clear(const GrFixedClip & clip,const SkPMColor4f & color,CanClearFullscreen canClearFullscreen)276 void GrRenderTargetContextPriv::clear(const GrFixedClip& clip,
277                                       const SkPMColor4f& color,
278                                       CanClearFullscreen canClearFullscreen) {
279     ASSERT_SINGLE_OWNER_PRIV
280     RETURN_IF_ABANDONED_PRIV
281     SkDEBUGCODE(fRenderTargetContext->validate();)
282     GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContextPriv", "clear",
283                                    fRenderTargetContext->fContext);
284 
285     AutoCheckFlush acf(fRenderTargetContext->drawingManager());
286     fRenderTargetContext->internalClear(clip, color, canClearFullscreen);
287 }
288 
clear_to_grpaint(const SkPMColor4f & color,GrPaint * paint)289 static void clear_to_grpaint(const SkPMColor4f& color, GrPaint* paint) {
290     paint->setColor4f(color);
291     if (color.isOpaque()) {
292         // Can just rely on the src-over blend mode to do the right thing
293         paint->setPorterDuffXPFactory(SkBlendMode::kSrcOver);
294     } else {
295         // A clear overwrites the prior color, so even if it's transparent, it behaves as if it
296         // were src blended
297         paint->setPorterDuffXPFactory(SkBlendMode::kSrc);
298     }
299 }
300 
internalClear(const GrFixedClip & clip,const SkPMColor4f & color,CanClearFullscreen canClearFullscreen)301 void GrRenderTargetContext::internalClear(const GrFixedClip& clip,
302                                           const SkPMColor4f& color,
303                                           CanClearFullscreen canClearFullscreen) {
304     bool isFull = false;
305     if (!clip.hasWindowRectangles()) {
306         isFull = !clip.scissorEnabled() ||
307                  (CanClearFullscreen::kYes == canClearFullscreen &&
308                   this->caps()->preferFullscreenClears()) ||
309                  clip.scissorRect().contains(SkIRect::MakeWH(this->width(), this->height()));
310     }
311 
312     if (isFull) {
313         if (this->getRTOpList()->resetForFullscreenClear() &&
314             !this->caps()->performColorClearsAsDraws()) {
315             // The op list was emptied and native clears are allowed, so just use the load op
316             this->getRTOpList()->setColorLoadOp(GrLoadOp::kClear, color);
317             return;
318         } else {
319             // Will use an op for the clear, reset the load op to discard since the op will
320             // blow away the color buffer contents
321             this->getRTOpList()->setColorLoadOp(GrLoadOp::kDiscard);
322         }
323 
324         // Must add an op to the list (either because we couldn't use a load op, or because the
325         // clear load op isn't supported)
326         if (this->caps()->performColorClearsAsDraws()) {
327             SkRect rtRect = SkRect::MakeWH(this->width(), this->height());
328             GrPaint paint;
329             clear_to_grpaint(color, &paint);
330             this->addDrawOp(GrFixedClip::Disabled(),
331                             GrFillRectOp::Make(fContext, std::move(paint),
332                                                GrAAType::kNone, SkMatrix::I(), rtRect));
333         } else {
334             this->getRTOpList()->addOp(GrClearOp::Make(fContext, SkIRect::MakeEmpty(), color,
335                                                        /* fullscreen */ true), *this->caps());
336         }
337     } else {
338         if (this->caps()->performPartialClearsAsDraws()) {
339             // performPartialClearsAsDraws() also returns true if any clear has to be a draw.
340             SkRect scissor = SkRect::Make(clip.scissorRect());
341             GrPaint paint;
342             clear_to_grpaint(color, &paint);
343 
344             this->addDrawOp(clip, GrFillRectOp::Make(fContext, std::move(paint), GrAAType::kNone,
345                                                      SkMatrix::I(), scissor));
346         } else {
347             std::unique_ptr<GrOp> op(GrClearOp::Make(fContext, clip, color,
348                                                      this->asSurfaceProxy()));
349             // This version of the clear op factory can return null if the clip doesn't intersect
350             // with the surface proxy's boundary
351             if (!op) {
352                 return;
353             }
354             this->getRTOpList()->addOp(std::move(op), *this->caps());
355         }
356     }
357 }
358 
absClear(const SkIRect * clearRect,const SkPMColor4f & color)359 void GrRenderTargetContextPriv::absClear(const SkIRect* clearRect, const SkPMColor4f& color) {
360     ASSERT_SINGLE_OWNER_PRIV
361     RETURN_IF_ABANDONED_PRIV
362     SkDEBUGCODE(fRenderTargetContext->validate();)
363     GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContextPriv", "absClear",
364                                    fRenderTargetContext->fContext);
365 
366     AutoCheckFlush acf(fRenderTargetContext->drawingManager());
367 
368     SkIRect rtRect = SkIRect::MakeWH(fRenderTargetContext->fRenderTargetProxy->worstCaseWidth(),
369                                      fRenderTargetContext->fRenderTargetProxy->worstCaseHeight());
370 
371     if (clearRect) {
372         if (clearRect->contains(rtRect)) {
373             clearRect = nullptr; // full screen
374         } else {
375             if (!rtRect.intersect(*clearRect)) {
376                 return;
377             }
378         }
379     }
380 
381     // TODO: in a post-MDB world this should be handled at the OpList level.
382     // This makes sure to always add an op to the list, instead of marking the clear as a load op.
383     // This code follows very similar logic to internalClear() below, but critical differences are
384     // highlighted in line related to absClear()'s unique behavior.
385     if (clearRect) {
386         if (fRenderTargetContext->caps()->performPartialClearsAsDraws()) {
387             GrPaint paint;
388             clear_to_grpaint(color, &paint);
389 
390             // Use the disabled clip; the rect geometry already matches the clear rectangle and
391             // if it were added to a scissor, that would be intersected with the logical surface
392             // bounds and not the worst case dimensions required here.
393             fRenderTargetContext->addDrawOp(GrFixedClip::Disabled(),
394                                             GrFillRectOp::Make(fRenderTargetContext->fContext,
395                                                                std::move(paint),
396                                                                GrAAType::kNone,
397                                                                SkMatrix::I(),
398                                                                SkRect::Make(rtRect)));
399         } else {
400             // Must use the ClearOp factory that takes a boolean (false) instead of a surface
401             // proxy. The surface proxy variant would intersect the clip rect with its logical
402             // bounds, which is not desired in this special case.
403             fRenderTargetContext->getRTOpList()->addOp(
404                     GrClearOp::Make(fRenderTargetContext->fContext, rtRect, color,
405                                     /* fullscreen */ false),
406                     *fRenderTargetContext->caps());
407         }
408     } else {
409         // Reset the oplist like in internalClear(), but do not rely on a load op for the clear
410         fRenderTargetContext->getRTOpList()->resetForFullscreenClear();
411         fRenderTargetContext->getRTOpList()->setColorLoadOp(GrLoadOp::kDiscard);
412 
413         if (fRenderTargetContext->caps()->performColorClearsAsDraws()) {
414             // This draws a quad covering the worst case dimensions instead of just the logical
415             // width and height like in internalClear().
416             GrPaint paint;
417             clear_to_grpaint(color, &paint);
418             fRenderTargetContext->addDrawOp(GrFixedClip::Disabled(),
419                                             GrFillRectOp::Make(fRenderTargetContext->fContext,
420                                                                std::move(paint),
421                                                                GrAAType::kNone,
422                                                                SkMatrix::I(),
423                                                                SkRect::Make(rtRect)));
424         } else {
425             // Nothing special about this path in absClear compared to internalClear()
426             fRenderTargetContext->getRTOpList()->addOp(
427                     GrClearOp::Make(fRenderTargetContext->fContext, SkIRect::MakeEmpty(), color,
428                                     /* fullscreen */ true),
429                     *fRenderTargetContext->caps());
430         }
431     }
432 }
433 
drawPaint(const GrClip & clip,GrPaint && paint,const SkMatrix & viewMatrix)434 void GrRenderTargetContext::drawPaint(const GrClip& clip,
435                                       GrPaint&& paint,
436                                       const SkMatrix& viewMatrix) {
437     ASSERT_SINGLE_OWNER
438     RETURN_IF_ABANDONED
439     SkDEBUGCODE(this->validate();)
440     GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "drawPaint", fContext);
441 
442     // set rect to be big enough to fill the space, but not super-huge, so we
443     // don't overflow fixed-point implementations
444 
445     SkRect r = fRenderTargetProxy->getBoundsRect();
446 
447     // Check if we can optimize a clipped drawPaint(). We only do the transformation when there are
448     // no fragment processors because they may depend on having correct local coords and this path
449     // draws in device space without a local matrix. It currently handles converting clipRRect()
450     // to drawRRect() and solid colors to screen-filling drawRects() (which are then converted into
451     // clears if possible in drawRect).
452     if (!paint.numTotalFragmentProcessors()) {
453         SkRRect rrect;
454         GrAA aa = GrAA::kNo;
455         if (clip.isRRect(r, &rrect, &aa)) {
456             if (rrect.isRect()) {
457                 // Use drawFilledRect() with no clip and the reduced rectangle
458                 this->drawFilledRect(GrNoClip(), std::move(paint), aa, SkMatrix::I(), rrect.rect());
459             } else {
460                 // Use drawRRect() with no clip
461                 this->drawRRect(GrNoClip(), std::move(paint), aa, SkMatrix::I(), rrect,
462                                 GrStyle::SimpleFill());
463             }
464         } else {
465             // Use drawFilledRect() with no view matrix to draw a fullscreen quad, but preserve
466             // the clip. Since the paint has no FPs we can drop the view matrix without worrying
467             // about local coordinates. If the clip is simple, drawFilledRect() will turn this into
468             // a clear or a scissored clear.
469             this->drawFilledRect(clip, std::move(paint), aa, SkMatrix::I(), r);
470         }
471         return;
472     }
473 
474     // Since the paint is not trivial, there's no way at this point drawRect() could have converted
475     // this drawPaint() into an optimized clear. drawRect() would then use GrFillRectOp without
476     // a local matrix, so we can simplify things and use the local matrix variant to draw a screen
477     // filling rect with the inverse view matrix for local coords, which works for all matrix
478     // conditions.
479     SkMatrix localMatrix;
480     if (!viewMatrix.invert(&localMatrix)) {
481         return;
482     }
483 
484     AutoCheckFlush acf(this->drawingManager());
485     std::unique_ptr<GrDrawOp> op = GrFillRectOp::MakeWithLocalMatrix(
486             fContext, std::move(paint), GrAAType::kNone, SkMatrix::I(), localMatrix, r);
487     this->addDrawOp(clip, std::move(op));
488 }
489 
rect_contains_inclusive(const SkRect & rect,const SkPoint & point)490 static inline bool rect_contains_inclusive(const SkRect& rect, const SkPoint& point) {
491     return point.fX >= rect.fLeft && point.fX <= rect.fRight &&
492            point.fY >= rect.fTop && point.fY <= rect.fBottom;
493 }
494 
495 // Attempts to crop a rect and optional local rect to the clip boundaries.
496 // Returns false if the draw can be skipped entirely.
crop_filled_rect(int width,int height,const GrClip & clip,const SkMatrix & viewMatrix,SkRect * rect,SkRect * localRect=nullptr)497 static bool crop_filled_rect(int width, int height, const GrClip& clip,
498                              const SkMatrix& viewMatrix, SkRect* rect,
499                              SkRect* localRect = nullptr) {
500     if (!viewMatrix.rectStaysRect()) {
501         return true;
502     }
503 
504     SkIRect clipDevBounds;
505     SkRect clipBounds;
506 
507     clip.getConservativeBounds(width, height, &clipDevBounds);
508     if (!SkMatrixPriv::InverseMapRect(viewMatrix, &clipBounds, SkRect::Make(clipDevBounds))) {
509         return false;
510     }
511 
512     if (localRect) {
513         if (!rect->intersects(clipBounds)) {
514             return false;
515         }
516         const SkScalar dx = localRect->width() / rect->width();
517         const SkScalar dy = localRect->height() / rect->height();
518         if (clipBounds.fLeft > rect->fLeft) {
519             localRect->fLeft += (clipBounds.fLeft - rect->fLeft) * dx;
520             rect->fLeft = clipBounds.fLeft;
521         }
522         if (clipBounds.fTop > rect->fTop) {
523             localRect->fTop += (clipBounds.fTop - rect->fTop) * dy;
524             rect->fTop = clipBounds.fTop;
525         }
526         if (clipBounds.fRight < rect->fRight) {
527             localRect->fRight -= (rect->fRight - clipBounds.fRight) * dx;
528             rect->fRight = clipBounds.fRight;
529         }
530         if (clipBounds.fBottom < rect->fBottom) {
531             localRect->fBottom -= (rect->fBottom - clipBounds.fBottom) * dy;
532             rect->fBottom = clipBounds.fBottom;
533         }
534         return true;
535     }
536 
537     return rect->intersect(clipBounds);
538 }
539 
drawFilledRectAsClear(const GrClip & clip,GrPaint && paint,GrAA aa,const SkMatrix & viewMatrix,const SkRect & rect)540 bool GrRenderTargetContext::drawFilledRectAsClear(const GrClip& clip, GrPaint&& paint, GrAA aa,
541                                                   const SkMatrix& viewMatrix, const SkRect& rect) {
542     // Rules for a filled rect to become a clear [+scissor]:
543     // 1. The paint is a constant blend color with no other FPs
544     // 2. The view matrix maps rectangles to rectangles, or the transformed quad fully covers
545     //    the render target (or clear region in #3).
546     // 3. The clip is an intersection of rectangles, so the clear region will be the
547     //    intersection of the clip and the provided rect.
548     // 4. The clear region aligns with pixel bounds
549     // 5. There are no user stencil settings (and since the clip was IOR, the clip won't need
550     //    to use the stencil either).
551     // If all conditions pass, the filled rect can either be a fullscreen clear (if it's big
552     // enough), or the rectangle geometry will be used as the scissor clip on the clear.
553     // If everything passes but rule #4, this submits a simplified fill rect op instead so that the
554     // rounding differences between clip and draws don't fight each other.
555     // NOTE: we route draws into clear() regardless of performColorClearsAsDraws() since the
556     // clear call is allowed to reset the oplist even when it also happens to use a GrFillRectOp.
557 
558     SkPMColor4f clearColor;
559     if (paint.numCoverageFragmentProcessors() > 0 || !paint.isConstantBlendedColor(&clearColor)) {
560         return false;
561     }
562 
563     const SkRect rtRect = fRenderTargetProxy->getBoundsRect();
564     // Will be the intersection of render target, clip, and quad
565     SkRect combinedRect = rtRect;
566 
567     SkRRect clipRRect;
568     GrAA clipAA;
569     if (!clip.quickContains(rtRect)) {
570         // If the clip is an rrect with no rounding, then it can replace the full RT bounds as the
571         // limiting region, although we will have to worry about AA. If the clip is anything
572         // more complicated, just punt to the regular fill rect op.
573         if (!clip.isRRect(rtRect, &clipRRect, &clipAA) || !clipRRect.isRect()) {
574             return false;
575         }
576         combinedRect = clipRRect.rect();
577     } else {
578         // The clip is outside the render target, so the clip can be ignored
579         clipAA = GrAA::kNo;
580     }
581 
582     if (viewMatrix.rectStaysRect()) {
583         // Skip the extra overhead of inverting the view matrix to see if rtRect is contained in the
584         // drawn rectangle, and instead just intersect rtRect with the transformed rect. It will be
585         // the new clear region.
586         if (!combinedRect.intersect(viewMatrix.mapRect(rect))) {
587             // No intersection means nothing should be drawn, so return true but don't add an op
588             return true;
589         }
590     } else {
591         // If the transformed rectangle does not contain the combined rt and clip, the draw is too
592         // complex to be implemented as a clear
593         SkMatrix invM;
594         if (!viewMatrix.invert(&invM)) {
595             return false;
596         }
597         // The clip region in the rect's local space, so the test becomes the local rect containing
598         // the quad's points.
599         GrQuad quad = GrQuad::MakeFromRect(rtRect, invM);
600         if (!rect_contains_inclusive(rect, quad.point(0)) ||
601             !rect_contains_inclusive(rect, quad.point(1)) ||
602             !rect_contains_inclusive(rect, quad.point(2)) ||
603             !rect_contains_inclusive(rect, quad.point(3))) {
604             // No containment, so rtRect can't be filled by a solid color
605             return false;
606         }
607         // combinedRect can be filled by a solid color but doesn't need to be modified since it's
608         // inside the quad to be drawn.
609     }
610 
611     // Almost every condition is met; now it requires that the combined rect align with pixel
612     // boundaries in order for it to become a scissor-clear. Ignore the AA status in this case
613     // since non-AA with partial-pixel coordinates can be rounded differently on the GPU,
614     // leading to unexpected differences between a scissor test and a rasterized quad.
615     // Also skip very small rectangles since the scissor+clear doesn't by us much then.
616     if (combinedRect.contains(rtRect)) {
617         // Full screen clear
618         this->clear(nullptr, clearColor, CanClearFullscreen::kYes);
619         return true;
620     } else if (GrClip::IsPixelAligned(combinedRect) &&
621                combinedRect.width() > 256 && combinedRect.height() > 256) {
622         // Scissor + clear (round shouldn't do anything since we are pixel aligned)
623         SkIRect scissorRect;
624         combinedRect.round(&scissorRect);
625         this->clear(&scissorRect, clearColor, CanClearFullscreen::kNo);
626         return true;
627     }
628 
629     // If we got here, we can't use a scissor + clear, but combinedRect represents the correct
630     // geometry combination of quad + clip so we can perform a simplified fill rect op. We do this
631     // mostly to avoid mismatches in rounding logic on the CPU vs. the GPU, which frequently appears
632     // when drawing and clipping something to the same non-AA rect that never-the-less has
633     // non-integer coordinates.
634 
635     // For AA, use non-AA only when both clip and draw are non-AA.
636     if (clipAA == GrAA::kYes) {
637         aa = GrAA::kYes;
638     }
639     GrAAType aaType = this->chooseAAType(aa, GrAllowMixedSamples::kNo);
640     this->addDrawOp(GrFixedClip::Disabled(),
641                     GrFillRectOp::Make(fContext, std::move(paint), aaType, SkMatrix::I(),
642                                        combinedRect));
643     return true;
644 }
645 
drawFilledRect(const GrClip & clip,GrPaint && paint,GrAA aa,const SkMatrix & viewMatrix,const SkRect & rect,const GrUserStencilSettings * ss)646 void GrRenderTargetContext::drawFilledRect(const GrClip& clip,
647                                            GrPaint&& paint,
648                                            GrAA aa,
649                                            const SkMatrix& viewMatrix,
650                                            const SkRect& rect,
651                                            const GrUserStencilSettings* ss) {
652 
653     if (!ss) {
654         if (this->drawFilledRectAsClear(clip, std::move(paint), aa, viewMatrix, rect)) {
655             return;
656         }
657         // Fall through to fill rect op
658         assert_alive(paint);
659     }
660 
661     SkRect croppedRect = rect;
662     if (!crop_filled_rect(this->width(), this->height(), clip, viewMatrix, &croppedRect)) {
663         // The rectangle would not be drawn, so no need to add a draw op to the list
664         return;
665     }
666 
667     GrAAType aaType = this->chooseAAType(aa, GrAllowMixedSamples::kNo);
668     this->addDrawOp(clip, GrFillRectOp::Make(fContext, std::move(paint), aaType, viewMatrix,
669                                              croppedRect, ss));
670 }
671 
drawRect(const GrClip & clip,GrPaint && paint,GrAA aa,const SkMatrix & viewMatrix,const SkRect & rect,const GrStyle * style)672 void GrRenderTargetContext::drawRect(const GrClip& clip,
673                                      GrPaint&& paint,
674                                      GrAA aa,
675                                      const SkMatrix& viewMatrix,
676                                      const SkRect& rect,
677                                      const GrStyle* style) {
678     if (!style) {
679         style = &GrStyle::SimpleFill();
680     }
681     ASSERT_SINGLE_OWNER
682     RETURN_IF_ABANDONED
683     SkDEBUGCODE(this->validate();)
684     GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "drawRect", fContext);
685 
686     // Path effects should've been devolved to a path in SkGpuDevice
687     SkASSERT(!style->pathEffect());
688 
689     AutoCheckFlush acf(this->drawingManager());
690 
691     const SkStrokeRec& stroke = style->strokeRec();
692     if (stroke.getStyle() == SkStrokeRec::kFill_Style) {
693         this->drawFilledRect(clip, std::move(paint), aa, viewMatrix, rect);
694         return;
695     } else if (stroke.getStyle() == SkStrokeRec::kStroke_Style ||
696                stroke.getStyle() == SkStrokeRec::kHairline_Style) {
697         if ((!rect.width() || !rect.height()) &&
698             SkStrokeRec::kHairline_Style != stroke.getStyle()) {
699             SkScalar r = stroke.getWidth() / 2;
700             // TODO: Move these stroke->fill fallbacks to GrShape?
701             switch (stroke.getJoin()) {
702                 case SkPaint::kMiter_Join:
703                     this->drawRect(
704                             clip, std::move(paint), aa, viewMatrix,
705                             {rect.fLeft - r, rect.fTop - r, rect.fRight + r, rect.fBottom + r},
706                             &GrStyle::SimpleFill());
707                     return;
708                 case SkPaint::kRound_Join:
709                     // Raster draws nothing when both dimensions are empty.
710                     if (rect.width() || rect.height()){
711                         SkRRect rrect = SkRRect::MakeRectXY(rect.makeOutset(r, r), r, r);
712                         this->drawRRect(clip, std::move(paint), aa, viewMatrix, rrect,
713                                         GrStyle::SimpleFill());
714                         return;
715                     }
716                 case SkPaint::kBevel_Join:
717                     if (!rect.width()) {
718                         this->drawRect(clip, std::move(paint), aa, viewMatrix,
719                                        {rect.fLeft - r, rect.fTop, rect.fRight + r, rect.fBottom},
720                                        &GrStyle::SimpleFill());
721                     } else {
722                         this->drawRect(clip, std::move(paint), aa, viewMatrix,
723                                        {rect.fLeft, rect.fTop - r, rect.fRight, rect.fBottom + r},
724                                        &GrStyle::SimpleFill());
725                     }
726                     return;
727                 }
728         }
729 
730         std::unique_ptr<GrDrawOp> op;
731 
732         GrAAType aaType = this->chooseAAType(aa, GrAllowMixedSamples::kNo);
733         op = GrStrokeRectOp::Make(fContext, std::move(paint), aaType, viewMatrix, rect, stroke);
734         // op may be null if the stroke is not supported or if using coverage aa and the view matrix
735         // does not preserve rectangles.
736         if (op) {
737             this->addDrawOp(clip, std::move(op));
738             return;
739         }
740     }
741     assert_alive(paint);
742     this->drawShapeUsingPathRenderer(clip, std::move(paint), aa, viewMatrix, GrShape(rect, *style));
743 }
744 
drawQuadSet(const GrClip & clip,GrPaint && paint,GrAA aa,const SkMatrix & viewMatrix,const QuadSetEntry quads[],int cnt)745 void GrRenderTargetContext::drawQuadSet(const GrClip& clip, GrPaint&& paint, GrAA aa,
746                                         const SkMatrix& viewMatrix, const QuadSetEntry quads[],
747                                         int cnt) {
748     GrAAType aaType = this->chooseAAType(aa, GrAllowMixedSamples::kNo);
749     this->addDrawOp(clip, GrFillRectOp::MakeSet(fContext, std::move(paint), aaType, viewMatrix,
750                                                 quads, cnt));
751 }
752 
maxWindowRectangles() const753 int GrRenderTargetContextPriv::maxWindowRectangles() const {
754     return fRenderTargetContext->fRenderTargetProxy->maxWindowRectangles(
755             *fRenderTargetContext->caps());
756 }
757 
clearStencilClip(const GrFixedClip & clip,bool insideStencilMask)758 void GrRenderTargetContextPriv::clearStencilClip(const GrFixedClip& clip, bool insideStencilMask) {
759     ASSERT_SINGLE_OWNER_PRIV
760     RETURN_IF_ABANDONED_PRIV
761     SkDEBUGCODE(fRenderTargetContext->validate();)
762     GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContextPriv", "clearStencilClip",
763                                    fRenderTargetContext->fContext);
764 
765     AutoCheckFlush acf(fRenderTargetContext->drawingManager());
766 
767     fRenderTargetContext->internalStencilClear(clip, insideStencilMask);
768 }
769 
internalStencilClear(const GrFixedClip & clip,bool insideStencilMask)770 void GrRenderTargetContext::internalStencilClear(const GrFixedClip& clip, bool insideStencilMask) {
771     if (this->caps()->performStencilClearsAsDraws()) {
772         const GrUserStencilSettings* ss = GrStencilSettings::SetClipBitSettings(insideStencilMask);
773         SkRect rtRect = SkRect::MakeWH(this->width(), this->height());
774 
775         // Configure the paint to have no impact on the color buffer
776         GrPaint paint;
777         paint.setColor4f({0.f, 0.f, 0.f, 0.f});
778         paint.setPorterDuffXPFactory(SkBlendMode::kSrcOver);
779 
780         // Mark stencil usage here before addDrawOp() so that it doesn't try to re-call
781         // internalStencilClear() just because the op has stencil settings.
782         this->setNeedsStencil();
783         this->addDrawOp(clip, GrFillRectOp::Make(fContext, std::move(paint),
784                         GrAAType::kNone, SkMatrix::I(), rtRect, ss));
785     } else {
786         std::unique_ptr<GrOp> op(GrClearStencilClipOp::Make(fContext, clip, insideStencilMask,
787                                                             fRenderTargetProxy.get()));
788         if (!op) {
789             return;
790         }
791         this->getRTOpList()->addOp(std::move(op), *this->caps());
792     }
793 }
794 
stencilPath(const GrHardClip & clip,GrAAType aaType,const SkMatrix & viewMatrix,const GrPath * path)795 void GrRenderTargetContextPriv::stencilPath(const GrHardClip& clip,
796                                             GrAAType aaType,
797                                             const SkMatrix& viewMatrix,
798                                             const GrPath* path) {
799     ASSERT_SINGLE_OWNER_PRIV
800     RETURN_IF_ABANDONED_PRIV
801     SkDEBUGCODE(fRenderTargetContext->validate();)
802     GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContextPriv", "stencilPath",
803                                    fRenderTargetContext->fContext);
804 
805     SkASSERT(aaType != GrAAType::kCoverage);
806 
807     bool useHWAA = GrAATypeIsHW(aaType);
808     // TODO: extract portions of checkDraw that are relevant to path stenciling.
809     SkASSERT(path);
810     SkASSERT(fRenderTargetContext->caps()->shaderCaps()->pathRenderingSupport());
811 
812     // FIXME: Use path bounds instead of this WAR once
813     // https://bugs.chromium.org/p/skia/issues/detail?id=5640 is resolved.
814     SkRect bounds = SkRect::MakeIWH(fRenderTargetContext->width(), fRenderTargetContext->height());
815 
816     // Setup clip
817     GrAppliedHardClip appliedClip;
818     if (!clip.apply(fRenderTargetContext->width(), fRenderTargetContext->height(), &appliedClip,
819                     &bounds)) {
820         return;
821     }
822 
823     fRenderTargetContext->setNeedsStencil();
824 
825     std::unique_ptr<GrOp> op = GrStencilPathOp::Make(fRenderTargetContext->fContext,
826                                                      viewMatrix,
827                                                      useHWAA,
828                                                      path->getFillType(),
829                                                      appliedClip.hasStencilClip(),
830                                                      appliedClip.scissorState(),
831                                                      path);
832     if (!op) {
833         return;
834     }
835     op->setClippedBounds(bounds);
836     fRenderTargetContext->getRTOpList()->addOp(std::move(op), *fRenderTargetContext->caps());
837 }
838 
stencilRect(const GrHardClip & clip,const GrUserStencilSettings * ss,GrAAType aaType,const SkMatrix & viewMatrix,const SkRect & rect)839 void GrRenderTargetContextPriv::stencilRect(const GrHardClip& clip,
840                                             const GrUserStencilSettings* ss,
841                                             GrAAType aaType,
842                                             const SkMatrix& viewMatrix,
843                                             const SkRect& rect) {
844     ASSERT_SINGLE_OWNER_PRIV
845     RETURN_IF_ABANDONED_PRIV
846     SkDEBUGCODE(fRenderTargetContext->validate();)
847     GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContextPriv", "stencilRect",
848                                    fRenderTargetContext->fContext);
849 
850     SkASSERT(GrAAType::kCoverage != aaType);
851     AutoCheckFlush acf(fRenderTargetContext->drawingManager());
852 
853     GrPaint paint;
854     paint.setXPFactory(GrDisableColorXPFactory::Get());
855     std::unique_ptr<GrDrawOp> op = GrFillRectOp::Make(
856             fRenderTargetContext->fContext, std::move(paint), aaType, viewMatrix,  rect, ss);
857     fRenderTargetContext->addDrawOp(clip, std::move(op));
858 }
859 
drawAndStencilRect(const GrHardClip & clip,const GrUserStencilSettings * ss,SkRegion::Op op,bool invert,GrAA aa,const SkMatrix & viewMatrix,const SkRect & rect)860 bool GrRenderTargetContextPriv::drawAndStencilRect(const GrHardClip& clip,
861                                                    const GrUserStencilSettings* ss,
862                                                    SkRegion::Op op,
863                                                    bool invert,
864                                                    GrAA aa,
865                                                    const SkMatrix& viewMatrix,
866                                                    const SkRect& rect) {
867     ASSERT_SINGLE_OWNER_PRIV
868     RETURN_FALSE_IF_ABANDONED_PRIV
869     SkDEBUGCODE(fRenderTargetContext->validate();)
870     GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContextPriv", "drawAndStencilRect",
871                                    fRenderTargetContext->fContext);
872 
873     AutoCheckFlush acf(fRenderTargetContext->drawingManager());
874 
875     GrPaint paint;
876     paint.setCoverageSetOpXPFactory(op, invert);
877 
878     // This will always succeed to draw a rectangle
879     fRenderTargetContext->drawFilledRect(clip, std::move(paint), aa, viewMatrix, rect, ss);
880     return true;
881 }
882 
fillRectWithEdgeAA(const GrClip & clip,GrPaint && paint,GrAA aa,GrQuadAAFlags edgeAA,const SkMatrix & viewMatrix,const SkRect & rect,const SkRect * localRect)883 void GrRenderTargetContext::fillRectWithEdgeAA(const GrClip& clip, GrPaint&& paint, GrAA aa,
884                                                GrQuadAAFlags edgeAA, const SkMatrix& viewMatrix,
885                                                const SkRect& rect, const SkRect* localRect) {
886     ASSERT_SINGLE_OWNER
887     RETURN_IF_ABANDONED
888     SkDEBUGCODE(this->validate();)
889     GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "fillRectWithEdgeAA", fContext);
890 
891     GrAAType aaType = this->chooseAAType(aa, GrAllowMixedSamples::kNo);
892     std::unique_ptr<GrDrawOp> op;
893 
894     if (localRect) {
895         // If local coordinates are provided, skip the optimization check to go through
896         // drawFilledRect, and also calculate clipped local coordinates
897         SkRect croppedRect = rect;
898         SkRect croppedLocalRect = *localRect;
899         if (!crop_filled_rect(this->width(), this->height(), clip, viewMatrix, &croppedRect,
900                               &croppedLocalRect)) {
901             return;
902         }
903         op = GrFillRectOp::MakePerEdgeWithLocalRect(fContext, std::move(paint), aaType, edgeAA,
904                                                     viewMatrix, croppedRect, croppedLocalRect);
905     } else {
906         // If aaType turns into MSAA, make sure to keep quads with no AA edges as MSAA. Sending
907         // those to drawFilledRect() would have it turn off MSAA in that case, which breaks seaming
908         // with any partial AA edges that kept MSAA.
909         if (aaType != GrAAType::kMSAA &&
910             (edgeAA == GrQuadAAFlags::kNone || edgeAA == GrQuadAAFlags::kAll)) {
911             // This is equivalent to a regular filled rect draw, so route through there to take
912             // advantage of draw->clear optimizations
913             this->drawFilledRect(clip, std::move(paint), GrAA(edgeAA == GrQuadAAFlags::kAll),
914                                  viewMatrix, rect);
915             return;
916         }
917 
918         SkRect croppedRect = rect;
919         if (!crop_filled_rect(this->width(), this->height(), clip, viewMatrix, &croppedRect)) {
920             return;
921         }
922         op = GrFillRectOp::MakePerEdge(fContext, std::move(paint), aaType, edgeAA, viewMatrix,
923                                        croppedRect);
924     }
925 
926     AutoCheckFlush acf(this->drawingManager());
927     this->addDrawOp(clip, std::move(op));
928 }
929 
fillQuadWithEdgeAA(const GrClip & clip,GrPaint && paint,GrAA aa,GrQuadAAFlags edgeAA,const SkMatrix & viewMatrix,const SkPoint quad[4],const SkPoint localQuad[4])930 void GrRenderTargetContext::fillQuadWithEdgeAA(const GrClip& clip, GrPaint&& paint, GrAA aa,
931                                                GrQuadAAFlags edgeAA, const SkMatrix& viewMatrix,
932                                                const SkPoint quad[4], const SkPoint localQuad[4]) {
933     ASSERT_SINGLE_OWNER
934     RETURN_IF_ABANDONED
935     SkDEBUGCODE(this->validate();)
936     GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "fillQuadWithEdgeAA", fContext);
937 
938     GrAAType aaType = this->chooseAAType(aa, GrAllowMixedSamples::kNo);
939 
940     AutoCheckFlush acf(this->drawingManager());
941     // MakePerEdgeQuad automatically does the right thing if localQuad is null or not
942     this->addDrawOp(clip, GrFillRectOp::MakePerEdgeQuad(fContext, std::move(paint), aaType, edgeAA,
943                                                         viewMatrix, quad, localQuad));
944 }
945 
946 // Creates a paint for GrFillRectOp that matches behavior of GrTextureOp
draw_texture_to_grpaint(sk_sp<GrTextureProxy> proxy,const SkRect * domain,GrSamplerState::Filter filter,SkBlendMode mode,const SkPMColor4f & color,sk_sp<GrColorSpaceXform> csXform,GrPaint * paint)947 static void draw_texture_to_grpaint(sk_sp<GrTextureProxy> proxy, const SkRect* domain,
948                                     GrSamplerState::Filter filter, SkBlendMode mode,
949                                     const SkPMColor4f& color, sk_sp<GrColorSpaceXform> csXform,
950                                     GrPaint* paint) {
951     paint->setColor4f(color);
952     paint->setXPFactory(SkBlendMode_AsXPFactory(mode));
953 
954     std::unique_ptr<GrFragmentProcessor> fp;
955     if (domain) {
956         SkRect correctedDomain = *domain;
957         if (filter == GrSamplerState::Filter::kBilerp) {
958             // Inset by 1/2 pixel, which GrTextureOp and GrTextureAdjuster handle automatically
959             correctedDomain.inset(0.5f, 0.5f);
960         }
961         fp = GrTextureDomainEffect::Make(std::move(proxy), SkMatrix::I(), correctedDomain,
962                                          GrTextureDomain::kClamp_Mode, filter);
963     } else {
964         fp = GrSimpleTextureEffect::Make(std::move(proxy), SkMatrix::I(), filter);
965     }
966 
967     fp = GrColorSpaceXformEffect::Make(std::move(fp), csXform);
968     paint->addColorFragmentProcessor(std::move(fp));
969 }
970 
drawTexture(const GrClip & clip,sk_sp<GrTextureProxy> proxy,GrSamplerState::Filter filter,SkBlendMode mode,const SkPMColor4f & color,const SkRect & srcRect,const SkRect & dstRect,GrAA aa,GrQuadAAFlags aaFlags,SkCanvas::SrcRectConstraint constraint,const SkMatrix & viewMatrix,sk_sp<GrColorSpaceXform> textureColorSpaceXform)971 void GrRenderTargetContext::drawTexture(const GrClip& clip, sk_sp<GrTextureProxy> proxy,
972                                         GrSamplerState::Filter filter, SkBlendMode mode,
973                                         const SkPMColor4f& color, const SkRect& srcRect,
974                                         const SkRect& dstRect, GrAA aa, GrQuadAAFlags aaFlags,
975                                         SkCanvas::SrcRectConstraint constraint,
976                                         const SkMatrix& viewMatrix,
977                                         sk_sp<GrColorSpaceXform> textureColorSpaceXform) {
978     ASSERT_SINGLE_OWNER
979     RETURN_IF_ABANDONED
980     SkDEBUGCODE(this->validate();)
981     GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "drawTexture", fContext);
982     if (constraint == SkCanvas::kStrict_SrcRectConstraint &&
983         srcRect.contains(proxy->getWorstCaseBoundsRect())) {
984         constraint = SkCanvas::kFast_SrcRectConstraint;
985     }
986 
987     GrAAType aaType = this->chooseAAType(aa, GrAllowMixedSamples::kNo);
988     SkRect clippedDstRect = dstRect;
989     SkRect clippedSrcRect = srcRect;
990     if (!crop_filled_rect(this->width(), this->height(), clip, viewMatrix, &clippedDstRect,
991                           &clippedSrcRect)) {
992         return;
993     }
994 
995     AutoCheckFlush acf(this->drawingManager());
996 
997     std::unique_ptr<GrDrawOp> op;
998     if (mode != SkBlendMode::kSrcOver) {
999         // Emulation mode with GrPaint and GrFillRectOp
1000         if (filter != GrSamplerState::Filter::kNearest &&
1001             !GrTextureOp::GetFilterHasEffect(viewMatrix, clippedSrcRect, clippedDstRect)) {
1002             filter = GrSamplerState::Filter::kNearest;
1003         }
1004 
1005         GrPaint paint;
1006         draw_texture_to_grpaint(std::move(proxy),
1007                 constraint == SkCanvas::kStrict_SrcRectConstraint ? &srcRect : nullptr,
1008                 filter, mode, color, std::move(textureColorSpaceXform), &paint);
1009         op = GrFillRectOp::MakePerEdgeWithLocalRect(fContext, std::move(paint), aaType, aaFlags,
1010                                                     viewMatrix, clippedDstRect, clippedSrcRect);
1011     } else {
1012         // Can use a lighter weight op that can chain across proxies
1013         op = GrTextureOp::Make(fContext, std::move(proxy), filter, color, clippedSrcRect,
1014                                clippedDstRect, aaType, aaFlags, constraint, viewMatrix,
1015                                std::move(textureColorSpaceXform));
1016     }
1017 
1018     this->addDrawOp(clip, std::move(op));
1019 }
1020 
drawTextureQuad(const GrClip & clip,sk_sp<GrTextureProxy> proxy,GrSamplerState::Filter filter,SkBlendMode mode,const SkPMColor4f & color,const SkPoint srcQuad[4],const SkPoint dstQuad[4],GrAA aa,GrQuadAAFlags aaFlags,const SkRect * domain,const SkMatrix & viewMatrix,sk_sp<GrColorSpaceXform> texXform)1021 void GrRenderTargetContext::drawTextureQuad(const GrClip& clip, sk_sp<GrTextureProxy> proxy,
1022                                             GrSamplerState::Filter filter, SkBlendMode mode,
1023                                             const SkPMColor4f& color, const SkPoint srcQuad[4],
1024                                             const SkPoint dstQuad[4], GrAA aa,
1025                                             GrQuadAAFlags aaFlags, const SkRect* domain,
1026                                             const SkMatrix& viewMatrix,
1027                                             sk_sp<GrColorSpaceXform> texXform) {
1028     ASSERT_SINGLE_OWNER
1029     RETURN_IF_ABANDONED
1030     SkDEBUGCODE(this->validate();)
1031     GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "drawTextureQuad", fContext);
1032     if (domain && domain->contains(proxy->getWorstCaseBoundsRect())) {
1033         domain = nullptr;
1034     }
1035 
1036     GrAAType aaType = this->chooseAAType(aa, GrAllowMixedSamples::kNo);
1037 
1038     // Unlike drawTexture(), don't bother cropping or optimizing the filter type since we're
1039     // sampling an arbitrary quad of the texture.
1040     AutoCheckFlush acf(this->drawingManager());
1041     std::unique_ptr<GrDrawOp> op;
1042     if (mode != SkBlendMode::kSrcOver) {
1043         // Emulation mode, but don't bother converting to kNearest filter since it's an arbitrary
1044         // quad that is being drawn, which makes the tests too expensive here
1045         GrPaint paint;
1046         draw_texture_to_grpaint(
1047                 std::move(proxy), domain, filter, mode, color, std::move(texXform), &paint);
1048         op = GrFillRectOp::MakePerEdgeQuad(fContext, std::move(paint), aaType, aaFlags, viewMatrix,
1049                                            dstQuad, srcQuad);
1050     } else {
1051         // Use lighter weight GrTextureOp
1052         op = GrTextureOp::MakeQuad(fContext, std::move(proxy), filter, color, srcQuad, dstQuad,
1053                                    aaType, aaFlags, domain, viewMatrix, std::move(texXform));
1054     }
1055 
1056     this->addDrawOp(clip, std::move(op));
1057 }
1058 
drawTextureSet(const GrClip & clip,const TextureSetEntry set[],int cnt,GrSamplerState::Filter filter,SkBlendMode mode,GrAA aa,const SkMatrix & viewMatrix,sk_sp<GrColorSpaceXform> texXform)1059 void GrRenderTargetContext::drawTextureSet(const GrClip& clip, const TextureSetEntry set[], int cnt,
1060                                            GrSamplerState::Filter filter, SkBlendMode mode,
1061                                            GrAA aa, const SkMatrix& viewMatrix,
1062                                            sk_sp<GrColorSpaceXform> texXform) {
1063     ASSERT_SINGLE_OWNER
1064     RETURN_IF_ABANDONED
1065     SkDEBUGCODE(this->validate();)
1066     GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "drawTextureSet", fContext);
1067 
1068     if (mode != SkBlendMode::kSrcOver ||
1069         !fContext->priv().caps()->dynamicStateArrayGeometryProcessorTextureSupport()) {
1070         // Draw one at a time with GrFillRectOp and a GrPaint that emulates what GrTextureOp does
1071         SkMatrix ctm;
1072         for (int i = 0; i < cnt; ++i) {
1073             float alpha = set[i].fAlpha;
1074             ctm = viewMatrix;
1075             if (set[i].fPreViewMatrix) {
1076                 ctm.preConcat(*set[i].fPreViewMatrix);
1077             }
1078 
1079             if (set[i].fDstClipQuad == nullptr) {
1080                 // Stick with original rectangles, which allows the ops to know more about what's
1081                 // being drawn.
1082                 this->drawTexture(clip, set[i].fProxy, filter, mode, {alpha, alpha, alpha, alpha},
1083                                   set[i].fSrcRect, set[i].fDstRect, aa, set[i].fAAFlags,
1084                                   SkCanvas::kFast_SrcRectConstraint, ctm, texXform);
1085             } else {
1086                 // Generate interpolated texture coordinates to match the dst clip
1087                 SkPoint srcQuad[4];
1088                 GrMapRectPoints(set[i].fDstRect, set[i].fSrcRect, set[i].fDstClipQuad, srcQuad, 4);
1089                 // Don't send srcRect as the domain, since the normal case doesn't use a constraint
1090                 // with the entire srcRect, so sampling into dstRect outside of dstClip will just
1091                 // keep seams look more correct.
1092                 this->drawTextureQuad(clip, set[i].fProxy, filter, mode,
1093                                       {alpha, alpha, alpha, alpha}, srcQuad, set[i].fDstClipQuad,
1094                                       aa, set[i].fAAFlags, nullptr, ctm, texXform);
1095             }
1096         }
1097     } else {
1098         // Can use a single op, avoiding GrPaint creation, and can batch across proxies
1099         AutoCheckFlush acf(this->drawingManager());
1100         GrAAType aaType = this->chooseAAType(aa, GrAllowMixedSamples::kNo);
1101         auto op = GrTextureOp::MakeSet(fContext, set, cnt, filter, aaType, viewMatrix,
1102                                        std::move(texXform));
1103         this->addDrawOp(clip, std::move(op));
1104     }
1105 }
1106 
fillRectWithLocalMatrix(const GrClip & clip,GrPaint && paint,GrAA aa,const SkMatrix & viewMatrix,const SkRect & rectToDraw,const SkMatrix & localMatrix)1107 void GrRenderTargetContext::fillRectWithLocalMatrix(const GrClip& clip,
1108                                                     GrPaint&& paint,
1109                                                     GrAA aa,
1110                                                     const SkMatrix& viewMatrix,
1111                                                     const SkRect& rectToDraw,
1112                                                     const SkMatrix& localMatrix) {
1113     ASSERT_SINGLE_OWNER
1114     RETURN_IF_ABANDONED
1115     SkDEBUGCODE(this->validate();)
1116     GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "fillRectWithLocalMatrix", fContext);
1117 
1118     SkRect croppedRect = rectToDraw;
1119     if (!crop_filled_rect(this->width(), this->height(), clip, viewMatrix, &croppedRect)) {
1120         return;
1121     }
1122 
1123     AutoCheckFlush acf(this->drawingManager());
1124 
1125     GrAAType aaType = this->chooseAAType(aa, GrAllowMixedSamples::kNo);
1126     this->addDrawOp(clip, GrFillRectOp::MakeWithLocalMatrix(fContext, std::move(paint), aaType,
1127                                                             viewMatrix, localMatrix, croppedRect));
1128 }
1129 
drawVertices(const GrClip & clip,GrPaint && paint,const SkMatrix & viewMatrix,sk_sp<SkVertices> vertices,const SkVertices::Bone bones[],int boneCount,GrPrimitiveType * overridePrimType)1130 void GrRenderTargetContext::drawVertices(const GrClip& clip,
1131                                          GrPaint&& paint,
1132                                          const SkMatrix& viewMatrix,
1133                                          sk_sp<SkVertices> vertices,
1134                                          const SkVertices::Bone bones[],
1135                                          int boneCount,
1136                                          GrPrimitiveType* overridePrimType) {
1137     ASSERT_SINGLE_OWNER
1138     RETURN_IF_ABANDONED
1139     SkDEBUGCODE(this->validate();)
1140     GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "drawVertices", fContext);
1141 
1142     AutoCheckFlush acf(this->drawingManager());
1143 
1144     SkASSERT(vertices);
1145     GrAAType aaType = this->chooseAAType(GrAA::kNo, GrAllowMixedSamples::kNo);
1146     std::unique_ptr<GrDrawOp> op = GrDrawVerticesOp::Make(
1147             fContext, std::move(paint), std::move(vertices), bones, boneCount, viewMatrix, aaType,
1148             this->colorSpaceInfo().refColorSpaceXformFromSRGB(), overridePrimType);
1149     this->addDrawOp(clip, std::move(op));
1150 }
1151 
1152 ///////////////////////////////////////////////////////////////////////////////
1153 
drawAtlas(const GrClip & clip,GrPaint && paint,const SkMatrix & viewMatrix,int spriteCount,const SkRSXform xform[],const SkRect texRect[],const SkColor colors[])1154 void GrRenderTargetContext::drawAtlas(const GrClip& clip,
1155                                       GrPaint&& paint,
1156                                       const SkMatrix& viewMatrix,
1157                                       int spriteCount,
1158                                       const SkRSXform xform[],
1159                                       const SkRect texRect[],
1160                                       const SkColor colors[]) {
1161     ASSERT_SINGLE_OWNER
1162     RETURN_IF_ABANDONED
1163     SkDEBUGCODE(this->validate();)
1164     GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "drawAtlas", fContext);
1165 
1166     AutoCheckFlush acf(this->drawingManager());
1167 
1168     GrAAType aaType = this->chooseAAType(GrAA::kNo, GrAllowMixedSamples::kNo);
1169     std::unique_ptr<GrDrawOp> op = GrDrawAtlasOp::Make(fContext, std::move(paint), viewMatrix,
1170                                                        aaType, spriteCount, xform, texRect, colors);
1171     this->addDrawOp(clip, std::move(op));
1172 }
1173 
1174 ///////////////////////////////////////////////////////////////////////////////
1175 
drawRRect(const GrClip & origClip,GrPaint && paint,GrAA aa,const SkMatrix & viewMatrix,const SkRRect & rrect,const GrStyle & style)1176 void GrRenderTargetContext::drawRRect(const GrClip& origClip,
1177                                       GrPaint&& paint,
1178                                       GrAA aa,
1179                                       const SkMatrix& viewMatrix,
1180                                       const SkRRect& rrect,
1181                                       const GrStyle& style) {
1182     ASSERT_SINGLE_OWNER
1183     RETURN_IF_ABANDONED
1184     SkDEBUGCODE(this->validate();)
1185     GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "drawRRect", fContext);
1186 
1187     const SkStrokeRec& stroke = style.strokeRec();
1188     if (stroke.getStyle() == SkStrokeRec::kFill_Style && rrect.isEmpty()) {
1189        return;
1190     }
1191 
1192     GrNoClip noclip;
1193     const GrClip* clip = &origClip;
1194 #ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
1195     // The Android framework frequently clips rrects to themselves where the clip is non-aa and the
1196     // draw is aa. Since our lower level clip code works from op bounds, which are SkRects, it
1197     // doesn't detect that the clip can be ignored (modulo antialiasing). The following test
1198     // attempts to mitigate the stencil clip cost but will only help when the entire clip stack
1199     // can be ignored. We'd prefer to fix this in the framework by removing the clips calls. This
1200     // only works for filled rrects since the stroke width outsets beyond the rrect itself.
1201     SkRRect devRRect;
1202     if (stroke.getStyle() == SkStrokeRec::kFill_Style && rrect.transform(viewMatrix, &devRRect) &&
1203         clip->quickContains(devRRect)) {
1204         clip = &noclip;
1205     }
1206 #endif
1207     SkASSERT(!style.pathEffect()); // this should've been devolved to a path in SkGpuDevice
1208 
1209     AutoCheckFlush acf(this->drawingManager());
1210 
1211     GrAAType aaType = this->chooseAAType(aa, GrAllowMixedSamples::kNo);
1212     if (GrAAType::kCoverage == aaType) {
1213         std::unique_ptr<GrDrawOp> op;
1214         if (style.isSimpleFill()) {
1215             op = GrAAFillRRectOp::Make(fContext, viewMatrix, rrect, *this->caps(),
1216                                        std::move(paint));
1217         }
1218         if (!op) {
1219             assert_alive(paint);
1220             op = GrOvalOpFactory::MakeRRectOp(fContext, std::move(paint), viewMatrix, rrect, stroke,
1221                                               this->caps()->shaderCaps());
1222         }
1223 
1224         if (op) {
1225             this->addDrawOp(*clip, std::move(op));
1226             return;
1227         }
1228     }
1229 
1230     assert_alive(paint);
1231     this->drawShapeUsingPathRenderer(*clip, std::move(paint), aa, viewMatrix,
1232                                      GrShape(rrect, style));
1233 }
1234 
1235 ///////////////////////////////////////////////////////////////////////////////
1236 
map(const SkMatrix & m,const SkPoint3 & pt)1237 static SkPoint3 map(const SkMatrix& m, const SkPoint3& pt) {
1238     SkPoint3 result;
1239     m.mapXY(pt.fX, pt.fY, (SkPoint*)&result.fX);
1240     result.fZ = pt.fZ;
1241     return result;
1242 }
1243 
drawFastShadow(const GrClip & clip,const SkMatrix & viewMatrix,const SkPath & path,const SkDrawShadowRec & rec)1244 bool GrRenderTargetContext::drawFastShadow(const GrClip& clip,
1245                                            const SkMatrix& viewMatrix,
1246                                            const SkPath& path,
1247                                            const SkDrawShadowRec& rec) {
1248     ASSERT_SINGLE_OWNER
1249     if (fContext->priv().abandoned()) {
1250         return true;
1251     }
1252     SkDEBUGCODE(this->validate();)
1253     GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "drawFastShadow", fContext);
1254 
1255     // check z plane
1256     bool tiltZPlane = SkToBool(!SkScalarNearlyZero(rec.fZPlaneParams.fX) ||
1257                                !SkScalarNearlyZero(rec.fZPlaneParams.fY));
1258     bool skipAnalytic = SkToBool(rec.fFlags & SkShadowFlags::kGeometricOnly_ShadowFlag);
1259     if (tiltZPlane || skipAnalytic || !viewMatrix.rectStaysRect() || !viewMatrix.isSimilarity()) {
1260         return false;
1261     }
1262 
1263     SkRRect rrect;
1264     SkRect rect;
1265     // we can only handle rects, circles, and rrects with circular corners
1266     bool isRRect = path.isRRect(&rrect) && SkRRectPriv::IsSimpleCircular(rrect) &&
1267         rrect.radii(SkRRect::kUpperLeft_Corner).fX > SK_ScalarNearlyZero;
1268     if (!isRRect &&
1269         path.isOval(&rect) && SkScalarNearlyEqual(rect.width(), rect.height()) &&
1270         rect.width() > SK_ScalarNearlyZero) {
1271         rrect.setOval(rect);
1272         isRRect = true;
1273     }
1274     if (!isRRect && path.isRect(&rect)) {
1275         rrect.setRect(rect);
1276         isRRect = true;
1277     }
1278 
1279     if (!isRRect) {
1280         return false;
1281     }
1282 
1283     if (rrect.isEmpty()) {
1284         return true;
1285     }
1286 
1287     AutoCheckFlush acf(this->drawingManager());
1288 
1289     // transform light
1290     SkPoint3 devLightPos = map(viewMatrix, rec.fLightPos);
1291 
1292     // 1/scale
1293     SkScalar devToSrcScale = viewMatrix.isScaleTranslate() ?
1294         SkScalarInvert(viewMatrix[SkMatrix::kMScaleX]) :
1295         sk_float_rsqrt(viewMatrix[SkMatrix::kMScaleX] * viewMatrix[SkMatrix::kMScaleX] +
1296                        viewMatrix[SkMatrix::kMSkewX] * viewMatrix[SkMatrix::kMSkewX]);
1297 
1298     SkScalar occluderHeight = rec.fZPlaneParams.fZ;
1299     bool transparent = SkToBool(rec.fFlags & SkShadowFlags::kTransparentOccluder_ShadowFlag);
1300 
1301     if (SkColorGetA(rec.fAmbientColor) > 0) {
1302         SkScalar devSpaceInsetWidth = SkDrawShadowMetrics::AmbientBlurRadius(occluderHeight);
1303         const SkScalar umbraRecipAlpha = SkDrawShadowMetrics::AmbientRecipAlpha(occluderHeight);
1304         const SkScalar devSpaceAmbientBlur = devSpaceInsetWidth * umbraRecipAlpha;
1305 
1306         // Outset the shadow rrect to the border of the penumbra
1307         SkScalar ambientPathOutset = devSpaceInsetWidth * devToSrcScale;
1308         SkRRect ambientRRect;
1309         SkRect outsetRect = rrect.rect().makeOutset(ambientPathOutset, ambientPathOutset);
1310         // If the rrect was an oval then its outset will also be one.
1311         // We set it explicitly to avoid errors.
1312         if (rrect.isOval()) {
1313             ambientRRect = SkRRect::MakeOval(outsetRect);
1314         } else {
1315             SkScalar outsetRad = SkRRectPriv::GetSimpleRadii(rrect).fX + ambientPathOutset;
1316             ambientRRect = SkRRect::MakeRectXY(outsetRect, outsetRad, outsetRad);
1317         }
1318 
1319         GrColor ambientColor = SkColorToPremulGrColor(rec.fAmbientColor);
1320         if (transparent) {
1321             // set a large inset to force a fill
1322             devSpaceInsetWidth = ambientRRect.width();
1323         }
1324 
1325         std::unique_ptr<GrDrawOp> op = GrShadowRRectOp::Make(fContext,
1326                                                              ambientColor,
1327                                                              viewMatrix,
1328                                                              ambientRRect,
1329                                                              devSpaceAmbientBlur,
1330                                                              devSpaceInsetWidth);
1331         SkASSERT(op);
1332         this->addDrawOp(clip, std::move(op));
1333     }
1334 
1335     if (SkColorGetA(rec.fSpotColor) > 0) {
1336         SkScalar devSpaceSpotBlur;
1337         SkScalar spotScale;
1338         SkVector spotOffset;
1339         SkDrawShadowMetrics::GetSpotParams(occluderHeight, devLightPos.fX, devLightPos.fY,
1340                                            devLightPos.fZ, rec.fLightRadius,
1341                                            &devSpaceSpotBlur, &spotScale, &spotOffset);
1342         // handle scale of radius due to CTM
1343         const SkScalar srcSpaceSpotBlur = devSpaceSpotBlur * devToSrcScale;
1344 
1345         // Adjust translate for the effect of the scale.
1346         spotOffset.fX += spotScale*viewMatrix[SkMatrix::kMTransX];
1347         spotOffset.fY += spotScale*viewMatrix[SkMatrix::kMTransY];
1348         // This offset is in dev space, need to transform it into source space.
1349         SkMatrix ctmInverse;
1350         if (viewMatrix.invert(&ctmInverse)) {
1351             ctmInverse.mapPoints(&spotOffset, 1);
1352         } else {
1353             // Since the matrix is a similarity, this should never happen, but just in case...
1354             SkDebugf("Matrix is degenerate. Will not render spot shadow correctly!\n");
1355             SkASSERT(false);
1356         }
1357 
1358         // Compute the transformed shadow rrect
1359         SkRRect spotShadowRRect;
1360         SkMatrix shadowTransform;
1361         shadowTransform.setScaleTranslate(spotScale, spotScale, spotOffset.fX, spotOffset.fY);
1362         rrect.transform(shadowTransform, &spotShadowRRect);
1363         SkScalar spotRadius = SkRRectPriv::GetSimpleRadii(spotShadowRRect).fX;
1364 
1365         // Compute the insetWidth
1366         SkScalar blurOutset = srcSpaceSpotBlur;
1367         SkScalar insetWidth = blurOutset;
1368         if (transparent) {
1369             // If transparent, just do a fill
1370             insetWidth += spotShadowRRect.width();
1371         } else {
1372             // For shadows, instead of using a stroke we specify an inset from the penumbra
1373             // border. We want to extend this inset area so that it meets up with the caster
1374             // geometry. The inset geometry will by default already be inset by the blur width.
1375             //
1376             // We compare the min and max corners inset by the radius between the original
1377             // rrect and the shadow rrect. The distance between the two plus the difference
1378             // between the scaled radius and the original radius gives the distance from the
1379             // transformed shadow shape to the original shape in that corner. The max
1380             // of these gives the maximum distance we need to cover.
1381             //
1382             // Since we are outsetting by 1/2 the blur distance, we just add the maxOffset to
1383             // that to get the full insetWidth.
1384             SkScalar maxOffset;
1385             if (rrect.isRect()) {
1386                 // Manhattan distance works better for rects
1387                 maxOffset = SkTMax(SkTMax(SkTAbs(spotShadowRRect.rect().fLeft -
1388                                                  rrect.rect().fLeft),
1389                                           SkTAbs(spotShadowRRect.rect().fTop -
1390                                                  rrect.rect().fTop)),
1391                                    SkTMax(SkTAbs(spotShadowRRect.rect().fRight -
1392                                                  rrect.rect().fRight),
1393                                           SkTAbs(spotShadowRRect.rect().fBottom -
1394                                                  rrect.rect().fBottom)));
1395             } else {
1396                 SkScalar dr = spotRadius - SkRRectPriv::GetSimpleRadii(rrect).fX;
1397                 SkPoint upperLeftOffset = SkPoint::Make(spotShadowRRect.rect().fLeft -
1398                                                         rrect.rect().fLeft + dr,
1399                                                         spotShadowRRect.rect().fTop -
1400                                                         rrect.rect().fTop + dr);
1401                 SkPoint lowerRightOffset = SkPoint::Make(spotShadowRRect.rect().fRight -
1402                                                          rrect.rect().fRight - dr,
1403                                                          spotShadowRRect.rect().fBottom -
1404                                                          rrect.rect().fBottom - dr);
1405                 maxOffset = SkScalarSqrt(SkTMax(SkPointPriv::LengthSqd(upperLeftOffset),
1406                                                 SkPointPriv::LengthSqd(lowerRightOffset))) + dr;
1407             }
1408             insetWidth += SkTMax(blurOutset, maxOffset);
1409         }
1410 
1411         // Outset the shadow rrect to the border of the penumbra
1412         SkRect outsetRect = spotShadowRRect.rect().makeOutset(blurOutset, blurOutset);
1413         if (spotShadowRRect.isOval()) {
1414             spotShadowRRect = SkRRect::MakeOval(outsetRect);
1415         } else {
1416             SkScalar outsetRad = spotRadius + blurOutset;
1417             spotShadowRRect = SkRRect::MakeRectXY(outsetRect, outsetRad, outsetRad);
1418         }
1419 
1420         GrColor spotColor = SkColorToPremulGrColor(rec.fSpotColor);
1421 
1422         std::unique_ptr<GrDrawOp> op = GrShadowRRectOp::Make(fContext,
1423                                                              spotColor,
1424                                                              viewMatrix,
1425                                                              spotShadowRRect,
1426                                                              2.0f * devSpaceSpotBlur,
1427                                                              insetWidth);
1428         SkASSERT(op);
1429         this->addDrawOp(clip, std::move(op));
1430     }
1431 
1432     return true;
1433 }
1434 
1435 ///////////////////////////////////////////////////////////////////////////////
1436 
drawFilledDRRect(const GrClip & clip,GrPaint && paint,GrAA aa,const SkMatrix & viewMatrix,const SkRRect & origOuter,const SkRRect & origInner)1437 bool GrRenderTargetContext::drawFilledDRRect(const GrClip& clip,
1438                                              GrPaint&& paint,
1439                                              GrAA aa,
1440                                              const SkMatrix& viewMatrix,
1441                                              const SkRRect& origOuter,
1442                                              const SkRRect& origInner) {
1443     SkASSERT(!origInner.isEmpty());
1444     SkASSERT(!origOuter.isEmpty());
1445 
1446     SkTCopyOnFirstWrite<SkRRect> inner(origInner), outer(origOuter);
1447 
1448     GrAAType aaType = this->chooseAAType(aa, GrAllowMixedSamples::kNo);
1449 
1450     if (GrAAType::kMSAA == aaType) {
1451         return false;
1452     }
1453 
1454     if (GrAAType::kCoverage == aaType && SkRRectPriv::IsCircle(*inner)
1455                                       && SkRRectPriv::IsCircle(*outer)) {
1456         auto outerR = outer->width() / 2.f;
1457         auto innerR = inner->width() / 2.f;
1458         auto cx = outer->getBounds().fLeft + outerR;
1459         auto cy = outer->getBounds().fTop + outerR;
1460         if (SkScalarNearlyEqual(cx, inner->getBounds().fLeft + innerR) &&
1461             SkScalarNearlyEqual(cy, inner->getBounds().fTop + innerR)) {
1462             auto avgR = (innerR + outerR) / 2.f;
1463             auto circleBounds = SkRect::MakeLTRB(cx - avgR, cy - avgR, cx + avgR, cy + avgR);
1464             SkStrokeRec stroke(SkStrokeRec::kFill_InitStyle);
1465             stroke.setStrokeStyle(outerR - innerR);
1466             auto op = GrOvalOpFactory::MakeOvalOp(fContext, std::move(paint), viewMatrix,
1467                                                   circleBounds, GrStyle(stroke, nullptr),
1468                                                   this->caps()->shaderCaps());
1469             if (op) {
1470                 this->addDrawOp(clip, std::move(op));
1471                 return true;
1472             }
1473             assert_alive(paint);
1474         }
1475     }
1476 
1477     GrClipEdgeType innerEdgeType, outerEdgeType;
1478     if (GrAAType::kCoverage == aaType) {
1479         innerEdgeType = GrClipEdgeType::kInverseFillAA;
1480         outerEdgeType = GrClipEdgeType::kFillAA;
1481     } else {
1482         innerEdgeType = GrClipEdgeType::kInverseFillBW;
1483         outerEdgeType = GrClipEdgeType::kFillBW;
1484     }
1485 
1486     SkMatrix inverseVM;
1487     if (!viewMatrix.isIdentity()) {
1488         if (!origInner.transform(viewMatrix, inner.writable())) {
1489             return false;
1490         }
1491         if (!origOuter.transform(viewMatrix, outer.writable())) {
1492             return false;
1493         }
1494         if (!viewMatrix.invert(&inverseVM)) {
1495             return false;
1496         }
1497     } else {
1498         inverseVM.reset();
1499     }
1500 
1501     const auto& caps = *this->caps()->shaderCaps();
1502     // TODO these need to be a geometry processors
1503     auto innerEffect = GrRRectEffect::Make(innerEdgeType, *inner, caps);
1504     if (!innerEffect) {
1505         return false;
1506     }
1507 
1508     auto outerEffect = GrRRectEffect::Make(outerEdgeType, *outer, caps);
1509     if (!outerEffect) {
1510         return false;
1511     }
1512 
1513     paint.addCoverageFragmentProcessor(std::move(innerEffect));
1514     paint.addCoverageFragmentProcessor(std::move(outerEffect));
1515 
1516     SkRect bounds = outer->getBounds();
1517     if (GrAAType::kCoverage == aaType) {
1518         bounds.outset(SK_ScalarHalf, SK_ScalarHalf);
1519     }
1520 
1521     this->fillRectWithLocalMatrix(clip, std::move(paint), GrAA::kNo, SkMatrix::I(), bounds,
1522                                   inverseVM);
1523     return true;
1524 }
1525 
drawDRRect(const GrClip & clip,GrPaint && paint,GrAA aa,const SkMatrix & viewMatrix,const SkRRect & outer,const SkRRect & inner)1526 void GrRenderTargetContext::drawDRRect(const GrClip& clip,
1527                                        GrPaint&& paint,
1528                                        GrAA aa,
1529                                        const SkMatrix& viewMatrix,
1530                                        const SkRRect& outer,
1531                                        const SkRRect& inner) {
1532     ASSERT_SINGLE_OWNER
1533     RETURN_IF_ABANDONED
1534     SkDEBUGCODE(this->validate();)
1535     GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "drawDRRect", fContext);
1536 
1537     SkASSERT(!outer.isEmpty());
1538     SkASSERT(!inner.isEmpty());
1539 
1540     AutoCheckFlush acf(this->drawingManager());
1541 
1542     if (this->drawFilledDRRect(clip, std::move(paint), aa, viewMatrix, outer, inner)) {
1543         return;
1544     }
1545     assert_alive(paint);
1546 
1547     SkPath path;
1548     path.setIsVolatile(true);
1549     path.addRRect(inner);
1550     path.addRRect(outer);
1551     path.setFillType(SkPath::kEvenOdd_FillType);
1552     this->drawShapeUsingPathRenderer(clip, std::move(paint), aa, viewMatrix, GrShape(path));
1553 }
1554 
1555 ///////////////////////////////////////////////////////////////////////////////
1556 
drawRegion(const GrClip & clip,GrPaint && paint,GrAA aa,const SkMatrix & viewMatrix,const SkRegion & region,const GrStyle & style,const GrUserStencilSettings * ss)1557 void GrRenderTargetContext::drawRegion(const GrClip& clip,
1558                                        GrPaint&& paint,
1559                                        GrAA aa,
1560                                        const SkMatrix& viewMatrix,
1561                                        const SkRegion& region,
1562                                        const GrStyle& style,
1563                                        const GrUserStencilSettings* ss) {
1564     ASSERT_SINGLE_OWNER
1565     RETURN_IF_ABANDONED
1566     SkDEBUGCODE(this->validate();)
1567     GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "drawRegion", fContext);
1568 
1569     if (GrAA::kYes == aa) {
1570         // GrRegionOp performs no antialiasing but is much faster, so here we check the matrix
1571         // to see whether aa is really required.
1572         if (!SkToBool(viewMatrix.getType() & ~(SkMatrix::kTranslate_Mask)) &&
1573             SkScalarIsInt(viewMatrix.getTranslateX()) &&
1574             SkScalarIsInt(viewMatrix.getTranslateY())) {
1575             aa = GrAA::kNo;
1576         }
1577     }
1578     bool complexStyle = !style.isSimpleFill();
1579     if (complexStyle || GrAA::kYes == aa) {
1580         SkPath path;
1581         region.getBoundaryPath(&path);
1582         path.setIsVolatile(true);
1583 
1584         return this->drawPath(clip, std::move(paint), aa, viewMatrix, path, style);
1585     }
1586 
1587     GrAAType aaType = this->chooseAAType(GrAA::kNo, GrAllowMixedSamples::kNo);
1588     std::unique_ptr<GrDrawOp> op = GrRegionOp::Make(fContext, std::move(paint), viewMatrix, region,
1589                                                     aaType, ss);
1590     this->addDrawOp(clip, std::move(op));
1591 }
1592 
drawOval(const GrClip & clip,GrPaint && paint,GrAA aa,const SkMatrix & viewMatrix,const SkRect & oval,const GrStyle & style)1593 void GrRenderTargetContext::drawOval(const GrClip& clip,
1594                                      GrPaint&& paint,
1595                                      GrAA aa,
1596                                      const SkMatrix& viewMatrix,
1597                                      const SkRect& oval,
1598                                      const GrStyle& style) {
1599     ASSERT_SINGLE_OWNER
1600     RETURN_IF_ABANDONED
1601     SkDEBUGCODE(this->validate();)
1602     GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "drawOval", fContext);
1603 
1604     const SkStrokeRec& stroke = style.strokeRec();
1605 
1606     if (oval.isEmpty() && !style.pathEffect()) {
1607         if (stroke.getStyle() == SkStrokeRec::kFill_Style) {
1608             return;
1609         }
1610 
1611         this->drawRect(clip, std::move(paint), aa, viewMatrix, oval, &style);
1612         return;
1613     }
1614 
1615     AutoCheckFlush acf(this->drawingManager());
1616 
1617     GrAAType aaType = this->chooseAAType(aa, GrAllowMixedSamples::kNo);
1618     if (GrAAType::kCoverage == aaType) {
1619         std::unique_ptr<GrDrawOp> op;
1620         // GrAAFillRRectOp has special geometry and a fragment-shader branch to conditionally
1621         // evaluate the arc equation. This same special geometry and fragment branch also turn out
1622         // to be a substantial optimization for drawing ovals (namely, by not evaluating the arc
1623         // equation inside the oval's inner diamond). Given these optimizations, it's a clear win to
1624         // draw ovals the exact same way we do round rects.
1625         //
1626         // However, we still don't draw true circles as round rects, because it can cause perf
1627         // regressions on some platforms as compared to the dedicated circle Op.
1628         if (style.isSimpleFill() && oval.height() != oval.width()) {
1629             op = GrAAFillRRectOp::Make(fContext, viewMatrix, SkRRect::MakeOval(oval), *this->caps(),
1630                                        std::move(paint));
1631         }
1632         if (!op) {
1633             assert_alive(paint);
1634             op = GrOvalOpFactory::MakeOvalOp(fContext, std::move(paint), viewMatrix, oval, style,
1635                                              this->caps()->shaderCaps());
1636         }
1637         if (op) {
1638             this->addDrawOp(clip, std::move(op));
1639             return;
1640         }
1641     }
1642 
1643     assert_alive(paint);
1644     this->drawShapeUsingPathRenderer(
1645             clip, std::move(paint), aa, viewMatrix,
1646             GrShape(SkRRect::MakeOval(oval), SkPath::kCW_Direction, 2, false, style));
1647 }
1648 
drawArc(const GrClip & clip,GrPaint && paint,GrAA aa,const SkMatrix & viewMatrix,const SkRect & oval,SkScalar startAngle,SkScalar sweepAngle,bool useCenter,const GrStyle & style)1649 void GrRenderTargetContext::drawArc(const GrClip& clip,
1650                                     GrPaint&& paint,
1651                                     GrAA aa,
1652                                     const SkMatrix& viewMatrix,
1653                                     const SkRect& oval,
1654                                     SkScalar startAngle,
1655                                     SkScalar sweepAngle,
1656                                     bool useCenter,
1657                                     const GrStyle& style) {
1658     ASSERT_SINGLE_OWNER
1659     RETURN_IF_ABANDONED
1660     SkDEBUGCODE(this->validate();)
1661             GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "drawArc", fContext);
1662 
1663     AutoCheckFlush acf(this->drawingManager());
1664 
1665     GrAAType aaType = this->chooseAAType(aa, GrAllowMixedSamples::kNo);
1666     if (GrAAType::kCoverage == aaType) {
1667         const GrShaderCaps* shaderCaps = this->caps()->shaderCaps();
1668         std::unique_ptr<GrDrawOp> op = GrOvalOpFactory::MakeArcOp(fContext,
1669                                                                   std::move(paint),
1670                                                                   viewMatrix,
1671                                                                   oval,
1672                                                                   startAngle,
1673                                                                   sweepAngle,
1674                                                                   useCenter,
1675                                                                   style,
1676                                                                   shaderCaps);
1677         if (op) {
1678             this->addDrawOp(clip, std::move(op));
1679             return;
1680         }
1681         assert_alive(paint);
1682     }
1683     this->drawShapeUsingPathRenderer(
1684             clip, std::move(paint), aa, viewMatrix,
1685             GrShape::MakeArc(oval, startAngle, sweepAngle, useCenter, style));
1686 }
1687 
drawImageLattice(const GrClip & clip,GrPaint && paint,const SkMatrix & viewMatrix,sk_sp<GrTextureProxy> image,sk_sp<GrColorSpaceXform> csxf,GrSamplerState::Filter filter,std::unique_ptr<SkLatticeIter> iter,const SkRect & dst)1688 void GrRenderTargetContext::drawImageLattice(const GrClip& clip,
1689                                              GrPaint&& paint,
1690                                              const SkMatrix& viewMatrix,
1691                                              sk_sp<GrTextureProxy> image,
1692                                              sk_sp<GrColorSpaceXform> csxf,
1693                                              GrSamplerState::Filter filter,
1694                                              std::unique_ptr<SkLatticeIter> iter,
1695                                              const SkRect& dst) {
1696     ASSERT_SINGLE_OWNER
1697     RETURN_IF_ABANDONED
1698     SkDEBUGCODE(this->validate();)
1699     GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "drawImageLattice", fContext);
1700 
1701     AutoCheckFlush acf(this->drawingManager());
1702 
1703     std::unique_ptr<GrDrawOp> op =
1704             GrLatticeOp::MakeNonAA(fContext, std::move(paint), viewMatrix, std::move(image),
1705                                    std::move(csxf), filter, std::move(iter), dst);
1706     this->addDrawOp(clip, std::move(op));
1707 }
1708 
drawDrawable(std::unique_ptr<SkDrawable::GpuDrawHandler> drawable,const SkRect & bounds)1709 void GrRenderTargetContext::drawDrawable(std::unique_ptr<SkDrawable::GpuDrawHandler> drawable,
1710                                          const SkRect& bounds) {
1711     std::unique_ptr<GrOp> op(GrDrawableOp::Make(fContext, std::move(drawable), bounds));
1712     SkASSERT(op);
1713     this->getRTOpList()->addOp(std::move(op), *this->caps());
1714 }
1715 
prepareForExternalIO(SkSurface::BackendSurfaceAccess access,GrFlushFlags flags,int numSemaphores,GrBackendSemaphore backendSemaphores[],GrGpuFinishedProc finishedProc,GrGpuFinishedContext finishedContext)1716 GrSemaphoresSubmitted GrRenderTargetContext::prepareForExternalIO(
1717         SkSurface::BackendSurfaceAccess access, GrFlushFlags flags, int numSemaphores,
1718         GrBackendSemaphore backendSemaphores[], GrGpuFinishedProc finishedProc,
1719         GrGpuFinishedContext finishedContext) {
1720     ASSERT_SINGLE_OWNER
1721     if (fContext->priv().abandoned()) {
1722         return GrSemaphoresSubmitted::kNo;
1723     }
1724     SkDEBUGCODE(this->validate();)
1725     GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "prepareForExternalIO", fContext);
1726 
1727     return this->drawingManager()->prepareSurfaceForExternalIO(fRenderTargetProxy.get(),
1728                                                                access, flags,
1729                                                                numSemaphores,
1730                                                                backendSemaphores,
1731                                                                finishedProc,
1732                                                                finishedContext);
1733 }
1734 
waitOnSemaphores(int numSemaphores,const GrBackendSemaphore waitSemaphores[])1735 bool GrRenderTargetContext::waitOnSemaphores(int numSemaphores,
1736                                              const GrBackendSemaphore waitSemaphores[]) {
1737     ASSERT_SINGLE_OWNER
1738     RETURN_FALSE_IF_ABANDONED
1739     SkDEBUGCODE(this->validate();)
1740     GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "waitOnSemaphores", fContext);
1741 
1742     AutoCheckFlush acf(this->drawingManager());
1743 
1744     if (numSemaphores && !this->caps()->fenceSyncSupport()) {
1745         return false;
1746     }
1747 
1748     auto direct = fContext->priv().asDirectContext();
1749     if (!direct) {
1750         return false;
1751     }
1752 
1753     auto resourceProvider = direct->priv().resourceProvider();
1754 
1755     for (int i = 0; i < numSemaphores; ++i) {
1756         sk_sp<GrSemaphore> sema = resourceProvider->wrapBackendSemaphore(
1757                 waitSemaphores[i], GrResourceProvider::SemaphoreWrapType::kWillWait,
1758                 kAdopt_GrWrapOwnership);
1759         std::unique_ptr<GrOp> waitOp(GrSemaphoreOp::MakeWait(fContext, std::move(sema),
1760                                                              fRenderTargetProxy.get()));
1761         this->getRTOpList()->addWaitOp(std::move(waitOp), *this->caps());
1762     }
1763     return true;
1764 }
1765 
insertEventMarker(const SkString & str)1766 void GrRenderTargetContext::insertEventMarker(const SkString& str) {
1767     std::unique_ptr<GrOp> op(GrDebugMarkerOp::Make(fContext, fRenderTargetProxy.get(), str));
1768     this->getRTOpList()->addOp(std::move(op), *this->caps());
1769 }
1770 
caps() const1771 const GrCaps* GrRenderTargetContext::caps() const {
1772     return fContext->priv().caps();
1773 }
1774 
drawPath(const GrClip & clip,GrPaint && paint,GrAA aa,const SkMatrix & viewMatrix,const SkPath & path,const GrStyle & style)1775 void GrRenderTargetContext::drawPath(const GrClip& clip,
1776                                      GrPaint&& paint,
1777                                      GrAA aa,
1778                                      const SkMatrix& viewMatrix,
1779                                      const SkPath& path,
1780                                      const GrStyle& style) {
1781     ASSERT_SINGLE_OWNER
1782     RETURN_IF_ABANDONED
1783     SkDEBUGCODE(this->validate();)
1784     GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "drawPath", fContext);
1785 
1786     GrShape shape(path, style);
1787 
1788     this->drawShape(clip, std::move(paint), aa, viewMatrix, shape);
1789 }
1790 
drawShape(const GrClip & clip,GrPaint && paint,GrAA aa,const SkMatrix & viewMatrix,const GrShape & shape)1791 void GrRenderTargetContext::drawShape(const GrClip& clip,
1792                                       GrPaint&& paint,
1793                                       GrAA aa,
1794                                       const SkMatrix& viewMatrix,
1795                                       const GrShape& shape) {
1796     ASSERT_SINGLE_OWNER
1797     RETURN_IF_ABANDONED
1798     SkDEBUGCODE(this->validate();)
1799     GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "drawShape", fContext);
1800 
1801     if (shape.isEmpty()) {
1802         if (shape.inverseFilled()) {
1803             this->drawPaint(clip, std::move(paint), viewMatrix);
1804         }
1805         return;
1806     }
1807 
1808     AutoCheckFlush acf(this->drawingManager());
1809 
1810     if (!shape.style().hasPathEffect()) {
1811         GrAAType aaType = this->chooseAAType(aa, GrAllowMixedSamples::kNo);
1812         SkRRect rrect;
1813         // We can ignore the starting point and direction since there is no path effect.
1814         bool inverted;
1815         if (shape.asRRect(&rrect, nullptr, nullptr, &inverted) && !inverted) {
1816             if (rrect.isRect()) {
1817                 this->drawRect(clip, std::move(paint), aa, viewMatrix, rrect.rect(),
1818                                &shape.style());
1819                 return;
1820             } else if (rrect.isOval()) {
1821                 this->drawOval(clip, std::move(paint), aa, viewMatrix, rrect.rect(), shape.style());
1822                 return;
1823             }
1824             this->drawRRect(clip, std::move(paint), aa, viewMatrix, rrect, shape.style());
1825             return;
1826         } else if (GrAAType::kCoverage == aaType && shape.style().isSimpleFill() &&
1827                    viewMatrix.rectStaysRect()) {
1828             // TODO: the rectStaysRect restriction could be lifted if we were willing to apply
1829             // the matrix to all the points individually rather than just to the rect
1830             SkRect rects[2];
1831             if (shape.asNestedRects(rects)) {
1832                 // Concave AA paths are expensive - try to avoid them for special cases
1833                 std::unique_ptr<GrDrawOp> op = GrStrokeRectOp::MakeNested(
1834                                 fContext, std::move(paint), viewMatrix, rects);
1835                 if (op) {
1836                     this->addDrawOp(clip, std::move(op));
1837                 }
1838                 // Returning here indicates that there is nothing to draw in this case.
1839                 return;
1840             }
1841         }
1842     }
1843 
1844     this->drawShapeUsingPathRenderer(clip, std::move(paint), aa, viewMatrix, shape);
1845 }
1846 
drawAndStencilPath(const GrHardClip & clip,const GrUserStencilSettings * ss,SkRegion::Op op,bool invert,GrAA aa,const SkMatrix & viewMatrix,const SkPath & path)1847 bool GrRenderTargetContextPriv::drawAndStencilPath(const GrHardClip& clip,
1848                                                    const GrUserStencilSettings* ss,
1849                                                    SkRegion::Op op,
1850                                                    bool invert,
1851                                                    GrAA aa,
1852                                                    const SkMatrix& viewMatrix,
1853                                                    const SkPath& path) {
1854     ASSERT_SINGLE_OWNER_PRIV
1855     RETURN_FALSE_IF_ABANDONED_PRIV
1856     SkDEBUGCODE(fRenderTargetContext->validate();)
1857     GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContextPriv", "drawAndStencilPath",
1858                                    fRenderTargetContext->fContext);
1859 
1860     if (path.isEmpty() && path.isInverseFillType()) {
1861         this->drawAndStencilRect(clip, ss, op, invert, GrAA::kNo, SkMatrix::I(),
1862                                  SkRect::MakeIWH(fRenderTargetContext->width(),
1863                                                  fRenderTargetContext->height()));
1864         return true;
1865     }
1866 
1867     AutoCheckFlush acf(fRenderTargetContext->drawingManager());
1868 
1869     // An Assumption here is that path renderer would use some form of tweaking
1870     // the src color (either the input alpha or in the frag shader) to implement
1871     // aa. If we have some future driver-mojo path AA that can do the right
1872     // thing WRT to the blend then we'll need some query on the PR.
1873     GrAAType aaType = fRenderTargetContext->chooseAAType(aa, GrAllowMixedSamples::kNo);
1874     bool hasUserStencilSettings = !ss->isUnused();
1875 
1876     SkIRect clipConservativeBounds;
1877     clip.getConservativeBounds(fRenderTargetContext->width(), fRenderTargetContext->height(),
1878                                &clipConservativeBounds, nullptr);
1879 
1880     GrShape shape(path, GrStyle::SimpleFill());
1881     GrPathRenderer::CanDrawPathArgs canDrawArgs;
1882     canDrawArgs.fCaps = fRenderTargetContext->caps();
1883     canDrawArgs.fViewMatrix = &viewMatrix;
1884     canDrawArgs.fShape = &shape;
1885     canDrawArgs.fClipConservativeBounds = &clipConservativeBounds;
1886     canDrawArgs.fAAType = aaType;
1887     SkASSERT(!fRenderTargetContext->wrapsVkSecondaryCB());
1888     canDrawArgs.fTargetIsWrappedVkSecondaryCB = false;
1889     canDrawArgs.fHasUserStencilSettings = hasUserStencilSettings;
1890 
1891     // Don't allow the SW renderer
1892     GrPathRenderer* pr = fRenderTargetContext->drawingManager()->getPathRenderer(
1893             canDrawArgs, false, GrPathRendererChain::DrawType::kStencilAndColor);
1894     if (!pr) {
1895         return false;
1896     }
1897 
1898     GrPaint paint;
1899     paint.setCoverageSetOpXPFactory(op, invert);
1900 
1901     GrPathRenderer::DrawPathArgs args{fRenderTargetContext->drawingManager()->getContext(),
1902                                       std::move(paint),
1903                                       ss,
1904                                       fRenderTargetContext,
1905                                       &clip,
1906                                       &clipConservativeBounds,
1907                                       &viewMatrix,
1908                                       &shape,
1909                                       aaType,
1910                                       fRenderTargetContext->colorSpaceInfo().isLinearlyBlended()};
1911     pr->drawPath(args);
1912     return true;
1913 }
1914 
isBudgeted() const1915 SkBudgeted GrRenderTargetContextPriv::isBudgeted() const {
1916     ASSERT_SINGLE_OWNER_PRIV
1917 
1918     if (fRenderTargetContext->fContext->priv().abandoned()) {
1919         return SkBudgeted::kNo;
1920     }
1921 
1922     SkDEBUGCODE(fRenderTargetContext->validate();)
1923 
1924     return fRenderTargetContext->fRenderTargetProxy->isBudgeted();
1925 }
1926 
drawShapeUsingPathRenderer(const GrClip & clip,GrPaint && paint,GrAA aa,const SkMatrix & viewMatrix,const GrShape & originalShape)1927 void GrRenderTargetContext::drawShapeUsingPathRenderer(const GrClip& clip,
1928                                                        GrPaint&& paint,
1929                                                        GrAA aa,
1930                                                        const SkMatrix& viewMatrix,
1931                                                        const GrShape& originalShape) {
1932     ASSERT_SINGLE_OWNER
1933     RETURN_IF_ABANDONED
1934     GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "internalDrawPath", fContext);
1935 
1936     if (!viewMatrix.isFinite() || !originalShape.bounds().isFinite()) {
1937         return;
1938     }
1939 
1940     SkIRect clipConservativeBounds;
1941     clip.getConservativeBounds(this->width(), this->height(), &clipConservativeBounds, nullptr);
1942 
1943     GrShape tempShape;
1944     // NVPR cannot handle hairlines, so this would get picked up by a different stencil and
1945     // cover path renderer (i.e. default path renderer). The hairline renderer produces much
1946     // smoother hairlines than MSAA.
1947     GrAllowMixedSamples allowMixedSamples = originalShape.style().isSimpleHairline()
1948                                                     ? GrAllowMixedSamples::kNo
1949                                                     : GrAllowMixedSamples::kYes;
1950     GrAAType aaType = this->chooseAAType(aa, allowMixedSamples);
1951     GrPathRenderer::CanDrawPathArgs canDrawArgs;
1952     canDrawArgs.fCaps = this->caps();
1953     canDrawArgs.fViewMatrix = &viewMatrix;
1954     canDrawArgs.fShape = &originalShape;
1955     canDrawArgs.fClipConservativeBounds = &clipConservativeBounds;
1956     canDrawArgs.fTargetIsWrappedVkSecondaryCB = this->wrapsVkSecondaryCB();
1957     canDrawArgs.fHasUserStencilSettings = false;
1958 
1959     GrPathRenderer* pr;
1960     static constexpr GrPathRendererChain::DrawType kType = GrPathRendererChain::DrawType::kColor;
1961     if (originalShape.isEmpty() && !originalShape.inverseFilled()) {
1962         return;
1963     }
1964 
1965     canDrawArgs.fAAType = aaType;
1966 
1967     // Try a 1st time without applying any of the style to the geometry (and barring sw)
1968     pr = this->drawingManager()->getPathRenderer(canDrawArgs, false, kType);
1969     SkScalar styleScale =  GrStyle::MatrixToScaleFactor(viewMatrix);
1970 
1971     if (!pr && originalShape.style().pathEffect()) {
1972         // It didn't work above, so try again with the path effect applied.
1973         tempShape = originalShape.applyStyle(GrStyle::Apply::kPathEffectOnly, styleScale);
1974         if (tempShape.isEmpty()) {
1975             return;
1976         }
1977         canDrawArgs.fShape = &tempShape;
1978         pr = this->drawingManager()->getPathRenderer(canDrawArgs, false, kType);
1979     }
1980     if (!pr) {
1981         if (canDrawArgs.fShape->style().applies()) {
1982             tempShape = canDrawArgs.fShape->applyStyle(GrStyle::Apply::kPathEffectAndStrokeRec,
1983                                                        styleScale);
1984             if (tempShape.isEmpty()) {
1985                 return;
1986             }
1987             canDrawArgs.fShape = &tempShape;
1988             // This time, allow SW renderer
1989             pr = this->drawingManager()->getPathRenderer(canDrawArgs, true, kType);
1990         } else {
1991             pr = this->drawingManager()->getSoftwarePathRenderer();
1992         }
1993     }
1994 
1995     if (!pr) {
1996 #ifdef SK_DEBUG
1997         SkDebugf("Unable to find path renderer compatible with path.\n");
1998 #endif
1999         return;
2000     }
2001 
2002     GrPathRenderer::DrawPathArgs args{this->drawingManager()->getContext(),
2003                                       std::move(paint),
2004                                       &GrUserStencilSettings::kUnused,
2005                                       this,
2006                                       &clip,
2007                                       &clipConservativeBounds,
2008                                       &viewMatrix,
2009                                       canDrawArgs.fShape,
2010                                       aaType,
2011                                       this->colorSpaceInfo().isLinearlyBlended()};
2012     pr->drawPath(args);
2013 }
2014 
op_bounds(SkRect * bounds,const GrOp * op)2015 static void op_bounds(SkRect* bounds, const GrOp* op) {
2016     *bounds = op->bounds();
2017     if (op->hasZeroArea()) {
2018         if (op->hasAABloat()) {
2019             bounds->outset(0.5f, 0.5f);
2020         } else {
2021             // We don't know which way the particular GPU will snap lines or points at integer
2022             // coords. So we ensure that the bounds is large enough for either snap.
2023             SkRect before = *bounds;
2024             bounds->roundOut(bounds);
2025             if (bounds->fLeft == before.fLeft) {
2026                 bounds->fLeft -= 1;
2027             }
2028             if (bounds->fTop == before.fTop) {
2029                 bounds->fTop -= 1;
2030             }
2031             if (bounds->fRight == before.fRight) {
2032                 bounds->fRight += 1;
2033             }
2034             if (bounds->fBottom == before.fBottom) {
2035                 bounds->fBottom += 1;
2036             }
2037         }
2038     }
2039 }
2040 
addDrawOp(const GrClip & clip,std::unique_ptr<GrDrawOp> op,const std::function<WillAddOpFn> & willAddFn)2041 void GrRenderTargetContext::addDrawOp(const GrClip& clip, std::unique_ptr<GrDrawOp> op,
2042                                       const std::function<WillAddOpFn>& willAddFn) {
2043     ASSERT_SINGLE_OWNER
2044     if (fContext->priv().abandoned()) {
2045         fContext->priv().opMemoryPool()->release(std::move(op));
2046         return;
2047     }
2048     SkDEBUGCODE(this->validate();)
2049     SkDEBUGCODE(op->fAddDrawOpCalled = true;)
2050     GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "addDrawOp", fContext);
2051 
2052     // Setup clip
2053     SkRect bounds;
2054     op_bounds(&bounds, op.get());
2055     GrAppliedClip appliedClip;
2056     GrDrawOp::FixedFunctionFlags fixedFunctionFlags = op->fixedFunctionFlags();
2057     if (!clip.apply(fContext, this, fixedFunctionFlags & GrDrawOp::FixedFunctionFlags::kUsesHWAA,
2058                     fixedFunctionFlags & GrDrawOp::FixedFunctionFlags::kUsesStencil, &appliedClip,
2059                     &bounds)) {
2060         fContext->priv().opMemoryPool()->release(std::move(op));
2061         return;
2062     }
2063 
2064     if (fixedFunctionFlags & GrDrawOp::FixedFunctionFlags::kUsesStencil ||
2065         appliedClip.hasStencilClip()) {
2066         if (this->caps()->performStencilClearsAsDraws()) {
2067             // Must use an op to perform the clear of the stencil buffer before this op, but only
2068             // have to clear the first time any draw needs it (this also ensures we don't loop
2069             // forever when the internal stencil clear adds a draw op that has stencil settings).
2070             if (!fRenderTargetProxy->needsStencil()) {
2071                 // Send false so that the stencil buffer is fully cleared to 0
2072                 this->internalStencilClear(GrFixedClip::Disabled(), /* inside mask */ false);
2073             }
2074         } else {
2075             // Just make sure the stencil buffer is cleared before the draw op, easy to do it as
2076             // a load at the start
2077             this->getRTOpList()->setStencilLoadOp(GrLoadOp::kClear);
2078         }
2079 
2080         this->setNeedsStencil();
2081     }
2082 
2083     GrClampType clampType = GrPixelConfigClampType(this->colorSpaceInfo().config());
2084     GrXferProcessor::DstProxy dstProxy;
2085     GrProcessorSet::Analysis analysis = op->finalize(
2086             *this->caps(), &appliedClip, this->fsaaType(), clampType);
2087     if (analysis.requiresDstTexture()) {
2088         if (!this->setupDstProxy(this->asRenderTargetProxy(), clip, *op, &dstProxy)) {
2089             fContext->priv().opMemoryPool()->release(std::move(op));
2090             return;
2091         }
2092     }
2093 
2094     op->setClippedBounds(bounds);
2095     auto opList = this->getRTOpList();
2096     if (willAddFn) {
2097         willAddFn(op.get(), opList->uniqueID());
2098     }
2099     opList->addDrawOp(std::move(op), analysis, std::move(appliedClip), dstProxy, *this->caps());
2100 }
2101 
setupDstProxy(GrRenderTargetProxy * rtProxy,const GrClip & clip,const GrOp & op,GrXferProcessor::DstProxy * dstProxy)2102 bool GrRenderTargetContext::setupDstProxy(GrRenderTargetProxy* rtProxy, const GrClip& clip,
2103                                           const GrOp& op,
2104                                           GrXferProcessor::DstProxy* dstProxy) {
2105     // If we are wrapping a vulkan secondary command buffer, we can't make a dst copy because we
2106     // don't actually have a VkImage to make a copy of. Additionally we don't have the power to
2107     // start and stop the render pass in order to make the copy.
2108     if (rtProxy->wrapsVkSecondaryCB()) {
2109         return false;
2110     }
2111 
2112     if (this->caps()->textureBarrierSupport()) {
2113         if (GrTextureProxy* texProxy = rtProxy->asTextureProxy()) {
2114             // The render target is a texture, so we can read from it directly in the shader. The XP
2115             // will be responsible to detect this situation and request a texture barrier.
2116             dstProxy->setProxy(sk_ref_sp(texProxy));
2117             dstProxy->setOffset(0, 0);
2118             return true;
2119         }
2120     }
2121 
2122     SkIRect copyRect = SkIRect::MakeWH(rtProxy->width(), rtProxy->height());
2123 
2124     SkIRect clippedRect;
2125     clip.getConservativeBounds(rtProxy->width(), rtProxy->height(), &clippedRect);
2126     SkRect opBounds = op.bounds();
2127     // If the op has aa bloating or is a infinitely thin geometry (hairline) outset the bounds by
2128     // 0.5 pixels.
2129     if (op.hasAABloat() || op.hasZeroArea()) {
2130         opBounds.outset(0.5f, 0.5f);
2131         // An antialiased/hairline draw can sometimes bleed outside of the clips bounds. For
2132         // performance we may ignore the clip when the draw is entirely inside the clip is float
2133         // space but will hit pixels just outside the clip when actually rasterizing.
2134         clippedRect.outset(1, 1);
2135         clippedRect.intersect(SkIRect::MakeWH(rtProxy->width(), rtProxy->height()));
2136     }
2137     SkIRect opIBounds;
2138     opBounds.roundOut(&opIBounds);
2139     if (!clippedRect.intersect(opIBounds)) {
2140 #ifdef SK_DEBUG
2141         GrCapsDebugf(this->caps(), "setupDstTexture: Missed an early reject bailing on draw.");
2142 #endif
2143         return false;
2144     }
2145 
2146     // MSAA consideration: When there is support for reading MSAA samples in the shader we could
2147     // have per-sample dst values by making the copy multisampled.
2148     GrSurfaceDesc desc;
2149     bool rectsMustMatch = false;
2150     bool disallowSubrect = false;
2151     GrSurfaceOrigin origin;
2152     if (!this->caps()->initDescForDstCopy(rtProxy, &desc, &origin, &rectsMustMatch,
2153                                           &disallowSubrect)) {
2154         desc.fFlags = kRenderTarget_GrSurfaceFlag;
2155         desc.fConfig = rtProxy->config();
2156         origin = rtProxy->origin();
2157     }
2158 
2159     if (!disallowSubrect) {
2160         copyRect = clippedRect;
2161     }
2162 
2163     SkIPoint dstPoint, dstOffset;
2164     SkBackingFit fit;
2165     if (rectsMustMatch) {
2166         desc.fWidth = rtProxy->width();
2167         desc.fHeight = rtProxy->height();
2168         dstPoint = {copyRect.fLeft, copyRect.fTop};
2169         dstOffset = {0, 0};
2170         fit = SkBackingFit::kExact;
2171     } else {
2172         desc.fWidth = copyRect.width();
2173         desc.fHeight = copyRect.height();
2174         dstPoint = {0, 0};
2175         dstOffset = {copyRect.fLeft, copyRect.fTop};
2176         fit = SkBackingFit::kApprox;
2177     }
2178 
2179     SkASSERT(rtProxy->backendFormat().textureType() == GrTextureType::k2D);
2180     const GrBackendFormat& format = rtProxy->backendFormat();
2181     sk_sp<GrSurfaceContext> sContext = fContext->priv().makeDeferredSurfaceContext(
2182             format, desc, origin, GrMipMapped::kNo, fit, SkBudgeted::kYes,
2183             sk_ref_sp(this->colorSpaceInfo().colorSpace()));
2184     if (!sContext) {
2185         SkDebugf("setupDstTexture: surfaceContext creation failed.\n");
2186         return false;
2187     }
2188 
2189     if (!sContext->copy(rtProxy, copyRect, dstPoint)) {
2190         SkDebugf("setupDstTexture: copy failed.\n");
2191         return false;
2192     }
2193 
2194     dstProxy->setProxy(sContext->asTextureProxyRef());
2195     dstProxy->setOffset(dstOffset);
2196     return true;
2197 }
2198