GrRenderTargetContext.cpp revision e23bffd65b379aeeb6bb614de81369c130623e92
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 "GrColor.h"
13#include "GrContextPriv.h"
14#include "GrDrawingManager.h"
15#include "GrFixedClip.h"
16#include "GrGpuResourcePriv.h"
17#include "GrPathRenderer.h"
18#include "GrPipelineBuilder.h"
19#include "GrRenderTarget.h"
20#include "GrRenderTargetContextPriv.h"
21#include "GrRenderTargetPriv.h"
22#include "GrResourceProvider.h"
23#include "GrStencilAttachment.h"
24#include "SkDrawShadowRec.h"
25#include "SkLatticeIter.h"
26#include "SkMatrixPriv.h"
27#include "SkSurfacePriv.h"
28#include "effects/GrRRectEffect.h"
29#include "instanced/InstancedRendering.h"
30#include "ops/GrClearOp.h"
31#include "ops/GrClearStencilClipOp.h"
32#include "ops/GrDiscardOp.h"
33#include "ops/GrDrawAtlasOp.h"
34#include "ops/GrDrawOp.h"
35#include "ops/GrDrawVerticesOp.h"
36#include "ops/GrLatticeOp.h"
37#include "ops/GrNonAAFillRectOp.h"
38#include "ops/GrOp.h"
39#include "ops/GrOvalOpFactory.h"
40#include "ops/GrRectOpFactory.h"
41#include "ops/GrRegionOp.h"
42#include "ops/GrShadowRRectOp.h"
43#include "ops/GrStencilPathOp.h"
44#include "text/GrAtlasTextContext.h"
45#include "text/GrStencilAndCoverTextContext.h"
46
47#define ASSERT_OWNED_RESOURCE(R) SkASSERT(!(R) || (R)->getContext() == this->drawingManager()->getContext())
48#define ASSERT_SINGLE_OWNER \
49    SkDEBUGCODE(GrSingleOwner::AutoEnforce debug_SingleOwner(this->singleOwner());)
50#define ASSERT_SINGLE_OWNER_PRIV \
51    SkDEBUGCODE(GrSingleOwner::AutoEnforce debug_SingleOwner(fRenderTargetContext->singleOwner());)
52#define RETURN_IF_ABANDONED        if (this->drawingManager()->wasAbandoned()) { return; }
53#define RETURN_IF_ABANDONED_PRIV   if (fRenderTargetContext->drawingManager()->wasAbandoned()) { return; }
54#define RETURN_FALSE_IF_ABANDONED  if (this->drawingManager()->wasAbandoned()) { return false; }
55#define RETURN_FALSE_IF_ABANDONED_PRIV  if (fRenderTargetContext->drawingManager()->wasAbandoned()) { return false; }
56#define RETURN_NULL_IF_ABANDONED   if (this->drawingManager()->wasAbandoned()) { return nullptr; }
57
58class AutoCheckFlush {
59public:
60    AutoCheckFlush(GrDrawingManager* drawingManager) : fDrawingManager(drawingManager) {
61        SkASSERT(fDrawingManager);
62    }
63    ~AutoCheckFlush() { fDrawingManager->flushIfNecessary(); }
64
65private:
66    GrDrawingManager* fDrawingManager;
67};
68
69bool GrRenderTargetContext::wasAbandoned() const {
70    return this->drawingManager()->wasAbandoned();
71}
72
73// In MDB mode the reffing of the 'getLastOpList' call's result allows in-progress
74// GrOpLists to be picked up and added to by renderTargetContexts lower in the call
75// stack. When this occurs with a closed GrOpList, a new one will be allocated
76// when the renderTargetContext attempts to use it (via getOpList).
77GrRenderTargetContext::GrRenderTargetContext(GrContext* context,
78                                             GrDrawingManager* drawingMgr,
79                                             sk_sp<GrRenderTargetProxy> rtp,
80                                             sk_sp<SkColorSpace> colorSpace,
81                                             const SkSurfaceProps* surfaceProps,
82                                             GrAuditTrail* auditTrail,
83                                             GrSingleOwner* singleOwner)
84    : GrSurfaceContext(context, drawingMgr, std::move(colorSpace), auditTrail, singleOwner)
85    , fRenderTargetProxy(std::move(rtp))
86    , fOpList(sk_ref_sp(fRenderTargetProxy->getLastRenderTargetOpList()))
87    , fInstancedPipelineInfo(fRenderTargetProxy.get())
88    , fColorXformFromSRGB(nullptr)
89    , fSurfaceProps(SkSurfacePropsCopyOrDefault(surfaceProps)) {
90    if (fColorSpace) {
91        // sRGB sources are very common (SkColor, etc...), so we cache that gamut transformation
92        auto srgbColorSpace = SkColorSpace::MakeSRGB();
93        fColorXformFromSRGB = GrColorSpaceXform::Make(srgbColorSpace.get(), fColorSpace.get());
94    }
95    SkDEBUGCODE(this->validate();)
96}
97
98#ifdef SK_DEBUG
99void GrRenderTargetContext::validate() const {
100    SkASSERT(fRenderTargetProxy);
101    fRenderTargetProxy->validate(fContext);
102
103    if (fOpList && !fOpList->isClosed()) {
104        SkASSERT(fRenderTargetProxy->getLastOpList() == fOpList.get());
105    }
106}
107#endif
108
109GrRenderTargetContext::~GrRenderTargetContext() {
110    ASSERT_SINGLE_OWNER
111}
112
113GrTextureProxy* GrRenderTargetContext::asTextureProxy() {
114    return fRenderTargetProxy->asTextureProxy();
115}
116
117sk_sp<GrTextureProxy> GrRenderTargetContext::asTextureProxyRef() {
118    return sk_ref_sp(fRenderTargetProxy->asTextureProxy());
119}
120
121GrRenderTargetOpList* GrRenderTargetContext::getOpList() {
122    ASSERT_SINGLE_OWNER
123    SkDEBUGCODE(this->validate();)
124
125    if (!fOpList || fOpList->isClosed()) {
126        fOpList = this->drawingManager()->newRTOpList(fRenderTargetProxy.get());
127    }
128
129    return fOpList.get();
130}
131
132// MDB TODO: move this (and GrTextContext::copy) to GrSurfaceContext?
133bool GrRenderTargetContext::onCopy(GrSurfaceProxy* srcProxy,
134                                   const SkIRect& srcRect,
135                                   const SkIPoint& dstPoint) {
136    ASSERT_SINGLE_OWNER
137    RETURN_FALSE_IF_ABANDONED
138    SkDEBUGCODE(this->validate();)
139    GR_AUDIT_TRAIL_AUTO_FRAME(fAuditTrail, "GrRenderTargetContext::onCopy");
140
141    return this->getOpList()->copySurface(*this->caps(),
142                                          this->asSurfaceProxy(), srcProxy, srcRect, dstPoint);
143}
144
145void GrRenderTargetContext::drawText(const GrClip& clip, const SkPaint& skPaint,
146                                     const SkMatrix& viewMatrix, const char text[],
147                                     size_t byteLength, SkScalar x, SkScalar y,
148                                     const SkIRect& clipBounds) {
149    ASSERT_SINGLE_OWNER
150    RETURN_IF_ABANDONED
151    SkDEBUGCODE(this->validate();)
152    GR_AUDIT_TRAIL_AUTO_FRAME(fAuditTrail, "GrRenderTargetContext::drawText");
153
154    GrAtlasTextContext* atlasTextContext = this->drawingManager()->getAtlasTextContext();
155    atlasTextContext->drawText(fContext, this, clip, skPaint, viewMatrix, fSurfaceProps, text,
156                               byteLength, x, y, clipBounds);
157}
158
159void GrRenderTargetContext::drawPosText(const GrClip& clip, const SkPaint& paint,
160                                        const SkMatrix& viewMatrix, const char text[],
161                                        size_t byteLength, const SkScalar pos[],
162                                        int scalarsPerPosition, const SkPoint& offset,
163                                        const SkIRect& clipBounds) {
164    ASSERT_SINGLE_OWNER
165    RETURN_IF_ABANDONED
166    SkDEBUGCODE(this->validate();)
167    GR_AUDIT_TRAIL_AUTO_FRAME(fAuditTrail, "GrRenderTargetContext::drawPosText");
168
169    GrAtlasTextContext* atlasTextContext = this->drawingManager()->getAtlasTextContext();
170    atlasTextContext->drawPosText(fContext, this, clip, paint, viewMatrix, fSurfaceProps, text,
171                                  byteLength, pos, scalarsPerPosition, offset, clipBounds);
172}
173
174void GrRenderTargetContext::drawTextBlob(const GrClip& clip, const SkPaint& paint,
175                                         const SkMatrix& viewMatrix, const SkTextBlob* blob,
176                                         SkScalar x, SkScalar y, SkDrawFilter* filter,
177                                         const SkIRect& clipBounds) {
178    ASSERT_SINGLE_OWNER
179    RETURN_IF_ABANDONED
180    SkDEBUGCODE(this->validate();)
181    GR_AUDIT_TRAIL_AUTO_FRAME(fAuditTrail, "GrRenderTargetContext::drawTextBlob");
182
183    GrAtlasTextContext* atlasTextContext = this->drawingManager()->getAtlasTextContext();
184    atlasTextContext->drawTextBlob(fContext, this, clip, paint, viewMatrix, fSurfaceProps, blob, x,
185                                   y, filter, clipBounds);
186}
187
188void GrRenderTargetContext::discard() {
189    ASSERT_SINGLE_OWNER
190    RETURN_IF_ABANDONED
191    SkDEBUGCODE(this->validate();)
192    GR_AUDIT_TRAIL_AUTO_FRAME(fAuditTrail, "GrRenderTargetContext::discard");
193
194    AutoCheckFlush acf(this->drawingManager());
195
196    // Currently this just inserts a discard op. However, once in MDB this can remove all the
197    // previously recorded ops and change the load op to discard.
198    if (this->caps()->discardRenderTargetSupport()) {
199        std::unique_ptr<GrOp> op(GrDiscardOp::Make(fRenderTargetProxy.get()));
200        if (!op) {
201            return;
202        }
203        this->getOpList()->addOp(std::move(op), *this->caps());
204    }
205}
206
207void GrRenderTargetContext::clear(const SkIRect* rect,
208                                  const GrColor color,
209                                  bool canIgnoreRect) {
210    ASSERT_SINGLE_OWNER
211    RETURN_IF_ABANDONED
212    SkDEBUGCODE(this->validate();)
213    GR_AUDIT_TRAIL_AUTO_FRAME(fAuditTrail, "GrRenderTargetContext::clear");
214
215    AutoCheckFlush acf(this->drawingManager());
216    this->internalClear(rect ? GrFixedClip(*rect) : GrFixedClip::Disabled(), color, canIgnoreRect);
217}
218
219void GrRenderTargetContextPriv::absClear(const SkIRect* clearRect, const GrColor color) {
220    ASSERT_SINGLE_OWNER_PRIV
221    RETURN_IF_ABANDONED_PRIV
222    SkDEBUGCODE(fRenderTargetContext->validate();)
223    GR_AUDIT_TRAIL_AUTO_FRAME(fRenderTargetContext->fAuditTrail,
224                              "GrRenderTargetContext::absClear");
225
226    AutoCheckFlush acf(fRenderTargetContext->drawingManager());
227
228    SkIRect rtRect = SkIRect::MakeWH(fRenderTargetContext->fRenderTargetProxy->worstCaseWidth(),
229                                     fRenderTargetContext->fRenderTargetProxy->worstCaseHeight());
230
231    if (clearRect) {
232        if (clearRect->contains(rtRect)) {
233            clearRect = nullptr; // full screen
234        } else {
235            if (!rtRect.intersect(*clearRect)) {
236                return;
237            }
238        }
239    }
240
241    // TODO: in a post-MDB world this should be handled at the OpList level.
242    // An op-list that is initially cleared and has no other ops should receive an
243    // extra draw.
244    if (fRenderTargetContext->fContext->caps()->useDrawInsteadOfClear()) {
245        // This works around a driver bug with clear by drawing a rect instead.
246        // The driver will ignore a clear if it is the only thing rendered to a
247        // target before the target is read.
248        GrPaint paint;
249        paint.setColor4f(GrColor4f::FromGrColor(color));
250        paint.setXPFactory(GrPorterDuffXPFactory::Get(SkBlendMode::kSrc));
251
252        // We don't call drawRect() here to avoid the cropping to the, possibly smaller,
253        // RenderTargetProxy bounds
254        fRenderTargetContext->drawNonAAFilledRect(GrNoClip(), std::move(paint), SkMatrix::I(),
255                                                  SkRect::Make(rtRect), nullptr, nullptr, nullptr,
256                                                  GrAAType::kNone);
257
258    } else {
259        // This path doesn't handle coalescing of full screen clears b.c. it
260        // has to clear the entire render target - not just the content area.
261        // It could be done but will take more finagling.
262        std::unique_ptr<GrOp> op(GrClearOp::Make(rtRect, color, !clearRect));
263        if (!op) {
264            return;
265        }
266        fRenderTargetContext->getOpList()->addOp(std::move(op), *fRenderTargetContext->caps());
267    }
268}
269
270void GrRenderTargetContextPriv::clear(const GrFixedClip& clip,
271                                      const GrColor color,
272                                      bool canIgnoreClip) {
273    ASSERT_SINGLE_OWNER_PRIV
274    RETURN_IF_ABANDONED_PRIV
275    SkDEBUGCODE(fRenderTargetContext->validate();)
276    GR_AUDIT_TRAIL_AUTO_FRAME(fRenderTargetContext->fAuditTrail,
277                              "GrRenderTargetContextPriv::clear");
278
279    AutoCheckFlush acf(fRenderTargetContext->drawingManager());
280    fRenderTargetContext->internalClear(clip, color, canIgnoreClip);
281}
282
283void GrRenderTargetContext::internalClear(const GrFixedClip& clip,
284                                          const GrColor color,
285                                          bool canIgnoreClip) {
286    bool isFull = false;
287    if (!clip.hasWindowRectangles()) {
288        isFull = !clip.scissorEnabled() ||
289                 (canIgnoreClip && fContext->caps()->fullClearIsFree()) ||
290                 clip.scissorRect().contains(SkIRect::MakeWH(this->width(), this->height()));
291    }
292
293    if (fContext->caps()->useDrawInsteadOfClear()) {
294        // This works around a driver bug with clear by drawing a rect instead.
295        // The driver will ignore a clear if it is the only thing rendered to a
296        // target before the target is read.
297        SkIRect clearRect = SkIRect::MakeWH(this->width(), this->height());
298        if (isFull) {
299            this->discard();
300        } else if (!clearRect.intersect(clip.scissorRect())) {
301            return;
302        }
303
304        GrPaint paint;
305        paint.setColor4f(GrColor4f::FromGrColor(color));
306        paint.setXPFactory(GrPorterDuffXPFactory::Get(SkBlendMode::kSrc));
307
308        this->drawRect(clip, std::move(paint), GrAA::kNo, SkMatrix::I(), SkRect::Make(clearRect));
309    } else if (isFull) {
310        this->getOpList()->fullClear(*this->caps(), color);
311    } else {
312        std::unique_ptr<GrOp> op(GrClearOp::Make(clip, color, this->asSurfaceProxy()));
313        if (!op) {
314            return;
315        }
316        this->getOpList()->addOp(std::move(op), *this->caps());
317    }
318}
319
320void GrRenderTargetContext::drawPaint(const GrClip& clip,
321                                      GrPaint&& paint,
322                                      const SkMatrix& viewMatrix) {
323    ASSERT_SINGLE_OWNER
324    RETURN_IF_ABANDONED
325    SkDEBUGCODE(this->validate();)
326    GR_AUDIT_TRAIL_AUTO_FRAME(fAuditTrail, "GrRenderTargetContext::drawPaint");
327
328    // set rect to be big enough to fill the space, but not super-huge, so we
329    // don't overflow fixed-point implementations
330
331    SkRect r = fRenderTargetProxy->getBoundsRect();
332
333    SkRRect rrect;
334    GrAA aa;
335    // Check if we can replace a clipRRect()/drawPaint() with a drawRRect(). We only do the
336    // transformation for non-rect rrects. Rects caused a performance regression on an Android
337    // test that needs investigation. We also skip cases where there are fragment processors
338    // because they may depend on having correct local coords and this path draws in device space
339    // without a local matrix.
340    if (!paint.numTotalFragmentProcessors() && clip.isRRect(r, &rrect, &aa) && !rrect.isRect()) {
341        this->drawRRect(GrNoClip(), std::move(paint), aa, SkMatrix::I(), rrect,
342                        GrStyle::SimpleFill());
343        return;
344    }
345
346
347    bool isPerspective = viewMatrix.hasPerspective();
348
349    // We attempt to map r by the inverse matrix and draw that. mapRect will
350    // map the four corners and bound them with a new rect. This will not
351    // produce a correct result for some perspective matrices.
352    if (!isPerspective) {
353        if (!SkMatrixPriv::InverseMapRect(viewMatrix, &r, r)) {
354            SkDebugf("Could not invert matrix\n");
355            return;
356        }
357        this->drawRect(clip, std::move(paint), GrAA::kNo, viewMatrix, r);
358    } else {
359        SkMatrix localMatrix;
360        if (!viewMatrix.invert(&localMatrix)) {
361            SkDebugf("Could not invert matrix\n");
362            return;
363        }
364
365        AutoCheckFlush acf(this->drawingManager());
366
367        this->drawNonAAFilledRect(clip, std::move(paint), SkMatrix::I(), r, nullptr, &localMatrix,
368                                  nullptr, GrAAType::kNone);
369    }
370}
371
372static inline bool rect_contains_inclusive(const SkRect& rect, const SkPoint& point) {
373    return point.fX >= rect.fLeft && point.fX <= rect.fRight &&
374           point.fY >= rect.fTop && point.fY <= rect.fBottom;
375}
376
377static bool view_matrix_ok_for_aa_fill_rect(const SkMatrix& viewMatrix) {
378    return viewMatrix.preservesRightAngles();
379}
380
381// Attempts to crop a rect and optional local rect to the clip boundaries.
382// Returns false if the draw can be skipped entirely.
383static bool crop_filled_rect(int width, int height, const GrClip& clip,
384                             const SkMatrix& viewMatrix, SkRect* rect,
385                             SkRect* localRect = nullptr) {
386    if (!viewMatrix.rectStaysRect()) {
387        return true;
388    }
389
390    SkIRect clipDevBounds;
391    SkRect clipBounds;
392
393    clip.getConservativeBounds(width, height, &clipDevBounds);
394    if (!SkMatrixPriv::InverseMapRect(viewMatrix, &clipBounds, SkRect::Make(clipDevBounds))) {
395        return false;
396    }
397
398    if (localRect) {
399        if (!rect->intersects(clipBounds)) {
400            return false;
401        }
402        const SkScalar dx = localRect->width() / rect->width();
403        const SkScalar dy = localRect->height() / rect->height();
404        if (clipBounds.fLeft > rect->fLeft) {
405            localRect->fLeft += (clipBounds.fLeft - rect->fLeft) * dx;
406            rect->fLeft = clipBounds.fLeft;
407        }
408        if (clipBounds.fTop > rect->fTop) {
409            localRect->fTop += (clipBounds.fTop - rect->fTop) * dy;
410            rect->fTop = clipBounds.fTop;
411        }
412        if (clipBounds.fRight < rect->fRight) {
413            localRect->fRight -= (rect->fRight - clipBounds.fRight) * dx;
414            rect->fRight = clipBounds.fRight;
415        }
416        if (clipBounds.fBottom < rect->fBottom) {
417            localRect->fBottom -= (rect->fBottom - clipBounds.fBottom) * dy;
418            rect->fBottom = clipBounds.fBottom;
419        }
420        return true;
421    }
422
423    return rect->intersect(clipBounds);
424}
425
426bool GrRenderTargetContext::drawFilledRect(const GrClip& clip,
427                                           GrPaint&& paint,
428                                           GrAA aa,
429                                           const SkMatrix& viewMatrix,
430                                           const SkRect& rect,
431                                           const GrUserStencilSettings* ss) {
432    SkRect croppedRect = rect;
433    if (!crop_filled_rect(this->width(), this->height(), clip, viewMatrix, &croppedRect)) {
434        return true;
435    }
436
437    if (GrCaps::InstancedSupport::kNone != fContext->caps()->instancedSupport() &&
438        (!ss || ss->isDisabled(false))) {
439        gr_instanced::OpAllocator* oa = this->drawingManager()->instancingAllocator();
440        std::unique_ptr<GrDrawOp> op = oa->recordRect(croppedRect, viewMatrix, std::move(paint),
441                                                      aa, fInstancedPipelineInfo);
442        if (op) {
443            this->addDrawOp(clip, std::move(op));
444            return true;
445        }
446    }
447    GrAAType aaType = this->chooseAAType(aa, GrAllowMixedSamples::kNo);
448    if (GrAAType::kCoverage == aaType) {
449        // The fill path can handle rotation but not skew.
450        if (view_matrix_ok_for_aa_fill_rect(viewMatrix)) {
451            SkRect devBoundRect;
452            viewMatrix.mapRect(&devBoundRect, croppedRect);
453            std::unique_ptr<GrLegacyMeshDrawOp> op =
454                    GrRectOpFactory::MakeAAFill(paint, viewMatrix, rect, croppedRect, devBoundRect);
455            if (op) {
456                GrPipelineBuilder pipelineBuilder(std::move(paint), aaType);
457                if (ss) {
458                    pipelineBuilder.setUserStencil(ss);
459                }
460                this->addLegacyMeshDrawOp(std::move(pipelineBuilder), clip, std::move(op));
461                return true;
462            }
463        }
464    } else {
465        this->drawNonAAFilledRect(clip, std::move(paint), viewMatrix, croppedRect, nullptr, nullptr,
466                                  ss, aaType);
467        return true;
468    }
469
470    return false;
471}
472
473void GrRenderTargetContext::drawRect(const GrClip& clip,
474                                     GrPaint&& paint,
475                                     GrAA aa,
476                                     const SkMatrix& viewMatrix,
477                                     const SkRect& rect,
478                                     const GrStyle* style) {
479    if (!style) {
480        style = &GrStyle::SimpleFill();
481    }
482    ASSERT_SINGLE_OWNER
483    RETURN_IF_ABANDONED
484    SkDEBUGCODE(this->validate();)
485    GR_AUDIT_TRAIL_AUTO_FRAME(fAuditTrail, "GrRenderTargetContext::drawRect");
486
487    // Path effects should've been devolved to a path in SkGpuDevice
488    SkASSERT(!style->pathEffect());
489
490    AutoCheckFlush acf(this->drawingManager());
491
492    const SkStrokeRec& stroke = style->strokeRec();
493    if (stroke.getStyle() == SkStrokeRec::kFill_Style) {
494
495        if (!fContext->caps()->useDrawInsteadOfClear()) {
496            // Check if this is a full RT draw and can be replaced with a clear. We don't bother
497            // checking cases where the RT is fully inside a stroke.
498            SkRect rtRect = fRenderTargetProxy->getBoundsRect();
499            // Does the clip contain the entire RT?
500            if (clip.quickContains(rtRect)) {
501                SkMatrix invM;
502                if (!viewMatrix.invert(&invM)) {
503                    return;
504                }
505                // Does the rect bound the RT?
506                SkPoint srcSpaceRTQuad[4];
507                invM.mapRectToQuad(srcSpaceRTQuad, rtRect);
508                if (rect_contains_inclusive(rect, srcSpaceRTQuad[0]) &&
509                    rect_contains_inclusive(rect, srcSpaceRTQuad[1]) &&
510                    rect_contains_inclusive(rect, srcSpaceRTQuad[2]) &&
511                    rect_contains_inclusive(rect, srcSpaceRTQuad[3])) {
512                    // Will it blend?
513                    GrColor clearColor;
514                    if (paint.isConstantBlendedColor(&clearColor)) {
515                        this->clear(nullptr, clearColor, true);
516                        return;
517                    }
518                }
519            }
520        }
521
522        if (this->drawFilledRect(clip, std::move(paint), aa, viewMatrix, rect, nullptr)) {
523            return;
524        }
525    } else if (stroke.getStyle() == SkStrokeRec::kStroke_Style ||
526               stroke.getStyle() == SkStrokeRec::kHairline_Style) {
527        if ((!rect.width() || !rect.height()) &&
528            SkStrokeRec::kHairline_Style != stroke.getStyle()) {
529            SkScalar r = stroke.getWidth() / 2;
530            // TODO: Move these stroke->fill fallbacks to GrShape?
531            switch (stroke.getJoin()) {
532                case SkPaint::kMiter_Join:
533                    this->drawRect(
534                            clip, std::move(paint), aa, viewMatrix,
535                            {rect.fLeft - r, rect.fTop - r, rect.fRight + r, rect.fBottom + r},
536                            &GrStyle::SimpleFill());
537                    return;
538                case SkPaint::kRound_Join:
539                    // Raster draws nothing when both dimensions are empty.
540                    if (rect.width() || rect.height()){
541                        SkRRect rrect = SkRRect::MakeRectXY(rect.makeOutset(r, r), r, r);
542                        this->drawRRect(clip, std::move(paint), aa, viewMatrix, rrect,
543                                        GrStyle::SimpleFill());
544                        return;
545                    }
546                case SkPaint::kBevel_Join:
547                    if (!rect.width()) {
548                        this->drawRect(clip, std::move(paint), aa, viewMatrix,
549                                       {rect.fLeft - r, rect.fTop, rect.fRight + r, rect.fBottom},
550                                       &GrStyle::SimpleFill());
551                    } else {
552                        this->drawRect(clip, std::move(paint), aa, viewMatrix,
553                                       {rect.fLeft, rect.fTop - r, rect.fRight, rect.fBottom + r},
554                                       &GrStyle::SimpleFill());
555                    }
556                    return;
557                }
558        }
559
560        bool snapToPixelCenters = false;
561        std::unique_ptr<GrLegacyMeshDrawOp> op;
562
563        GrColor color = paint.getColor();
564        GrAAType aaType = this->chooseAAType(aa, GrAllowMixedSamples::kNo);
565        if (GrAAType::kCoverage == aaType) {
566            // The stroke path needs the rect to remain axis aligned (no rotation or skew).
567            if (viewMatrix.rectStaysRect()) {
568                op = GrRectOpFactory::MakeAAStroke(color, viewMatrix, rect, stroke);
569            }
570        } else {
571            // Depending on sub-pixel coordinates and the particular GPU, we may lose a corner of
572            // hairline rects. We jam all the vertices to pixel centers to avoid this, but not
573            // when MSAA is enabled because it can cause ugly artifacts.
574            snapToPixelCenters = stroke.getStyle() == SkStrokeRec::kHairline_Style &&
575                                 GrFSAAType::kUnifiedMSAA != fRenderTargetProxy->fsaaType();
576            op = GrRectOpFactory::MakeNonAAStroke(color, viewMatrix, rect, stroke,
577                                                  snapToPixelCenters);
578        }
579
580        if (op) {
581            GrPipelineBuilder pipelineBuilder(std::move(paint), aaType);
582            pipelineBuilder.setSnapVerticesToPixelCenters(snapToPixelCenters);
583            this->addLegacyMeshDrawOp(std::move(pipelineBuilder), clip, std::move(op));
584            return;
585        }
586    }
587
588    SkPath path;
589    path.setIsVolatile(true);
590    path.addRect(rect);
591    this->internalDrawPath(clip, std::move(paint), aa, viewMatrix, path, *style);
592}
593
594int GrRenderTargetContextPriv::maxWindowRectangles() const {
595    return fRenderTargetContext->fRenderTargetProxy->maxWindowRectangles(
596                                                    *fRenderTargetContext->fContext->caps());
597}
598
599void GrRenderTargetContextPriv::clearStencilClip(const GrFixedClip& clip, bool insideStencilMask) {
600    ASSERT_SINGLE_OWNER_PRIV
601    RETURN_IF_ABANDONED_PRIV
602    SkDEBUGCODE(fRenderTargetContext->validate();)
603    GR_AUDIT_TRAIL_AUTO_FRAME(fRenderTargetContext->fAuditTrail,
604                              "GrRenderTargetContextPriv::clearStencilClip");
605
606    AutoCheckFlush acf(fRenderTargetContext->drawingManager());
607
608    std::unique_ptr<GrOp> op(GrClearStencilClipOp::Make(
609                                                 clip, insideStencilMask,
610                                                 fRenderTargetContext->fRenderTargetProxy.get()));
611    if (!op) {
612        return;
613    }
614    fRenderTargetContext->getOpList()->addOp(std::move(op), *fRenderTargetContext->caps());
615}
616
617void GrRenderTargetContextPriv::stencilPath(const GrClip& clip,
618                                            GrAAType aaType,
619                                            const SkMatrix& viewMatrix,
620                                            const GrPath* path) {
621    ASSERT_SINGLE_OWNER_PRIV
622    RETURN_IF_ABANDONED_PRIV
623    SkDEBUGCODE(fRenderTargetContext->validate();)
624    GR_AUDIT_TRAIL_AUTO_FRAME(fRenderTargetContext->fAuditTrail,
625                              "GrRenderTargetContext::stencilPath");
626
627    SkASSERT(aaType != GrAAType::kCoverage);
628
629    bool useHWAA = GrAATypeIsHW(aaType);
630    // TODO: extract portions of checkDraw that are relevant to path stenciling.
631    SkASSERT(path);
632    SkASSERT(fRenderTargetContext->caps()->shaderCaps()->pathRenderingSupport());
633
634    // FIXME: Use path bounds instead of this WAR once
635    // https://bugs.chromium.org/p/skia/issues/detail?id=5640 is resolved.
636    SkRect bounds = SkRect::MakeIWH(fRenderTargetContext->width(), fRenderTargetContext->height());
637
638    // Setup clip
639    GrAppliedClip appliedClip;
640    if (!clip.apply(fRenderTargetContext->fContext, fRenderTargetContext, useHWAA, true,
641                    &appliedClip, &bounds)) {
642        return;
643    }
644
645    // Coverage AA does not make sense when rendering to the stencil buffer. The caller should never
646    // attempt this in a situation that would require coverage AA.
647    SkASSERT(!appliedClip.clipCoverageFragmentProcessor());
648
649    GrRenderTarget* rt = fRenderTargetContext->accessRenderTarget();
650    if (!rt) {
651        return;
652    }
653    GrStencilAttachment* stencilAttachment =
654            fRenderTargetContext->fContext->resourceProvider()->attachStencilAttachment(rt);
655    if (!stencilAttachment) {
656        SkDebugf("ERROR creating stencil attachment. Draw skipped.\n");
657        return;
658    }
659
660    std::unique_ptr<GrOp> op = GrStencilPathOp::Make(viewMatrix,
661                                                     useHWAA,
662                                                     path->getFillType(),
663                                                     appliedClip.hasStencilClip(),
664                                                     stencilAttachment->bits(),
665                                                     appliedClip.scissorState(),
666                                                     path);
667    if (!op) {
668        return;
669    }
670    op->setClippedBounds(bounds);
671    fRenderTargetContext->getOpList()->addOp(std::move(op), *fRenderTargetContext->caps());
672}
673
674void GrRenderTargetContextPriv::stencilRect(const GrClip& clip,
675                                            const GrUserStencilSettings* ss,
676                                            GrAAType aaType,
677                                            const SkMatrix& viewMatrix,
678                                            const SkRect& rect) {
679    ASSERT_SINGLE_OWNER_PRIV
680    RETURN_IF_ABANDONED_PRIV
681    SkDEBUGCODE(fRenderTargetContext->validate();)
682    GR_AUDIT_TRAIL_AUTO_FRAME(fRenderTargetContext->fAuditTrail,
683                              "GrRenderTargetContext::stencilRect");
684    SkASSERT(GrAAType::kCoverage != aaType);
685    AutoCheckFlush acf(fRenderTargetContext->drawingManager());
686
687    GrPaint paint;
688    paint.setXPFactory(GrDisableColorXPFactory::Get());
689
690    fRenderTargetContext->drawNonAAFilledRect(clip, std::move(paint), viewMatrix, rect, nullptr,
691                                              nullptr, ss, aaType);
692}
693
694bool GrRenderTargetContextPriv::drawAndStencilRect(const GrClip& clip,
695                                                   const GrUserStencilSettings* ss,
696                                                   SkRegion::Op op,
697                                                   bool invert,
698                                                   GrAA aa,
699                                                   const SkMatrix& viewMatrix,
700                                                   const SkRect& rect) {
701    ASSERT_SINGLE_OWNER_PRIV
702    RETURN_FALSE_IF_ABANDONED_PRIV
703    SkDEBUGCODE(fRenderTargetContext->validate();)
704    GR_AUDIT_TRAIL_AUTO_FRAME(fRenderTargetContext->fAuditTrail,
705                              "GrRenderTargetContext::drawAndStencilRect");
706
707    AutoCheckFlush acf(fRenderTargetContext->drawingManager());
708
709    GrPaint paint;
710    paint.setCoverageSetOpXPFactory(op, invert);
711
712    if (fRenderTargetContext->drawFilledRect(clip, std::move(paint), aa, viewMatrix, rect, ss)) {
713        return true;
714    }
715    SkPath path;
716    path.setIsVolatile(true);
717    path.addRect(rect);
718    return this->drawAndStencilPath(clip, ss, op, invert, aa, viewMatrix, path);
719}
720
721void GrRenderTargetContext::fillRectToRect(const GrClip& clip,
722                                           GrPaint&& paint,
723                                           GrAA aa,
724                                           const SkMatrix& viewMatrix,
725                                           const SkRect& rectToDraw,
726                                           const SkRect& localRect) {
727    ASSERT_SINGLE_OWNER
728    RETURN_IF_ABANDONED
729    SkDEBUGCODE(this->validate();)
730    GR_AUDIT_TRAIL_AUTO_FRAME(fAuditTrail, "GrRenderTargetContext::fillRectToRect");
731
732    SkRect croppedRect = rectToDraw;
733    SkRect croppedLocalRect = localRect;
734    if (!crop_filled_rect(this->width(), this->height(), clip, viewMatrix,
735                          &croppedRect, &croppedLocalRect)) {
736        return;
737    }
738
739    AutoCheckFlush acf(this->drawingManager());
740
741    if (GrCaps::InstancedSupport::kNone != fContext->caps()->instancedSupport()) {
742        gr_instanced::OpAllocator* oa = this->drawingManager()->instancingAllocator();
743        std::unique_ptr<GrDrawOp> op(oa->recordRect(croppedRect, viewMatrix, std::move(paint),
744                                                    croppedLocalRect, aa, fInstancedPipelineInfo));
745        if (op) {
746            this->addDrawOp(clip, std::move(op));
747            return;
748        }
749    }
750
751    GrAAType aaType = this->chooseAAType(aa, GrAllowMixedSamples::kNo);
752    if (GrAAType::kCoverage != aaType) {
753        this->drawNonAAFilledRect(clip, std::move(paint), viewMatrix, croppedRect,
754                                  &croppedLocalRect, nullptr, nullptr, aaType);
755        return;
756    }
757
758    if (view_matrix_ok_for_aa_fill_rect(viewMatrix)) {
759        std::unique_ptr<GrLegacyMeshDrawOp> op = GrAAFillRectOp::MakeWithLocalRect(
760                paint.getColor(), viewMatrix, croppedRect, croppedLocalRect);
761        GrPipelineBuilder pipelineBuilder(std::move(paint), aaType);
762        this->addLegacyMeshDrawOp(std::move(pipelineBuilder), clip, std::move(op));
763        return;
764    }
765
766    SkMatrix viewAndUnLocalMatrix;
767    if (!viewAndUnLocalMatrix.setRectToRect(localRect, rectToDraw, SkMatrix::kFill_ScaleToFit)) {
768        SkDebugf("fillRectToRect called with empty local matrix.\n");
769        return;
770    }
771    viewAndUnLocalMatrix.postConcat(viewMatrix);
772
773    SkPath path;
774    path.setIsVolatile(true);
775    path.addRect(localRect);
776    this->internalDrawPath(clip, std::move(paint), aa, viewAndUnLocalMatrix, path, GrStyle());
777}
778
779void GrRenderTargetContext::fillRectWithLocalMatrix(const GrClip& clip,
780                                                    GrPaint&& paint,
781                                                    GrAA aa,
782                                                    const SkMatrix& viewMatrix,
783                                                    const SkRect& rectToDraw,
784                                                    const SkMatrix& localMatrix) {
785    ASSERT_SINGLE_OWNER
786    RETURN_IF_ABANDONED
787    SkDEBUGCODE(this->validate();)
788    GR_AUDIT_TRAIL_AUTO_FRAME(fAuditTrail, "GrRenderTargetContext::fillRectWithLocalMatrix");
789
790    SkRect croppedRect = rectToDraw;
791    if (!crop_filled_rect(this->width(), this->height(), clip, viewMatrix, &croppedRect)) {
792        return;
793    }
794
795    AutoCheckFlush acf(this->drawingManager());
796
797    if (GrCaps::InstancedSupport::kNone != fContext->caps()->instancedSupport()) {
798        gr_instanced::OpAllocator* oa = this->drawingManager()->instancingAllocator();
799        std::unique_ptr<GrDrawOp> op(oa->recordRect(croppedRect, viewMatrix, std::move(paint),
800                                                    localMatrix, aa, fInstancedPipelineInfo));
801        if (op) {
802            this->addDrawOp(clip, std::move(op));
803            return;
804        }
805    }
806
807    GrAAType aaType = this->chooseAAType(aa, GrAllowMixedSamples::kNo);
808    if (GrAAType::kCoverage != aaType) {
809        this->drawNonAAFilledRect(clip, std::move(paint), viewMatrix, croppedRect, nullptr,
810                                  &localMatrix, nullptr, aaType);
811        return;
812    }
813
814    if (view_matrix_ok_for_aa_fill_rect(viewMatrix)) {
815        std::unique_ptr<GrLegacyMeshDrawOp> op =
816                GrAAFillRectOp::Make(paint.getColor(), viewMatrix, localMatrix, croppedRect);
817        GrPipelineBuilder pipelineBuilder(std::move(paint), aaType);
818        this->addLegacyMeshDrawOp(std::move(pipelineBuilder), clip, std::move(op));
819        return;
820    }
821
822    SkMatrix viewAndUnLocalMatrix;
823    if (!localMatrix.invert(&viewAndUnLocalMatrix)) {
824        SkDebugf("fillRectWithLocalMatrix called with degenerate local matrix.\n");
825        return;
826    }
827    viewAndUnLocalMatrix.postConcat(viewMatrix);
828
829    SkPath path;
830    path.setIsVolatile(true);
831    path.addRect(rectToDraw);
832    path.transform(localMatrix);
833    this->internalDrawPath(clip, std::move(paint), aa, viewAndUnLocalMatrix, path, GrStyle());
834}
835
836void GrRenderTargetContext::drawVertices(const GrClip& clip,
837                                         GrPaint&& paint,
838                                         const SkMatrix& viewMatrix,
839                                         sk_sp<SkVertices> vertices,
840                                         GrPrimitiveType* overridePrimType) {
841    ASSERT_SINGLE_OWNER
842    RETURN_IF_ABANDONED
843    SkDEBUGCODE(this->validate();)
844    GR_AUDIT_TRAIL_AUTO_FRAME(fAuditTrail, "GrRenderTargetContext::drawVertices");
845
846    AutoCheckFlush acf(this->drawingManager());
847
848    SkASSERT(vertices);
849    std::unique_ptr<GrLegacyMeshDrawOp> op = GrDrawVerticesOp::Make(paint.getColor(),
850                                                                    std::move(vertices), viewMatrix,
851                                                                    this->isGammaCorrect(),
852                                                                    fColorXformFromSRGB,
853                                                                    overridePrimType);
854    if (!op) {
855        return;
856    }
857    GrPipelineBuilder pipelineBuilder(std::move(paint), GrAAType::kNone);
858    this->addLegacyMeshDrawOp(std::move(pipelineBuilder), clip, std::move(op));
859}
860
861///////////////////////////////////////////////////////////////////////////////
862
863void GrRenderTargetContext::drawAtlas(const GrClip& clip,
864                                      GrPaint&& paint,
865                                      const SkMatrix& viewMatrix,
866                                      int spriteCount,
867                                      const SkRSXform xform[],
868                                      const SkRect texRect[],
869                                      const SkColor colors[]) {
870    ASSERT_SINGLE_OWNER
871    RETURN_IF_ABANDONED
872    SkDEBUGCODE(this->validate();)
873    GR_AUDIT_TRAIL_AUTO_FRAME(fAuditTrail, "GrRenderTargetContext::drawAtlas");
874
875    AutoCheckFlush acf(this->drawingManager());
876
877    std::unique_ptr<GrLegacyMeshDrawOp> op =
878            GrDrawAtlasOp::Make(paint.getColor(), viewMatrix, spriteCount, xform, texRect, colors);
879    GrPipelineBuilder pipelineBuilder(std::move(paint), GrAAType::kNone);
880    this->addLegacyMeshDrawOp(std::move(pipelineBuilder), clip, std::move(op));
881}
882
883///////////////////////////////////////////////////////////////////////////////
884
885void GrRenderTargetContext::drawRRect(const GrClip& origClip,
886                                      GrPaint&& paint,
887                                      GrAA aa,
888                                      const SkMatrix& viewMatrix,
889                                      const SkRRect& rrect,
890                                      const GrStyle& style) {
891    ASSERT_SINGLE_OWNER
892    RETURN_IF_ABANDONED
893    SkDEBUGCODE(this->validate();)
894    GR_AUDIT_TRAIL_AUTO_FRAME(fAuditTrail, "GrRenderTargetContext::drawRRect");
895    if (rrect.isEmpty()) {
896       return;
897    }
898
899    GrNoClip noclip;
900    const GrClip* clip = &origClip;
901#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
902    // The Android framework frequently clips rrects to themselves where the clip is non-aa and the
903    // draw is aa. Since our lower level clip code works from op bounds, which are SkRects, it
904    // doesn't detect that the clip can be ignored (modulo antialiasing). The following test
905    // attempts to mitigate the stencil clip cost but will only help when the entire clip stack
906    // can be ignored. We'd prefer to fix this in the framework by removing the clips calls.
907    SkRRect devRRect;
908    if (rrect.transform(viewMatrix, &devRRect) && clip->quickContains(devRRect)) {
909        clip = &noclip;
910    }
911#endif
912    SkASSERT(!style.pathEffect()); // this should've been devolved to a path in SkGpuDevice
913
914    AutoCheckFlush acf(this->drawingManager());
915    const SkStrokeRec stroke = style.strokeRec();
916
917    if (GrCaps::InstancedSupport::kNone != fContext->caps()->instancedSupport() &&
918        stroke.isFillStyle()) {
919        gr_instanced::OpAllocator* oa = this->drawingManager()->instancingAllocator();
920        std::unique_ptr<GrDrawOp> op(
921                oa->recordRRect(rrect, viewMatrix, std::move(paint), aa, fInstancedPipelineInfo));
922        if (op) {
923            this->addDrawOp(*clip, std::move(op));
924            return;
925        }
926    }
927
928    GrAAType aaType = this->chooseAAType(aa, GrAllowMixedSamples::kNo);
929    if (GrAAType::kCoverage == aaType) {
930        const GrShaderCaps* shaderCaps = fContext->caps()->shaderCaps();
931        std::unique_ptr<GrDrawOp> op = GrOvalOpFactory::MakeRRectOp(std::move(paint),
932                                                                    viewMatrix,
933                                                                    rrect,
934                                                                    stroke,
935                                                                    shaderCaps);
936        if (op) {
937            this->addDrawOp(*clip, std::move(op));
938            return;
939        }
940    }
941
942    SkPath path;
943    path.setIsVolatile(true);
944    path.addRRect(rrect);
945    this->internalDrawPath(*clip, std::move(paint), aa, viewMatrix, path, style);
946}
947
948///////////////////////////////////////////////////////////////////////////////
949
950static SkPoint3 map(const SkMatrix& m, const SkPoint3& pt) {
951    SkPoint3 result;
952    m.mapXY(pt.fX, pt.fY, (SkPoint*)&result.fX);
953    result.fZ = pt.fZ;
954    return result;
955}
956
957bool GrRenderTargetContext::drawFastShadow(const GrClip& clip,
958                                           GrPaint&& paint,
959                                           const SkMatrix& viewMatrix,
960                                           const SkPath& path,
961                                           const SkDrawShadowRec& rec) {
962    ASSERT_SINGLE_OWNER
963    if (this->drawingManager()->wasAbandoned()) {
964        return true;
965    }
966    SkDEBUGCODE(this->validate();)
967    GR_AUDIT_TRAIL_AUTO_FRAME(fAuditTrail, "GrRenderTargetContext::drawFastShadow");
968
969    // check z plane
970    bool tiltZPlane = SkToBool(!SkScalarNearlyZero(rec.fZPlaneParams.fX) ||
971                               !SkScalarNearlyZero(rec.fZPlaneParams.fY));
972    bool skipAnalytic = SkToBool(rec.fFlags & SkShadowFlags::kGeometricOnly_ShadowFlag);
973    if (tiltZPlane || skipAnalytic || !viewMatrix.rectStaysRect() || !viewMatrix.isSimilarity()) {
974        return false;
975    }
976
977    SkRRect rrect;
978    SkRect rect;
979    // we can only handle rects, circles, and rrects with circular corners
980    bool isRRect = path.isRRect(&rrect) && rrect.isSimpleCircular() &&
981        rrect.radii(SkRRect::kUpperLeft_Corner).fX > SK_ScalarNearlyZero;
982    if (!isRRect &&
983        path.isOval(&rect) && SkScalarNearlyEqual(rect.width(), rect.height()) &&
984        rect.width() > SK_ScalarNearlyZero) {
985        rrect.setOval(rect);
986        isRRect = true;
987    }
988    if (!isRRect && path.isRect(&rect)) {
989        rrect.setRect(rect);
990        isRRect = true;
991    }
992
993    if (!isRRect) {
994        return false;
995    }
996
997    if (rrect.isEmpty()) {
998        return true;
999    }
1000
1001    AutoCheckFlush acf(this->drawingManager());
1002
1003    // transform light
1004    SkPoint3 devLightPos = map(viewMatrix, rec.fLightPos);
1005
1006    // 1/scale
1007    SkScalar devToSrcScale = viewMatrix.isScaleTranslate() ?
1008        SkScalarInvert(viewMatrix[SkMatrix::kMScaleX]) :
1009        sk_float_rsqrt(viewMatrix[SkMatrix::kMScaleX] * viewMatrix[SkMatrix::kMScaleX] +
1010                       viewMatrix[SkMatrix::kMSkewX] * viewMatrix[SkMatrix::kMSkewX]);
1011
1012    SkScalar occluderHeight = rec.fZPlaneParams.fZ;
1013    GrColor4f color = paint.getColor4f();
1014    bool transparent = SkToBool(rec.fFlags & SkShadowFlags::kTransparentOccluder_ShadowFlag);
1015
1016    if (rec.fAmbientAlpha > 0) {
1017        static constexpr float kHeightFactor = 1.0f / 128.0f;
1018        static constexpr float kGeomFactor = 64.0f;
1019
1020        SkScalar devSpaceInsetWidth = occluderHeight * kHeightFactor * kGeomFactor;
1021        const float umbraAlpha = (1.0f + SkTMax(occluderHeight * kHeightFactor, 0.0f));
1022        const SkScalar devSpaceAmbientBlur = devSpaceInsetWidth * umbraAlpha;
1023
1024        // Outset the shadow rrect to the border of the penumbra
1025        SkScalar ambientPathOutset = devSpaceInsetWidth * devToSrcScale;
1026        SkRRect ambientRRect;
1027        SkRect outsetRect = rrect.rect().makeOutset(ambientPathOutset, ambientPathOutset);
1028        // If the rrect was an oval then its outset will also be one.
1029        // We set it explicitly to avoid errors.
1030        if (rrect.isOval()) {
1031            ambientRRect = SkRRect::MakeOval(outsetRect);
1032        } else {
1033            SkScalar outsetRad = rrect.getSimpleRadii().fX + ambientPathOutset;
1034            ambientRRect = SkRRect::MakeRectXY(outsetRect, outsetRad, outsetRad);
1035        }
1036
1037        GrColor ambientColor = color.mulByScalar(rec.fAmbientAlpha).toGrColor();
1038        if (transparent) {
1039            // set a large inset to force a fill
1040            devSpaceInsetWidth = ambientRRect.width();
1041        }
1042        // the fraction of the blur we want to apply is devSpaceInsetWidth/devSpaceAmbientBlur,
1043        // which is just 1/umbraAlpha.
1044        SkScalar blurClamp = SkScalarInvert(umbraAlpha);
1045
1046        std::unique_ptr<GrLegacyMeshDrawOp> op = GrShadowRRectOp::Make(ambientColor, viewMatrix,
1047                                                                       ambientRRect,
1048                                                                       devSpaceAmbientBlur,
1049                                                                       devSpaceInsetWidth,
1050                                                                       blurClamp);
1051        if (op) {
1052            GrPipelineBuilder pipelineBuilder(std::move(paint), GrAAType::kNone);
1053            this->addLegacyMeshDrawOp(std::move(pipelineBuilder), clip, std::move(op));
1054        }
1055    }
1056
1057    if (rec.fSpotAlpha > 0) {
1058        float zRatio = SkTPin(occluderHeight / (devLightPos.fZ - occluderHeight), 0.0f, 0.95f);
1059
1060        SkScalar devSpaceSpotBlur = 2.0f * rec.fLightRadius * zRatio;
1061        // handle scale of radius and pad due to CTM
1062        const SkScalar srcSpaceSpotBlur = devSpaceSpotBlur * devToSrcScale;
1063
1064        // Compute the scale and translation for the spot shadow.
1065        const SkScalar spotScale = devLightPos.fZ / (devLightPos.fZ - occluderHeight);
1066        SkPoint spotOffset = SkPoint::Make(zRatio*(-devLightPos.fX), zRatio*(-devLightPos.fY));
1067        // Adjust translate for the effect of the scale.
1068        spotOffset.fX += spotScale*viewMatrix[SkMatrix::kMTransX];
1069        spotOffset.fY += spotScale*viewMatrix[SkMatrix::kMTransY];
1070        // This offset is in dev space, need to transform it into source space.
1071        SkMatrix ctmInverse;
1072        if (viewMatrix.invert(&ctmInverse)) {
1073            ctmInverse.mapPoints(&spotOffset, 1);
1074        } else {
1075            // Since the matrix is a similarity, this should never happen, but just in case...
1076            SkDebugf("Matrix is degenerate. Will not render spot shadow correctly!\n");
1077            SkASSERT(false);
1078        }
1079
1080        // Compute the transformed shadow rrect
1081        SkRRect spotShadowRRect;
1082        SkMatrix shadowTransform;
1083        shadowTransform.setScaleTranslate(spotScale, spotScale, spotOffset.fX, spotOffset.fY);
1084        rrect.transform(shadowTransform, &spotShadowRRect);
1085        SkScalar spotRadius = spotShadowRRect.getSimpleRadii().fX;
1086
1087        // Compute the insetWidth
1088        SkScalar blurOutset = 0.5f*srcSpaceSpotBlur;
1089        SkScalar insetWidth = blurOutset;
1090        if (transparent) {
1091            // If transparent, just do a fill
1092            insetWidth += spotShadowRRect.width();
1093        } else {
1094            // For shadows, instead of using a stroke we specify an inset from the penumbra
1095            // border. We want to extend this inset area so that it meets up with the caster
1096            // geometry. The inset geometry will by default already be inset by the blur width.
1097            //
1098            // We compare the min and max corners inset by the radius between the original
1099            // rrect and the shadow rrect. The distance between the two plus the difference
1100            // between the scaled radius and the original radius gives the distance from the
1101            // transformed shadow shape to the original shape in that corner. The max
1102            // of these gives the maximum distance we need to cover.
1103            //
1104            // Since we are outsetting by 1/2 the blur distance, we just add the maxOffset to
1105            // that to get the full insetWidth.
1106            SkScalar maxOffset;
1107            if (rrect.isRect()) {
1108                // Manhattan distance works better for rects
1109                maxOffset = SkTMax(SkTMax(SkTAbs(spotShadowRRect.rect().fLeft -
1110                                                 rrect.rect().fLeft),
1111                                          SkTAbs(spotShadowRRect.rect().fTop -
1112                                                 rrect.rect().fTop)),
1113                                   SkTMax(SkTAbs(spotShadowRRect.rect().fRight -
1114                                                 rrect.rect().fRight),
1115                                          SkTAbs(spotShadowRRect.rect().fBottom -
1116                                                 rrect.rect().fBottom)));
1117            } else {
1118                SkScalar dr = spotRadius - rrect.getSimpleRadii().fX;
1119                SkPoint upperLeftOffset = SkPoint::Make(spotShadowRRect.rect().fLeft -
1120                                                        rrect.rect().fLeft + dr,
1121                                                        spotShadowRRect.rect().fTop -
1122                                                        rrect.rect().fTop + dr);
1123                SkPoint lowerRightOffset = SkPoint::Make(spotShadowRRect.rect().fRight -
1124                                                         rrect.rect().fRight - dr,
1125                                                         spotShadowRRect.rect().fBottom -
1126                                                         rrect.rect().fBottom - dr);
1127                maxOffset = SkScalarSqrt(SkTMax(upperLeftOffset.lengthSqd(),
1128                                                lowerRightOffset.lengthSqd())) + dr;
1129            }
1130            insetWidth += maxOffset;
1131        }
1132
1133        // Outset the shadow rrect to the border of the penumbra
1134        SkRect outsetRect = spotShadowRRect.rect().makeOutset(blurOutset, blurOutset);
1135        if (spotShadowRRect.isOval()) {
1136            spotShadowRRect = SkRRect::MakeOval(outsetRect);
1137        } else {
1138            SkScalar outsetRad = spotRadius + blurOutset;
1139            spotShadowRRect = SkRRect::MakeRectXY(outsetRect, outsetRad, outsetRad);
1140        }
1141
1142        GrColor spotColor = color.mulByScalar(rec.fSpotAlpha).toGrColor();
1143        std::unique_ptr<GrLegacyMeshDrawOp> op = GrShadowRRectOp::Make(spotColor, viewMatrix,
1144                                                                       spotShadowRRect,
1145                                                                       devSpaceSpotBlur,
1146                                                                       insetWidth);
1147        if (op) {
1148            GrPipelineBuilder pipelineBuilder(std::move(paint), GrAAType::kNone);
1149            this->addLegacyMeshDrawOp(std::move(pipelineBuilder), clip, std::move(op));
1150        }
1151    }
1152
1153    return true;
1154}
1155
1156///////////////////////////////////////////////////////////////////////////////
1157
1158bool GrRenderTargetContext::drawFilledDRRect(const GrClip& clip,
1159                                             GrPaint&& paint,
1160                                             GrAA aa,
1161                                             const SkMatrix& viewMatrix,
1162                                             const SkRRect& origOuter,
1163                                             const SkRRect& origInner) {
1164    SkASSERT(!origInner.isEmpty());
1165    SkASSERT(!origOuter.isEmpty());
1166
1167    if (GrCaps::InstancedSupport::kNone != fContext->caps()->instancedSupport()) {
1168        gr_instanced::OpAllocator* oa = this->drawingManager()->instancingAllocator();
1169        std::unique_ptr<GrDrawOp> op(oa->recordDRRect(
1170                origOuter, origInner, viewMatrix, std::move(paint), aa, fInstancedPipelineInfo));
1171        if (op) {
1172            this->addDrawOp(clip, std::move(op));
1173            return true;
1174        }
1175    }
1176
1177    GrAAType aaType = this->chooseAAType(aa, GrAllowMixedSamples::kNo);
1178
1179    GrPrimitiveEdgeType innerEdgeType, outerEdgeType;
1180    if (GrAAType::kCoverage == aaType) {
1181        innerEdgeType = kInverseFillAA_GrProcessorEdgeType;
1182        outerEdgeType = kFillAA_GrProcessorEdgeType;
1183    } else {
1184        innerEdgeType = kInverseFillBW_GrProcessorEdgeType;
1185        outerEdgeType = kFillBW_GrProcessorEdgeType;
1186    }
1187
1188    SkTCopyOnFirstWrite<SkRRect> inner(origInner), outer(origOuter);
1189    SkMatrix inverseVM;
1190    if (!viewMatrix.isIdentity()) {
1191        if (!origInner.transform(viewMatrix, inner.writable())) {
1192            return false;
1193        }
1194        if (!origOuter.transform(viewMatrix, outer.writable())) {
1195            return false;
1196        }
1197        if (!viewMatrix.invert(&inverseVM)) {
1198            return false;
1199        }
1200    } else {
1201        inverseVM.reset();
1202    }
1203
1204    // TODO these need to be a geometry processors
1205    sk_sp<GrFragmentProcessor> innerEffect(GrRRectEffect::Make(innerEdgeType, *inner));
1206    if (!innerEffect) {
1207        return false;
1208    }
1209
1210    sk_sp<GrFragmentProcessor> outerEffect(GrRRectEffect::Make(outerEdgeType, *outer));
1211    if (!outerEffect) {
1212        return false;
1213    }
1214
1215    paint.addCoverageFragmentProcessor(std::move(innerEffect));
1216    paint.addCoverageFragmentProcessor(std::move(outerEffect));
1217
1218    SkRect bounds = outer->getBounds();
1219    if (GrAAType::kCoverage == aaType) {
1220        bounds.outset(SK_ScalarHalf, SK_ScalarHalf);
1221    }
1222
1223    this->fillRectWithLocalMatrix(clip, std::move(paint), GrAA::kNo, SkMatrix::I(), bounds,
1224                                  inverseVM);
1225    return true;
1226}
1227
1228void GrRenderTargetContext::drawDRRect(const GrClip& clip,
1229                                       GrPaint&& paint,
1230                                       GrAA aa,
1231                                       const SkMatrix& viewMatrix,
1232                                       const SkRRect& outer,
1233                                       const SkRRect& inner) {
1234    ASSERT_SINGLE_OWNER
1235    RETURN_IF_ABANDONED
1236    SkDEBUGCODE(this->validate();)
1237    GR_AUDIT_TRAIL_AUTO_FRAME(fAuditTrail, "GrRenderTargetContext::drawDRRect");
1238
1239    SkASSERT(!outer.isEmpty());
1240    SkASSERT(!inner.isEmpty());
1241
1242    AutoCheckFlush acf(this->drawingManager());
1243
1244    if (this->drawFilledDRRect(clip, std::move(paint), aa, viewMatrix, outer, inner)) {
1245        return;
1246    }
1247
1248    SkPath path;
1249    path.setIsVolatile(true);
1250    path.addRRect(inner);
1251    path.addRRect(outer);
1252    path.setFillType(SkPath::kEvenOdd_FillType);
1253
1254    this->internalDrawPath(clip, std::move(paint), aa, viewMatrix, path, GrStyle::SimpleFill());
1255}
1256
1257///////////////////////////////////////////////////////////////////////////////
1258
1259static inline bool is_int(float x) {
1260    return x == (float) sk_float_round2int(x);
1261}
1262
1263void GrRenderTargetContext::drawRegion(const GrClip& clip,
1264                                       GrPaint&& paint,
1265                                       GrAA aa,
1266                                       const SkMatrix& viewMatrix,
1267                                       const SkRegion& region,
1268                                       const GrStyle& style) {
1269    ASSERT_SINGLE_OWNER
1270    RETURN_IF_ABANDONED
1271    SkDEBUGCODE(this->validate();)
1272    GR_AUDIT_TRAIL_AUTO_FRAME(fAuditTrail, "GrRenderTargetContext::drawRegion");
1273
1274    if (GrAA::kYes == aa) {
1275        // GrRegionOp performs no antialiasing but is much faster, so here we check the matrix
1276        // to see whether aa is really required.
1277        if (!SkToBool(viewMatrix.getType() & ~(SkMatrix::kTranslate_Mask)) &&
1278            is_int(viewMatrix.getTranslateX()) &&
1279            is_int(viewMatrix.getTranslateY())) {
1280            aa = GrAA::kNo;
1281        }
1282    }
1283    bool complexStyle = !style.isSimpleFill();
1284    if (complexStyle || GrAA::kYes == aa) {
1285        SkPath path;
1286        region.getBoundaryPath(&path);
1287        return this->drawPath(clip, std::move(paint), aa, viewMatrix, path, style);
1288    }
1289
1290    std::unique_ptr<GrLegacyMeshDrawOp> op = GrRegionOp::Make(paint.getColor(), viewMatrix, region);
1291    GrPipelineBuilder pipelineBuilder(std::move(paint), GrAAType::kNone);
1292    this->addLegacyMeshDrawOp(std::move(pipelineBuilder), clip, std::move(op));
1293}
1294
1295void GrRenderTargetContext::drawOval(const GrClip& clip,
1296                                     GrPaint&& paint,
1297                                     GrAA aa,
1298                                     const SkMatrix& viewMatrix,
1299                                     const SkRect& oval,
1300                                     const GrStyle& style) {
1301    ASSERT_SINGLE_OWNER
1302    RETURN_IF_ABANDONED
1303    SkDEBUGCODE(this->validate();)
1304    GR_AUDIT_TRAIL_AUTO_FRAME(fAuditTrail, "GrRenderTargetContext::drawOval");
1305
1306    if (oval.isEmpty()) {
1307       return;
1308    }
1309
1310    SkASSERT(!style.pathEffect()); // this should've been devolved to a path in SkGpuDevice
1311
1312    AutoCheckFlush acf(this->drawingManager());
1313    const SkStrokeRec& stroke = style.strokeRec();
1314
1315    if (GrCaps::InstancedSupport::kNone != fContext->caps()->instancedSupport() &&
1316        stroke.isFillStyle()) {
1317        gr_instanced::OpAllocator* oa = this->drawingManager()->instancingAllocator();
1318        std::unique_ptr<GrDrawOp> op(
1319                oa->recordOval(oval, viewMatrix, std::move(paint), aa, fInstancedPipelineInfo));
1320        if (op) {
1321            this->addDrawOp(clip, std::move(op));
1322            return;
1323        }
1324    }
1325
1326    GrAAType aaType = this->chooseAAType(aa, GrAllowMixedSamples::kNo);
1327    if (GrAAType::kCoverage == aaType) {
1328        const GrShaderCaps* shaderCaps = fContext->caps()->shaderCaps();
1329        std::unique_ptr<GrDrawOp> op =
1330                GrOvalOpFactory::MakeOvalOp(std::move(paint), viewMatrix, oval, stroke, shaderCaps);
1331        if (op) {
1332            this->addDrawOp(clip, std::move(op));
1333            return;
1334        }
1335    }
1336
1337    SkPath path;
1338    path.setIsVolatile(true);
1339    path.addOval(oval);
1340    this->internalDrawPath(clip, std::move(paint), aa, viewMatrix, path, style);
1341}
1342
1343void GrRenderTargetContext::drawArc(const GrClip& clip,
1344                                    GrPaint&& paint,
1345                                    GrAA aa,
1346                                    const SkMatrix& viewMatrix,
1347                                    const SkRect& oval,
1348                                    SkScalar startAngle,
1349                                    SkScalar sweepAngle,
1350                                    bool useCenter,
1351                                    const GrStyle& style) {
1352    ASSERT_SINGLE_OWNER
1353    RETURN_IF_ABANDONED
1354    SkDEBUGCODE(this->validate();)
1355    GR_AUDIT_TRAIL_AUTO_FRAME(fAuditTrail, "GrRenderTargetContext::drawArc");
1356
1357    AutoCheckFlush acf(this->drawingManager());
1358
1359    GrAAType aaType = this->chooseAAType(aa, GrAllowMixedSamples::kNo);
1360    if (GrAAType::kCoverage == aaType) {
1361        const GrShaderCaps* shaderCaps = fContext->caps()->shaderCaps();
1362        std::unique_ptr<GrDrawOp> op = GrOvalOpFactory::MakeArcOp(std::move(paint),
1363                                                                  viewMatrix,
1364                                                                  oval,
1365                                                                  startAngle,
1366                                                                  sweepAngle,
1367                                                                  useCenter,
1368                                                                  style,
1369                                                                  shaderCaps);
1370        if (op) {
1371            this->addDrawOp(clip, std::move(op));
1372            return;
1373        }
1374    }
1375    SkPath path;
1376    SkPathPriv::CreateDrawArcPath(&path, oval, startAngle, sweepAngle, useCenter,
1377                                  style.isSimpleFill());
1378    this->internalDrawPath(clip, std::move(paint), aa, viewMatrix, path, style);
1379}
1380
1381void GrRenderTargetContext::drawImageLattice(const GrClip& clip,
1382                                             GrPaint&& paint,
1383                                             const SkMatrix& viewMatrix,
1384                                             int imageWidth,
1385                                             int imageHeight,
1386                                             std::unique_ptr<SkLatticeIter> iter,
1387                                             const SkRect& dst) {
1388    ASSERT_SINGLE_OWNER
1389    RETURN_IF_ABANDONED
1390    SkDEBUGCODE(this->validate();)
1391    GR_AUDIT_TRAIL_AUTO_FRAME(fAuditTrail, "GrRenderTargetContext::drawImageLattice");
1392
1393    AutoCheckFlush acf(this->drawingManager());
1394
1395    std::unique_ptr<GrLegacyMeshDrawOp> op = GrLatticeOp::MakeNonAA(
1396            paint.getColor(), viewMatrix, imageWidth, imageHeight, std::move(iter), dst);
1397
1398    GrPipelineBuilder pipelineBuilder(std::move(paint), GrAAType::kNone);
1399    this->addLegacyMeshDrawOp(std::move(pipelineBuilder), clip, std::move(op));
1400}
1401
1402void GrRenderTargetContext::prepareForExternalIO() {
1403    ASSERT_SINGLE_OWNER
1404    RETURN_IF_ABANDONED
1405    SkDEBUGCODE(this->validate();)
1406    GR_AUDIT_TRAIL_AUTO_FRAME(fAuditTrail, "GrRenderTargetContext::prepareForExternalIO");
1407
1408    this->drawingManager()->prepareSurfaceForExternalIO(fRenderTargetProxy.get());
1409}
1410
1411void GrRenderTargetContext::drawNonAAFilledRect(const GrClip& clip,
1412                                                GrPaint&& paint,
1413                                                const SkMatrix& viewMatrix,
1414                                                const SkRect& rect,
1415                                                const SkRect* localRect,
1416                                                const SkMatrix* localMatrix,
1417                                                const GrUserStencilSettings* ss,
1418                                                GrAAType hwOrNoneAAType) {
1419    SkASSERT(GrAAType::kCoverage != hwOrNoneAAType);
1420    SkASSERT(GrAAType::kNone == hwOrNoneAAType || GrFSAAType::kNone != this->fsaaType());
1421    std::unique_ptr<GrDrawOp> op = GrNonAAFillRectOp::Make(
1422            std::move(paint), viewMatrix, rect, localRect, localMatrix, hwOrNoneAAType, ss);
1423    this->addDrawOp(clip, std::move(op));
1424}
1425
1426// Can 'path' be drawn as a pair of filled nested rectangles?
1427static bool fills_as_nested_rects(const SkMatrix& viewMatrix, const SkPath& path, SkRect rects[2]) {
1428
1429    if (path.isInverseFillType()) {
1430        return false;
1431    }
1432
1433    // TODO: this restriction could be lifted if we were willing to apply
1434    // the matrix to all the points individually rather than just to the rect
1435    if (!viewMatrix.rectStaysRect()) {
1436        return false;
1437    }
1438
1439    SkPath::Direction dirs[2];
1440    if (!path.isNestedFillRects(rects, dirs)) {
1441        return false;
1442    }
1443
1444    if (SkPath::kWinding_FillType == path.getFillType() && dirs[0] == dirs[1]) {
1445        // The two rects need to be wound opposite to each other
1446        return false;
1447    }
1448
1449    // Right now, nested rects where the margin is not the same width
1450    // all around do not render correctly
1451    const SkScalar* outer = rects[0].asScalars();
1452    const SkScalar* inner = rects[1].asScalars();
1453
1454    bool allEq = true;
1455
1456    SkScalar margin = SkScalarAbs(outer[0] - inner[0]);
1457    bool allGoE1 = margin >= SK_Scalar1;
1458
1459    for (int i = 1; i < 4; ++i) {
1460        SkScalar temp = SkScalarAbs(outer[i] - inner[i]);
1461        if (temp < SK_Scalar1) {
1462            allGoE1 = false;
1463        }
1464        if (!SkScalarNearlyEqual(margin, temp)) {
1465            allEq = false;
1466        }
1467    }
1468
1469    return allEq || allGoE1;
1470}
1471
1472void GrRenderTargetContext::drawPath(const GrClip& clip,
1473                                     GrPaint&& paint,
1474                                     GrAA aa,
1475                                     const SkMatrix& viewMatrix,
1476                                     const SkPath& path,
1477                                     const GrStyle& style) {
1478    ASSERT_SINGLE_OWNER
1479    RETURN_IF_ABANDONED
1480    SkDEBUGCODE(this->validate();)
1481    GR_AUDIT_TRAIL_AUTO_FRAME(fAuditTrail, "GrRenderTargetContext::drawPath");
1482
1483    if (path.isEmpty()) {
1484       if (path.isInverseFillType()) {
1485           this->drawPaint(clip, std::move(paint), viewMatrix);
1486       }
1487       return;
1488    }
1489
1490    AutoCheckFlush acf(this->drawingManager());
1491
1492    GrAAType aaType = this->chooseAAType(aa, GrAllowMixedSamples::kNo);
1493    if (GrAAType::kCoverage == aaType && !style.pathEffect()) {
1494        if (style.isSimpleFill() && !path.isConvex()) {
1495            // Concave AA paths are expensive - try to avoid them for special cases
1496            SkRect rects[2];
1497
1498            if (fills_as_nested_rects(viewMatrix, path, rects)) {
1499                std::unique_ptr<GrLegacyMeshDrawOp> op =
1500                        GrRectOpFactory::MakeAAFillNestedRects(paint.getColor(), viewMatrix, rects);
1501                if (op) {
1502                    GrPipelineBuilder pipelineBuilder(std::move(paint), aaType);
1503                    this->addLegacyMeshDrawOp(std::move(pipelineBuilder), clip, std::move(op));
1504                }
1505                return;
1506            }
1507        }
1508        SkRect ovalRect;
1509        bool isOval = path.isOval(&ovalRect);
1510
1511        if (isOval && !path.isInverseFillType()) {
1512            const GrShaderCaps* shaderCaps = fContext->caps()->shaderCaps();
1513            std::unique_ptr<GrDrawOp> op = GrOvalOpFactory::MakeOvalOp(
1514                    std::move(paint), viewMatrix, ovalRect, style.strokeRec(), shaderCaps);
1515            if (op) {
1516                this->addDrawOp(clip, std::move(op));
1517                return;
1518            }
1519        }
1520    }
1521
1522    // Note that internalDrawPath may sw-rasterize the path into a scratch texture.
1523    // Scratch textures can be recycled after they are returned to the texture
1524    // cache. This presents a potential hazard for buffered drawing. However,
1525    // the writePixels that uploads to the scratch will perform a flush so we're
1526    // OK.
1527    this->internalDrawPath(clip, std::move(paint), aa, viewMatrix, path, style);
1528}
1529
1530bool GrRenderTargetContextPriv::drawAndStencilPath(const GrClip& clip,
1531                                                   const GrUserStencilSettings* ss,
1532                                                   SkRegion::Op op,
1533                                                   bool invert,
1534                                                   GrAA aa,
1535                                                   const SkMatrix& viewMatrix,
1536                                                   const SkPath& path) {
1537    ASSERT_SINGLE_OWNER_PRIV
1538    RETURN_FALSE_IF_ABANDONED_PRIV
1539    SkDEBUGCODE(fRenderTargetContext->validate();)
1540    GR_AUDIT_TRAIL_AUTO_FRAME(fRenderTargetContext->fAuditTrail,
1541                              "GrRenderTargetContextPriv::drawAndStencilPath");
1542
1543    if (path.isEmpty() && path.isInverseFillType()) {
1544        this->drawAndStencilRect(clip, ss, op, invert, GrAA::kNo, SkMatrix::I(),
1545                                 SkRect::MakeIWH(fRenderTargetContext->width(),
1546                                                 fRenderTargetContext->height()));
1547        return true;
1548    }
1549
1550    AutoCheckFlush acf(fRenderTargetContext->drawingManager());
1551
1552    // An Assumption here is that path renderer would use some form of tweaking
1553    // the src color (either the input alpha or in the frag shader) to implement
1554    // aa. If we have some future driver-mojo path AA that can do the right
1555    // thing WRT to the blend then we'll need some query on the PR.
1556    GrAAType aaType = fRenderTargetContext->chooseAAType(aa, GrAllowMixedSamples::kNo);
1557    bool hasUserStencilSettings = !ss->isUnused();
1558
1559    GrShape shape(path, GrStyle::SimpleFill());
1560    GrPathRenderer::CanDrawPathArgs canDrawArgs;
1561    canDrawArgs.fCaps = fRenderTargetContext->drawingManager()->getContext()->caps();
1562    canDrawArgs.fViewMatrix = &viewMatrix;
1563    canDrawArgs.fShape = &shape;
1564    canDrawArgs.fAAType = aaType;
1565    canDrawArgs.fHasUserStencilSettings = hasUserStencilSettings;
1566
1567    // Don't allow the SW renderer
1568    GrPathRenderer* pr = fRenderTargetContext->drawingManager()->getPathRenderer(
1569            canDrawArgs, false, GrPathRendererChain::DrawType::kStencilAndColor);
1570    if (!pr) {
1571        return false;
1572    }
1573
1574    GrPaint paint;
1575    paint.setCoverageSetOpXPFactory(op, invert);
1576
1577    GrPathRenderer::DrawPathArgs args{
1578            fRenderTargetContext->drawingManager()->getContext(),
1579            std::move(paint),
1580            ss,
1581            fRenderTargetContext,
1582            &clip,
1583            &viewMatrix,
1584            &shape,
1585            aaType,
1586            fRenderTargetContext->isGammaCorrect()};
1587    pr->drawPath(args);
1588    return true;
1589}
1590
1591SkBudgeted GrRenderTargetContextPriv::isBudgeted() const {
1592    ASSERT_SINGLE_OWNER_PRIV
1593
1594    if (fRenderTargetContext->wasAbandoned()) {
1595        return SkBudgeted::kNo;
1596    }
1597
1598    SkDEBUGCODE(fRenderTargetContext->validate();)
1599
1600    return fRenderTargetContext->fRenderTargetProxy->isBudgeted();
1601}
1602
1603void GrRenderTargetContext::internalDrawPath(const GrClip& clip,
1604                                             GrPaint&& paint,
1605                                             GrAA aa,
1606                                             const SkMatrix& viewMatrix,
1607                                             const SkPath& path,
1608                                             const GrStyle& style) {
1609    ASSERT_SINGLE_OWNER
1610    RETURN_IF_ABANDONED
1611    SkASSERT(!path.isEmpty());
1612    GrShape shape;
1613    // NVPR cannot handle hairlines, so this would get picked up by a different stencil and
1614    // cover path renderer (i.e. default path renderer). The hairline renderer produces much
1615    // smoother hairlines than MSAA.
1616    GrAllowMixedSamples allowMixedSamples =
1617            style.isSimpleHairline() ? GrAllowMixedSamples::kNo : GrAllowMixedSamples::kYes;
1618    GrAAType aaType = this->chooseAAType(aa, allowMixedSamples);
1619    GrPathRenderer::CanDrawPathArgs canDrawArgs;
1620    canDrawArgs.fCaps = this->drawingManager()->getContext()->caps();
1621    canDrawArgs.fViewMatrix = &viewMatrix;
1622    canDrawArgs.fShape = &shape;
1623    canDrawArgs.fHasUserStencilSettings = false;
1624
1625    GrPathRenderer* pr;
1626    static constexpr GrPathRendererChain::DrawType kType = GrPathRendererChain::DrawType::kColor;
1627    do {
1628        shape = GrShape(path, style);
1629        if (shape.isEmpty()) {
1630            return;
1631        }
1632
1633        canDrawArgs.fAAType = aaType;
1634
1635        // Try a 1st time without applying any of the style to the geometry (and barring sw)
1636        pr = this->drawingManager()->getPathRenderer(canDrawArgs, false, kType);
1637        SkScalar styleScale =  GrStyle::MatrixToScaleFactor(viewMatrix);
1638
1639        if (!pr && shape.style().pathEffect()) {
1640            // It didn't work above, so try again with the path effect applied.
1641            shape = shape.applyStyle(GrStyle::Apply::kPathEffectOnly, styleScale);
1642            if (shape.isEmpty()) {
1643                return;
1644            }
1645            pr = this->drawingManager()->getPathRenderer(canDrawArgs, false, kType);
1646        }
1647        if (!pr) {
1648            if (shape.style().applies()) {
1649                shape = shape.applyStyle(GrStyle::Apply::kPathEffectAndStrokeRec, styleScale);
1650                if (shape.isEmpty()) {
1651                    return;
1652                }
1653            }
1654            // This time, allow SW renderer
1655            pr = this->drawingManager()->getPathRenderer(canDrawArgs, true, kType);
1656        }
1657        if (!pr && GrAATypeIsHW(aaType)) {
1658            // There are exceptional cases where we may wind up falling back to coverage based AA
1659            // when the target is MSAA (e.g. through disabling path renderers via GrContextOptions).
1660            aaType = GrAAType::kCoverage;
1661        } else {
1662            break;
1663        }
1664    } while(true);
1665
1666    if (!pr) {
1667#ifdef SK_DEBUG
1668        SkDebugf("Unable to find path renderer compatible with path.\n");
1669#endif
1670        return;
1671    }
1672
1673    GrPathRenderer::DrawPathArgs args{this->drawingManager()->getContext(),
1674                                      std::move(paint),
1675                                      &GrUserStencilSettings::kUnused,
1676                                      this,
1677                                      &clip,
1678                                      &viewMatrix,
1679                                      &shape,
1680                                      aaType,
1681                                      this->isGammaCorrect()};
1682    pr->drawPath(args);
1683}
1684
1685static void op_bounds(SkRect* bounds, const GrOp* op) {
1686    *bounds = op->bounds();
1687    if (op->hasZeroArea()) {
1688        if (op->hasAABloat()) {
1689            bounds->outset(0.5f, 0.5f);
1690        } else {
1691            // We don't know which way the particular GPU will snap lines or points at integer
1692            // coords. So we ensure that the bounds is large enough for either snap.
1693            SkRect before = *bounds;
1694            bounds->roundOut(bounds);
1695            if (bounds->fLeft == before.fLeft) {
1696                bounds->fLeft -= 1;
1697            }
1698            if (bounds->fTop == before.fTop) {
1699                bounds->fTop -= 1;
1700            }
1701            if (bounds->fRight == before.fRight) {
1702                bounds->fRight += 1;
1703            }
1704            if (bounds->fBottom == before.fBottom) {
1705                bounds->fBottom += 1;
1706            }
1707        }
1708    }
1709}
1710
1711uint32_t GrRenderTargetContext::addDrawOp(const GrClip& clip, std::unique_ptr<GrDrawOp> op) {
1712    ASSERT_SINGLE_OWNER
1713    if (this->drawingManager()->wasAbandoned()) {
1714        return SK_InvalidUniqueID;
1715    }
1716    SkDEBUGCODE(this->validate();)
1717    GR_AUDIT_TRAIL_AUTO_FRAME(fAuditTrail, "GrRenderTargetContext::addDrawOp");
1718
1719    // Setup clip
1720    SkRect bounds;
1721    op_bounds(&bounds, op.get());
1722    GrAppliedClip appliedClip;
1723    GrDrawOp::FixedFunctionFlags fixedFunctionFlags = op->fixedFunctionFlags();
1724    if (!clip.apply(fContext, this, fixedFunctionFlags & GrDrawOp::FixedFunctionFlags::kUsesHWAA,
1725                    fixedFunctionFlags & GrDrawOp::FixedFunctionFlags::kUsesStencil, &appliedClip,
1726                    &bounds)) {
1727        return SK_InvalidUniqueID;
1728    }
1729
1730    if (fixedFunctionFlags & GrDrawOp::FixedFunctionFlags::kUsesStencil ||
1731        appliedClip.hasStencilClip()) {
1732        // This forces instantiation of the render target.
1733        GrRenderTarget* rt = this->accessRenderTarget();
1734        if (!rt) {
1735            return SK_InvalidUniqueID;
1736        }
1737
1738        if (!fContext->resourceProvider()->attachStencilAttachment(rt)) {
1739            SkDebugf("ERROR creating stencil attachment. Draw skipped.\n");
1740            return SK_InvalidUniqueID;
1741        }
1742    }
1743
1744    GrXferProcessor::DstProxy dstProxy;
1745    if (op->xpRequiresDstTexture(*this->caps(), &appliedClip)) {
1746        if (!this->setupDstProxy(this->asRenderTargetProxy(), clip, op->bounds(), &dstProxy)) {
1747            return SK_InvalidUniqueID;
1748        }
1749    }
1750
1751    op->setClippedBounds(bounds);
1752    return this->getOpList()->addOp(std::move(op), *this->caps(),
1753                                    std::move(appliedClip), dstProxy);
1754}
1755
1756uint32_t GrRenderTargetContext::addLegacyMeshDrawOp(GrPipelineBuilder&& pipelineBuilder,
1757                                                    const GrClip& clip,
1758                                                    std::unique_ptr<GrLegacyMeshDrawOp> op) {
1759    ASSERT_SINGLE_OWNER
1760    if (this->drawingManager()->wasAbandoned()) {
1761        return SK_InvalidUniqueID;
1762    }
1763    SkDEBUGCODE(this->validate();)
1764    GR_AUDIT_TRAIL_AUTO_FRAME(fAuditTrail, "GrRenderTargetContext::addLegacyMeshDrawOp");
1765
1766    // Setup clip
1767    SkRect bounds;
1768    op_bounds(&bounds, op.get());
1769    GrAppliedClip appliedClip;
1770    if (!clip.apply(fContext, this, pipelineBuilder.isHWAntialias(),
1771                    pipelineBuilder.hasUserStencilSettings(), &appliedClip, &bounds)) {
1772        return SK_InvalidUniqueID;
1773    }
1774
1775    // This forces instantiation of the render target. Pipeline creation is moving to flush time
1776    // by which point instantiation must have occurred anyway.
1777    GrRenderTarget* rt = this->accessRenderTarget();
1778    if (!rt) {
1779        return SK_InvalidUniqueID;
1780    }
1781
1782    GrResourceProvider* resourceProvider = fContext->resourceProvider();
1783    bool usesStencil = pipelineBuilder.hasUserStencilSettings() || appliedClip.hasStencilClip();
1784    if (usesStencil) {
1785        if (!resourceProvider->attachStencilAttachment(this->accessRenderTarget())) {
1786            SkDebugf("ERROR creating stencil attachment. Draw skipped.\n");
1787            return SK_InvalidUniqueID;
1788        }
1789    }
1790
1791    bool isMixedSamples = GrFSAAType::kMixedSamples == this->fsaaType() &&
1792                          (pipelineBuilder.isHWAntialias() || usesStencil);
1793
1794    GrColor overrideColor;
1795    GrProcessorSet::Analysis analysis = op->analyzeUpdateAndRecordProcessors(
1796            &pipelineBuilder, &appliedClip, isMixedSamples, *this->caps(), &overrideColor);
1797
1798    GrPipeline::InitArgs args;
1799    pipelineBuilder.getPipelineInitArgs(&args);
1800    args.fAppliedClip = &appliedClip;
1801    args.fRenderTarget = rt;
1802    args.fCaps = this->caps();
1803    args.fResourceProvider = this->resourceProvider();
1804
1805    if (analysis.requiresDstTexture()) {
1806        if (!this->setupDstProxy(this->asRenderTargetProxy(), clip, bounds, &args.fDstProxy)) {
1807            return SK_InvalidUniqueID;
1808        }
1809    }
1810    op->initPipeline(args, analysis, overrideColor);
1811
1812    // Add the pipeline dependencies on textures, etc before recording this op.
1813    op->addDependenciesTo(fRenderTargetProxy.get());
1814
1815    op->setClippedBounds(bounds);
1816    return this->getOpList()->addOp(std::move(op), *this->caps());
1817}
1818
1819bool GrRenderTargetContext::setupDstProxy(GrRenderTargetProxy* rtProxy, const GrClip& clip,
1820                                            const SkRect& opBounds,
1821                                            GrXferProcessor::DstProxy* dstProxy) {
1822    if (this->caps()->textureBarrierSupport()) {
1823        if (GrTextureProxy* texProxy = rtProxy->asTextureProxy()) {
1824            // The render target is a texture, so we can read from it directly in the shader. The XP
1825            // will be responsible to detect this situation and request a texture barrier.
1826            dstProxy->setProxy(sk_ref_sp(texProxy));
1827            dstProxy->setOffset(0, 0);
1828            return true;
1829        }
1830    }
1831
1832    SkIRect copyRect = SkIRect::MakeWH(rtProxy->width(), rtProxy->height());
1833
1834    SkIRect clippedRect;
1835    clip.getConservativeBounds(rtProxy->width(), rtProxy->height(), &clippedRect);
1836    SkIRect drawIBounds;
1837    opBounds.roundOut(&drawIBounds);
1838    // Cover up for any precision issues by outsetting the op bounds a pixel in each direction.
1839    drawIBounds.outset(1, 1);
1840    if (!clippedRect.intersect(drawIBounds)) {
1841#ifdef SK_DEBUG
1842        GrCapsDebugf(this->caps(), "setupDstTexture: Missed an early reject bailing on draw.");
1843#endif
1844        return false;
1845    }
1846
1847    // MSAA consideration: When there is support for reading MSAA samples in the shader we could
1848    // have per-sample dst values by making the copy multisampled.
1849    GrSurfaceDesc desc;
1850    bool rectsMustMatch = false;
1851    bool disallowSubrect = false;
1852    if (!this->caps()->initDescForDstCopy(rtProxy, &desc, &rectsMustMatch, &disallowSubrect)) {
1853        desc.fOrigin = kBottomLeft_GrSurfaceOrigin;
1854        desc.fFlags = kRenderTarget_GrSurfaceFlag;
1855        desc.fConfig = rtProxy->config();
1856    }
1857
1858    if (!disallowSubrect) {
1859        copyRect = clippedRect;
1860    }
1861
1862    SkIPoint dstPoint, dstOffset;
1863    SkBackingFit fit;
1864    if (rectsMustMatch) {
1865        SkASSERT(desc.fOrigin == rtProxy->origin());
1866        desc.fWidth = rtProxy->width();
1867        desc.fHeight = rtProxy->height();
1868        dstPoint = {copyRect.fLeft, copyRect.fTop};
1869        dstOffset = {0, 0};
1870        fit = SkBackingFit::kExact;
1871    } else {
1872        desc.fWidth = copyRect.width();
1873        desc.fHeight = copyRect.height();
1874        dstPoint = {0, 0};
1875        dstOffset = {copyRect.fLeft, copyRect.fTop};
1876        fit = SkBackingFit::kApprox;
1877    }
1878
1879    sk_sp<GrSurfaceContext> sContext = fContext->contextPriv().makeDeferredSurfaceContext(
1880                                                                                desc,
1881                                                                                fit,
1882                                                                                SkBudgeted::kYes);
1883    if (!sContext) {
1884        SkDebugf("setupDstTexture: surfaceContext creation failed.\n");
1885        return false;
1886    }
1887
1888    if (!sContext->copy(rtProxy, copyRect, dstPoint)) {
1889        SkDebugf("setupDstTexture: copy failed.\n");
1890        return false;
1891    }
1892
1893    dstProxy->setProxy(sContext->asTextureProxyRef());
1894    dstProxy->setOffset(dstOffset);
1895    return true;
1896}
1897