GrRenderTargetContext.cpp revision 3fdd0bf2d90b1b82c1ac3aa982bdca600de7f4a8
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(fContext->resourceProvider(),
142                                          this, 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(clip, insideStencilMask,
609                                                        fRenderTargetContext));
610    if (!op) {
611        return;
612    }
613    fRenderTargetContext->getOpList()->addOp(std::move(op), *fRenderTargetContext->caps());
614}
615
616void GrRenderTargetContextPriv::stencilPath(const GrClip& clip,
617                                            GrAAType aaType,
618                                            const SkMatrix& viewMatrix,
619                                            const GrPath* path) {
620    ASSERT_SINGLE_OWNER_PRIV
621    RETURN_IF_ABANDONED_PRIV
622    SkDEBUGCODE(fRenderTargetContext->validate();)
623    GR_AUDIT_TRAIL_AUTO_FRAME(fRenderTargetContext->fAuditTrail,
624                              "GrRenderTargetContext::stencilPath");
625
626    SkASSERT(aaType != GrAAType::kCoverage);
627
628    bool useHWAA = GrAATypeIsHW(aaType);
629    // TODO: extract portions of checkDraw that are relevant to path stenciling.
630    SkASSERT(path);
631    SkASSERT(fRenderTargetContext->caps()->shaderCaps()->pathRenderingSupport());
632
633    // FIXME: Use path bounds instead of this WAR once
634    // https://bugs.chromium.org/p/skia/issues/detail?id=5640 is resolved.
635    SkRect bounds = SkRect::MakeIWH(fRenderTargetContext->width(), fRenderTargetContext->height());
636
637    // Setup clip
638    GrAppliedClip appliedClip;
639    if (!clip.apply(fRenderTargetContext->fContext, fRenderTargetContext, useHWAA, true,
640                    &appliedClip, &bounds)) {
641        return;
642    }
643
644    // Coverage AA does not make sense when rendering to the stencil buffer. The caller should never
645    // attempt this in a situation that would require coverage AA.
646    SkASSERT(!appliedClip.clipCoverageFragmentProcessor());
647
648    GrRenderTarget* rt = fRenderTargetContext->accessRenderTarget();
649    if (!rt) {
650        return;
651    }
652    GrStencilAttachment* stencilAttachment =
653            fRenderTargetContext->fContext->resourceProvider()->attachStencilAttachment(rt);
654    if (!stencilAttachment) {
655        SkDebugf("ERROR creating stencil attachment. Draw skipped.\n");
656        return;
657    }
658
659    std::unique_ptr<GrOp> op = GrStencilPathOp::Make(viewMatrix,
660                                                     useHWAA,
661                                                     path->getFillType(),
662                                                     appliedClip.hasStencilClip(),
663                                                     stencilAttachment->bits(),
664                                                     appliedClip.scissorState(),
665                                                     fRenderTargetContext,
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                                         GrPrimitiveType primitiveType,
840                                         int vertexCount,
841                                         const SkPoint positions[],
842                                         const SkPoint texCoords[],
843                                         const uint32_t colors[],
844                                         const uint16_t indices[],
845                                         int indexCount,
846                                         ColorArrayType colorArrayType) {
847    ASSERT_SINGLE_OWNER
848    RETURN_IF_ABANDONED
849    SkDEBUGCODE(this->validate();)
850    GR_AUDIT_TRAIL_AUTO_FRAME(fAuditTrail, "GrRenderTargetContext::drawVertices");
851
852    AutoCheckFlush acf(this->drawingManager());
853
854    // TODO clients should give us bounds
855    SkRect bounds;
856    if (!bounds.setBoundsCheck(positions, vertexCount)) {
857        SkDebugf("drawVertices call empty bounds\n");
858        return;
859    }
860
861    std::unique_ptr<GrLegacyMeshDrawOp> op = GrDrawVerticesOp::Make(
862            paint.getColor(), primitiveType, viewMatrix, positions, vertexCount, indices,
863            indexCount, colors, texCoords, bounds, colorArrayType);
864    if (!op) {
865        return;
866    }
867    GrPipelineBuilder pipelineBuilder(std::move(paint), GrAAType::kNone);
868    this->addLegacyMeshDrawOp(std::move(pipelineBuilder), clip, std::move(op));
869}
870
871void GrRenderTargetContext::drawVertices(const GrClip& clip,
872                                         GrPaint&& paint,
873                                         const SkMatrix& viewMatrix,
874                                         sk_sp<SkVertices> vertices) {
875    ASSERT_SINGLE_OWNER
876    RETURN_IF_ABANDONED
877    SkDEBUGCODE(this->validate();)
878    GR_AUDIT_TRAIL_AUTO_FRAME(fAuditTrail, "GrRenderTargetContext::drawVertices");
879
880    AutoCheckFlush acf(this->drawingManager());
881
882    SkASSERT(vertices);
883    std::unique_ptr<GrLegacyMeshDrawOp> op =
884            GrDrawVerticesOp::Make(paint.getColor(), std::move(vertices), viewMatrix);
885    if (!op) {
886        return;
887    }
888    GrPipelineBuilder pipelineBuilder(std::move(paint), GrAAType::kNone);
889    this->addLegacyMeshDrawOp(std::move(pipelineBuilder), clip, std::move(op));
890}
891
892///////////////////////////////////////////////////////////////////////////////
893
894void GrRenderTargetContext::drawAtlas(const GrClip& clip,
895                                      GrPaint&& paint,
896                                      const SkMatrix& viewMatrix,
897                                      int spriteCount,
898                                      const SkRSXform xform[],
899                                      const SkRect texRect[],
900                                      const SkColor colors[]) {
901    ASSERT_SINGLE_OWNER
902    RETURN_IF_ABANDONED
903    SkDEBUGCODE(this->validate();)
904    GR_AUDIT_TRAIL_AUTO_FRAME(fAuditTrail, "GrRenderTargetContext::drawAtlas");
905
906    AutoCheckFlush acf(this->drawingManager());
907
908    std::unique_ptr<GrLegacyMeshDrawOp> op =
909            GrDrawAtlasOp::Make(paint.getColor(), viewMatrix, spriteCount, xform, texRect, colors);
910    GrPipelineBuilder pipelineBuilder(std::move(paint), GrAAType::kNone);
911    this->addLegacyMeshDrawOp(std::move(pipelineBuilder), clip, std::move(op));
912}
913
914///////////////////////////////////////////////////////////////////////////////
915
916void GrRenderTargetContext::drawRRect(const GrClip& origClip,
917                                      GrPaint&& paint,
918                                      GrAA aa,
919                                      const SkMatrix& viewMatrix,
920                                      const SkRRect& rrect,
921                                      const GrStyle& style) {
922    ASSERT_SINGLE_OWNER
923    RETURN_IF_ABANDONED
924    SkDEBUGCODE(this->validate();)
925    GR_AUDIT_TRAIL_AUTO_FRAME(fAuditTrail, "GrRenderTargetContext::drawRRect");
926    if (rrect.isEmpty()) {
927       return;
928    }
929
930    GrNoClip noclip;
931    const GrClip* clip = &origClip;
932#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
933    // The Android framework frequently clips rrects to themselves where the clip is non-aa and the
934    // draw is aa. Since our lower level clip code works from op bounds, which are SkRects, it
935    // doesn't detect that the clip can be ignored (modulo antialiasing). The following test
936    // attempts to mitigate the stencil clip cost but will only help when the entire clip stack
937    // can be ignored. We'd prefer to fix this in the framework by removing the clips calls.
938    SkRRect devRRect;
939    if (rrect.transform(viewMatrix, &devRRect) && clip->quickContains(devRRect)) {
940        clip = &noclip;
941    }
942#endif
943    SkASSERT(!style.pathEffect()); // this should've been devolved to a path in SkGpuDevice
944
945    AutoCheckFlush acf(this->drawingManager());
946    const SkStrokeRec stroke = style.strokeRec();
947
948    if (GrCaps::InstancedSupport::kNone != fContext->caps()->instancedSupport() &&
949        stroke.isFillStyle()) {
950        gr_instanced::OpAllocator* oa = this->drawingManager()->instancingAllocator();
951        std::unique_ptr<GrDrawOp> op(
952                oa->recordRRect(rrect, viewMatrix, std::move(paint), aa, fInstancedPipelineInfo));
953        if (op) {
954            this->addDrawOp(*clip, std::move(op));
955            return;
956        }
957    }
958
959    GrAAType aaType = this->chooseAAType(aa, GrAllowMixedSamples::kNo);
960    if (GrAAType::kCoverage == aaType) {
961        const GrShaderCaps* shaderCaps = fContext->caps()->shaderCaps();
962        std::unique_ptr<GrDrawOp> op = GrOvalOpFactory::MakeRRectOp(std::move(paint),
963                                                                    paint.usesDistanceVectorField(),
964                                                                    viewMatrix,
965                                                                    rrect,
966                                                                    stroke,
967                                                                    shaderCaps);
968        if (op) {
969            this->addDrawOp(*clip, std::move(op));
970            return;
971        }
972    }
973
974    SkPath path;
975    path.setIsVolatile(true);
976    path.addRRect(rrect);
977    this->internalDrawPath(*clip, std::move(paint), aa, viewMatrix, path, style);
978}
979
980///////////////////////////////////////////////////////////////////////////////
981
982static SkPoint3 map(const SkMatrix& m, const SkPoint3& pt) {
983    SkPoint3 result;
984    m.mapXY(pt.fX, pt.fY, (SkPoint*)&result.fX);
985    result.fZ = pt.fZ;
986    return result;
987}
988
989bool GrRenderTargetContext::drawFastShadow(const GrClip& clip,
990                                           GrPaint&& paint,
991                                           const SkMatrix& viewMatrix,
992                                           const SkPath& path,
993                                           const SkDrawShadowRec& rec) {
994    ASSERT_SINGLE_OWNER
995    if (this->drawingManager()->wasAbandoned()) {
996        return true;
997    }
998    SkDEBUGCODE(this->validate();)
999    GR_AUDIT_TRAIL_AUTO_FRAME(fAuditTrail, "GrRenderTargetContext::drawFastShadow");
1000
1001    // check z plane
1002    bool tiltZPlane = SkToBool(!SkScalarNearlyZero(rec.fZPlaneParams.fX) ||
1003                               !SkScalarNearlyZero(rec.fZPlaneParams.fY));
1004    bool skipAnalytic = SkToBool(rec.fFlags & SkShadowFlags::kGeometricOnly_ShadowFlag);
1005    if (tiltZPlane || skipAnalytic || !viewMatrix.rectStaysRect() || !viewMatrix.isSimilarity()) {
1006        return false;
1007    }
1008
1009    SkRRect rrect;
1010    SkRect rect;
1011    // we can only handle rects, circles, and rrects with circular corners
1012    bool isRRect = path.isRRect(&rrect) && rrect.isSimpleCircular() &&
1013        rrect.radii(SkRRect::kUpperLeft_Corner).fX > SK_ScalarNearlyZero;
1014    if (!isRRect &&
1015        path.isOval(&rect) && SkScalarNearlyEqual(rect.width(), rect.height()) &&
1016        rect.width() > SK_ScalarNearlyZero) {
1017        rrect.setOval(rect);
1018        isRRect = true;
1019    }
1020    if (!isRRect && path.isRect(&rect)) {
1021        rrect.setRect(rect);
1022        isRRect = true;
1023    }
1024
1025    if (!isRRect) {
1026        return false;
1027    }
1028
1029    if (rrect.isEmpty()) {
1030        return true;
1031    }
1032
1033    AutoCheckFlush acf(this->drawingManager());
1034
1035    // transform light
1036    SkPoint3 devLightPos = map(viewMatrix, rec.fLightPos);
1037
1038    // 1/scale
1039    SkScalar devToSrcScale = viewMatrix.isScaleTranslate() ?
1040        SkScalarInvert(viewMatrix[SkMatrix::kMScaleX]) :
1041        sk_float_rsqrt(viewMatrix[SkMatrix::kMScaleX] * viewMatrix[SkMatrix::kMScaleX] +
1042                       viewMatrix[SkMatrix::kMSkewX] * viewMatrix[SkMatrix::kMSkewX]);
1043
1044    SkScalar occluderHeight = rec.fZPlaneParams.fZ;
1045    GrColor4f color = paint.getColor4f();
1046    bool transparent = SkToBool(rec.fFlags & SkShadowFlags::kTransparentOccluder_ShadowFlag);
1047
1048    if (rec.fAmbientAlpha > 0) {
1049        static constexpr float kHeightFactor = 1.0f / 128.0f;
1050        static constexpr float kGeomFactor = 64.0f;
1051
1052        SkScalar devSpaceInsetWidth = occluderHeight * kHeightFactor * kGeomFactor;
1053        const float umbraAlpha = (1.0f + SkTMax(occluderHeight * kHeightFactor, 0.0f));
1054        const SkScalar devSpaceAmbientBlur = devSpaceInsetWidth * umbraAlpha;
1055
1056        // Outset the shadow rrect to the border of the penumbra
1057        SkScalar ambientPathOutset = devSpaceInsetWidth * devToSrcScale;
1058        SkRRect ambientRRect;
1059        SkRect outsetRect = rrect.rect().makeOutset(ambientPathOutset, ambientPathOutset);
1060        // If the rrect was an oval then its outset will also be one.
1061        // We set it explicitly to avoid errors.
1062        if (rrect.isOval()) {
1063            ambientRRect = SkRRect::MakeOval(outsetRect);
1064        } else {
1065            SkScalar outsetRad = rrect.getSimpleRadii().fX + ambientPathOutset;
1066            ambientRRect = SkRRect::MakeRectXY(outsetRect, outsetRad, outsetRad);
1067        }
1068
1069        GrColor ambientColor = color.mulByScalar(rec.fAmbientAlpha).toGrColor();
1070        if (transparent) {
1071            // set a large inset to force a fill
1072            devSpaceInsetWidth = ambientRRect.width();
1073        }
1074        // the fraction of the blur we want to apply is devSpaceInsetWidth/devSpaceAmbientBlur,
1075        // which is just 1/umbraAlpha.
1076        SkScalar blurClamp = SkScalarInvert(umbraAlpha);
1077
1078        std::unique_ptr<GrLegacyMeshDrawOp> op = GrShadowRRectOp::Make(ambientColor, viewMatrix,
1079                                                                       ambientRRect,
1080                                                                       devSpaceAmbientBlur,
1081                                                                       devSpaceInsetWidth,
1082                                                                       blurClamp);
1083        if (op) {
1084            GrPipelineBuilder pipelineBuilder(std::move(paint), GrAAType::kNone);
1085            this->addLegacyMeshDrawOp(std::move(pipelineBuilder), clip, std::move(op));
1086        }
1087    }
1088
1089    if (rec.fSpotAlpha > 0) {
1090        float zRatio = SkTPin(occluderHeight / (devLightPos.fZ - occluderHeight), 0.0f, 0.95f);
1091
1092        SkScalar devSpaceSpotBlur = 2.0f * rec.fLightRadius * zRatio;
1093        // handle scale of radius and pad due to CTM
1094        const SkScalar srcSpaceSpotBlur = devSpaceSpotBlur * devToSrcScale;
1095
1096        // Compute the scale and translation for the spot shadow.
1097        const SkScalar spotScale = devLightPos.fZ / (devLightPos.fZ - occluderHeight);
1098        SkPoint spotOffset = SkPoint::Make(zRatio*(-devLightPos.fX), zRatio*(-devLightPos.fY));
1099        // Adjust translate for the effect of the scale.
1100        spotOffset.fX += spotScale*viewMatrix[SkMatrix::kMTransX];
1101        spotOffset.fY += spotScale*viewMatrix[SkMatrix::kMTransY];
1102        // This offset is in dev space, need to transform it into source space.
1103        SkMatrix ctmInverse;
1104        if (viewMatrix.invert(&ctmInverse)) {
1105            ctmInverse.mapPoints(&spotOffset, 1);
1106        } else {
1107            // Since the matrix is a similarity, this should never happen, but just in case...
1108            SkDebugf("Matrix is degenerate. Will not render spot shadow correctly!\n");
1109            SkASSERT(false);
1110        }
1111
1112        // Compute the transformed shadow rrect
1113        SkRRect spotShadowRRect;
1114        SkMatrix shadowTransform;
1115        shadowTransform.setScaleTranslate(spotScale, spotScale, spotOffset.fX, spotOffset.fY);
1116        rrect.transform(shadowTransform, &spotShadowRRect);
1117        SkScalar spotRadius = spotShadowRRect.getSimpleRadii().fX;
1118
1119        // Compute the insetWidth
1120        SkScalar blurOutset = 0.5f*srcSpaceSpotBlur;
1121        SkScalar insetWidth = blurOutset;
1122        if (transparent) {
1123            // If transparent, just do a fill
1124            insetWidth += spotShadowRRect.width();
1125        } else {
1126            // For shadows, instead of using a stroke we specify an inset from the penumbra
1127            // border. We want to extend this inset area so that it meets up with the caster
1128            // geometry. The inset geometry will by default already be inset by the blur width.
1129            //
1130            // We compare the min and max corners inset by the radius between the original
1131            // rrect and the shadow rrect. The distance between the two plus the difference
1132            // between the scaled radius and the original radius gives the distance from the
1133            // transformed shadow shape to the original shape in that corner. The max
1134            // of these gives the maximum distance we need to cover.
1135            //
1136            // Since we are outsetting by 1/2 the blur distance, we just add the maxOffset to
1137            // that to get the full insetWidth.
1138            SkScalar maxOffset;
1139            if (rrect.isRect()) {
1140                // Manhattan distance works better for rects
1141                maxOffset = SkTMax(SkTMax(SkTAbs(spotShadowRRect.rect().fLeft -
1142                                                 rrect.rect().fLeft),
1143                                          SkTAbs(spotShadowRRect.rect().fTop -
1144                                                 rrect.rect().fTop)),
1145                                   SkTMax(SkTAbs(spotShadowRRect.rect().fRight -
1146                                                 rrect.rect().fRight),
1147                                          SkTAbs(spotShadowRRect.rect().fBottom -
1148                                                 rrect.rect().fBottom)));
1149            } else {
1150                SkScalar dr = spotRadius - rrect.getSimpleRadii().fX;
1151                SkPoint upperLeftOffset = SkPoint::Make(spotShadowRRect.rect().fLeft -
1152                                                        rrect.rect().fLeft + dr,
1153                                                        spotShadowRRect.rect().fTop -
1154                                                        rrect.rect().fTop + dr);
1155                SkPoint lowerRightOffset = SkPoint::Make(spotShadowRRect.rect().fRight -
1156                                                         rrect.rect().fRight - dr,
1157                                                         spotShadowRRect.rect().fBottom -
1158                                                         rrect.rect().fBottom - dr);
1159                maxOffset = SkScalarSqrt(SkTMax(upperLeftOffset.lengthSqd(),
1160                                                lowerRightOffset.lengthSqd())) + dr;
1161            }
1162            insetWidth += maxOffset;
1163        }
1164
1165        // Outset the shadow rrect to the border of the penumbra
1166        SkRect outsetRect = spotShadowRRect.rect().makeOutset(blurOutset, blurOutset);
1167        if (spotShadowRRect.isOval()) {
1168            spotShadowRRect = SkRRect::MakeOval(outsetRect);
1169        } else {
1170            SkScalar outsetRad = spotRadius + blurOutset;
1171            spotShadowRRect = SkRRect::MakeRectXY(outsetRect, outsetRad, outsetRad);
1172        }
1173
1174        GrColor spotColor = color.mulByScalar(rec.fSpotAlpha).toGrColor();
1175        std::unique_ptr<GrLegacyMeshDrawOp> op = GrShadowRRectOp::Make(spotColor, viewMatrix,
1176                                                                       spotShadowRRect,
1177                                                                       devSpaceSpotBlur,
1178                                                                       insetWidth);
1179        if (op) {
1180            GrPipelineBuilder pipelineBuilder(std::move(paint), GrAAType::kNone);
1181            this->addLegacyMeshDrawOp(std::move(pipelineBuilder), clip, std::move(op));
1182        }
1183    }
1184
1185    return true;
1186}
1187
1188///////////////////////////////////////////////////////////////////////////////
1189
1190bool GrRenderTargetContext::drawFilledDRRect(const GrClip& clip,
1191                                             GrPaint&& paint,
1192                                             GrAA aa,
1193                                             const SkMatrix& viewMatrix,
1194                                             const SkRRect& origOuter,
1195                                             const SkRRect& origInner) {
1196    SkASSERT(!origInner.isEmpty());
1197    SkASSERT(!origOuter.isEmpty());
1198
1199    if (GrCaps::InstancedSupport::kNone != fContext->caps()->instancedSupport()) {
1200        gr_instanced::OpAllocator* oa = this->drawingManager()->instancingAllocator();
1201        std::unique_ptr<GrDrawOp> op(oa->recordDRRect(
1202                origOuter, origInner, viewMatrix, std::move(paint), aa, fInstancedPipelineInfo));
1203        if (op) {
1204            this->addDrawOp(clip, std::move(op));
1205            return true;
1206        }
1207    }
1208
1209    GrAAType aaType = this->chooseAAType(aa, GrAllowMixedSamples::kNo);
1210
1211    GrPrimitiveEdgeType innerEdgeType, outerEdgeType;
1212    if (GrAAType::kCoverage == aaType) {
1213        innerEdgeType = kInverseFillAA_GrProcessorEdgeType;
1214        outerEdgeType = kFillAA_GrProcessorEdgeType;
1215    } else {
1216        innerEdgeType = kInverseFillBW_GrProcessorEdgeType;
1217        outerEdgeType = kFillBW_GrProcessorEdgeType;
1218    }
1219
1220    SkTCopyOnFirstWrite<SkRRect> inner(origInner), outer(origOuter);
1221    SkMatrix inverseVM;
1222    if (!viewMatrix.isIdentity()) {
1223        if (!origInner.transform(viewMatrix, inner.writable())) {
1224            return false;
1225        }
1226        if (!origOuter.transform(viewMatrix, outer.writable())) {
1227            return false;
1228        }
1229        if (!viewMatrix.invert(&inverseVM)) {
1230            return false;
1231        }
1232    } else {
1233        inverseVM.reset();
1234    }
1235
1236    // TODO these need to be a geometry processors
1237    sk_sp<GrFragmentProcessor> innerEffect(GrRRectEffect::Make(innerEdgeType, *inner));
1238    if (!innerEffect) {
1239        return false;
1240    }
1241
1242    sk_sp<GrFragmentProcessor> outerEffect(GrRRectEffect::Make(outerEdgeType, *outer));
1243    if (!outerEffect) {
1244        return false;
1245    }
1246
1247    paint.addCoverageFragmentProcessor(std::move(innerEffect));
1248    paint.addCoverageFragmentProcessor(std::move(outerEffect));
1249
1250    SkRect bounds = outer->getBounds();
1251    if (GrAAType::kCoverage == aaType) {
1252        bounds.outset(SK_ScalarHalf, SK_ScalarHalf);
1253    }
1254
1255    this->fillRectWithLocalMatrix(clip, std::move(paint), GrAA::kNo, SkMatrix::I(), bounds,
1256                                  inverseVM);
1257    return true;
1258}
1259
1260void GrRenderTargetContext::drawDRRect(const GrClip& clip,
1261                                       GrPaint&& paint,
1262                                       GrAA aa,
1263                                       const SkMatrix& viewMatrix,
1264                                       const SkRRect& outer,
1265                                       const SkRRect& inner) {
1266    ASSERT_SINGLE_OWNER
1267    RETURN_IF_ABANDONED
1268    SkDEBUGCODE(this->validate();)
1269    GR_AUDIT_TRAIL_AUTO_FRAME(fAuditTrail, "GrRenderTargetContext::drawDRRect");
1270
1271    SkASSERT(!outer.isEmpty());
1272    SkASSERT(!inner.isEmpty());
1273
1274    AutoCheckFlush acf(this->drawingManager());
1275
1276    if (this->drawFilledDRRect(clip, std::move(paint), aa, viewMatrix, outer, inner)) {
1277        return;
1278    }
1279
1280    SkPath path;
1281    path.setIsVolatile(true);
1282    path.addRRect(inner);
1283    path.addRRect(outer);
1284    path.setFillType(SkPath::kEvenOdd_FillType);
1285
1286    this->internalDrawPath(clip, std::move(paint), aa, viewMatrix, path, GrStyle::SimpleFill());
1287}
1288
1289///////////////////////////////////////////////////////////////////////////////
1290
1291static inline bool is_int(float x) {
1292    return x == (float) sk_float_round2int(x);
1293}
1294
1295void GrRenderTargetContext::drawRegion(const GrClip& clip,
1296                                       GrPaint&& paint,
1297                                       GrAA aa,
1298                                       const SkMatrix& viewMatrix,
1299                                       const SkRegion& region,
1300                                       const GrStyle& style) {
1301    ASSERT_SINGLE_OWNER
1302    RETURN_IF_ABANDONED
1303    SkDEBUGCODE(this->validate();)
1304    GR_AUDIT_TRAIL_AUTO_FRAME(fAuditTrail, "GrRenderTargetContext::drawRegion");
1305
1306    if (GrAA::kYes == aa) {
1307        // GrRegionOp performs no antialiasing but is much faster, so here we check the matrix
1308        // to see whether aa is really required.
1309        if (!SkToBool(viewMatrix.getType() & ~(SkMatrix::kTranslate_Mask)) &&
1310            is_int(viewMatrix.getTranslateX()) &&
1311            is_int(viewMatrix.getTranslateY())) {
1312            aa = GrAA::kNo;
1313        }
1314    }
1315    bool complexStyle = !style.isSimpleFill();
1316    if (complexStyle || GrAA::kYes == aa) {
1317        SkPath path;
1318        region.getBoundaryPath(&path);
1319        return this->drawPath(clip, std::move(paint), aa, viewMatrix, path, style);
1320    }
1321
1322    std::unique_ptr<GrLegacyMeshDrawOp> op = GrRegionOp::Make(paint.getColor(), viewMatrix, region);
1323    GrPipelineBuilder pipelineBuilder(std::move(paint), GrAAType::kNone);
1324    this->addLegacyMeshDrawOp(std::move(pipelineBuilder), clip, std::move(op));
1325}
1326
1327void GrRenderTargetContext::drawOval(const GrClip& clip,
1328                                     GrPaint&& paint,
1329                                     GrAA aa,
1330                                     const SkMatrix& viewMatrix,
1331                                     const SkRect& oval,
1332                                     const GrStyle& style) {
1333    ASSERT_SINGLE_OWNER
1334    RETURN_IF_ABANDONED
1335    SkDEBUGCODE(this->validate();)
1336    GR_AUDIT_TRAIL_AUTO_FRAME(fAuditTrail, "GrRenderTargetContext::drawOval");
1337
1338    if (oval.isEmpty()) {
1339       return;
1340    }
1341
1342    SkASSERT(!style.pathEffect()); // this should've been devolved to a path in SkGpuDevice
1343
1344    AutoCheckFlush acf(this->drawingManager());
1345    const SkStrokeRec& stroke = style.strokeRec();
1346
1347    if (GrCaps::InstancedSupport::kNone != fContext->caps()->instancedSupport() &&
1348        stroke.isFillStyle()) {
1349        gr_instanced::OpAllocator* oa = this->drawingManager()->instancingAllocator();
1350        std::unique_ptr<GrDrawOp> op(
1351                oa->recordOval(oval, viewMatrix, std::move(paint), aa, fInstancedPipelineInfo));
1352        if (op) {
1353            this->addDrawOp(clip, std::move(op));
1354            return;
1355        }
1356    }
1357
1358    GrAAType aaType = this->chooseAAType(aa, GrAllowMixedSamples::kNo);
1359    if (GrAAType::kCoverage == aaType) {
1360        const GrShaderCaps* shaderCaps = fContext->caps()->shaderCaps();
1361        std::unique_ptr<GrDrawOp> op =
1362                GrOvalOpFactory::MakeOvalOp(std::move(paint), viewMatrix, oval, stroke, shaderCaps);
1363        if (op) {
1364            this->addDrawOp(clip, std::move(op));
1365            return;
1366        }
1367    }
1368
1369    SkPath path;
1370    path.setIsVolatile(true);
1371    path.addOval(oval);
1372    this->internalDrawPath(clip, std::move(paint), aa, viewMatrix, path, style);
1373}
1374
1375void GrRenderTargetContext::drawArc(const GrClip& clip,
1376                                    GrPaint&& paint,
1377                                    GrAA aa,
1378                                    const SkMatrix& viewMatrix,
1379                                    const SkRect& oval,
1380                                    SkScalar startAngle,
1381                                    SkScalar sweepAngle,
1382                                    bool useCenter,
1383                                    const GrStyle& style) {
1384    ASSERT_SINGLE_OWNER
1385    RETURN_IF_ABANDONED
1386    SkDEBUGCODE(this->validate();)
1387    GR_AUDIT_TRAIL_AUTO_FRAME(fAuditTrail, "GrRenderTargetContext::drawArc");
1388
1389    AutoCheckFlush acf(this->drawingManager());
1390
1391    GrAAType aaType = this->chooseAAType(aa, GrAllowMixedSamples::kNo);
1392    if (GrAAType::kCoverage == aaType) {
1393        const GrShaderCaps* shaderCaps = fContext->caps()->shaderCaps();
1394        std::unique_ptr<GrDrawOp> op = GrOvalOpFactory::MakeArcOp(std::move(paint),
1395                                                                  viewMatrix,
1396                                                                  oval,
1397                                                                  startAngle,
1398                                                                  sweepAngle,
1399                                                                  useCenter,
1400                                                                  style,
1401                                                                  shaderCaps);
1402        if (op) {
1403            this->addDrawOp(clip, std::move(op));
1404            return;
1405        }
1406    }
1407    SkPath path;
1408    SkPathPriv::CreateDrawArcPath(&path, oval, startAngle, sweepAngle, useCenter,
1409                                  style.isSimpleFill());
1410    this->internalDrawPath(clip, std::move(paint), aa, viewMatrix, path, style);
1411}
1412
1413void GrRenderTargetContext::drawImageLattice(const GrClip& clip,
1414                                             GrPaint&& paint,
1415                                             const SkMatrix& viewMatrix,
1416                                             int imageWidth,
1417                                             int imageHeight,
1418                                             std::unique_ptr<SkLatticeIter> iter,
1419                                             const SkRect& dst) {
1420    ASSERT_SINGLE_OWNER
1421    RETURN_IF_ABANDONED
1422    SkDEBUGCODE(this->validate();)
1423    GR_AUDIT_TRAIL_AUTO_FRAME(fAuditTrail, "GrRenderTargetContext::drawImageLattice");
1424
1425    AutoCheckFlush acf(this->drawingManager());
1426
1427    std::unique_ptr<GrLegacyMeshDrawOp> op = GrLatticeOp::MakeNonAA(
1428            paint.getColor(), viewMatrix, imageWidth, imageHeight, std::move(iter), dst);
1429
1430    GrPipelineBuilder pipelineBuilder(std::move(paint), GrAAType::kNone);
1431    this->addLegacyMeshDrawOp(std::move(pipelineBuilder), clip, std::move(op));
1432}
1433
1434void GrRenderTargetContext::prepareForExternalIO() {
1435    ASSERT_SINGLE_OWNER
1436    RETURN_IF_ABANDONED
1437    SkDEBUGCODE(this->validate();)
1438    GR_AUDIT_TRAIL_AUTO_FRAME(fAuditTrail, "GrRenderTargetContext::prepareForExternalIO");
1439
1440    this->drawingManager()->prepareSurfaceForExternalIO(fRenderTargetProxy.get());
1441}
1442
1443void GrRenderTargetContext::drawNonAAFilledRect(const GrClip& clip,
1444                                                GrPaint&& paint,
1445                                                const SkMatrix& viewMatrix,
1446                                                const SkRect& rect,
1447                                                const SkRect* localRect,
1448                                                const SkMatrix* localMatrix,
1449                                                const GrUserStencilSettings* ss,
1450                                                GrAAType hwOrNoneAAType) {
1451    SkASSERT(GrAAType::kCoverage != hwOrNoneAAType);
1452    SkASSERT(GrAAType::kNone == hwOrNoneAAType || GrFSAAType::kNone != this->fsaaType());
1453    std::unique_ptr<GrDrawOp> op = GrNonAAFillRectOp::Make(
1454            std::move(paint), viewMatrix, rect, localRect, localMatrix, hwOrNoneAAType, ss);
1455    this->addDrawOp(clip, std::move(op));
1456}
1457
1458// Can 'path' be drawn as a pair of filled nested rectangles?
1459static bool fills_as_nested_rects(const SkMatrix& viewMatrix, const SkPath& path, SkRect rects[2]) {
1460
1461    if (path.isInverseFillType()) {
1462        return false;
1463    }
1464
1465    // TODO: this restriction could be lifted if we were willing to apply
1466    // the matrix to all the points individually rather than just to the rect
1467    if (!viewMatrix.rectStaysRect()) {
1468        return false;
1469    }
1470
1471    SkPath::Direction dirs[2];
1472    if (!path.isNestedFillRects(rects, dirs)) {
1473        return false;
1474    }
1475
1476    if (SkPath::kWinding_FillType == path.getFillType() && dirs[0] == dirs[1]) {
1477        // The two rects need to be wound opposite to each other
1478        return false;
1479    }
1480
1481    // Right now, nested rects where the margin is not the same width
1482    // all around do not render correctly
1483    const SkScalar* outer = rects[0].asScalars();
1484    const SkScalar* inner = rects[1].asScalars();
1485
1486    bool allEq = true;
1487
1488    SkScalar margin = SkScalarAbs(outer[0] - inner[0]);
1489    bool allGoE1 = margin >= SK_Scalar1;
1490
1491    for (int i = 1; i < 4; ++i) {
1492        SkScalar temp = SkScalarAbs(outer[i] - inner[i]);
1493        if (temp < SK_Scalar1) {
1494            allGoE1 = false;
1495        }
1496        if (!SkScalarNearlyEqual(margin, temp)) {
1497            allEq = false;
1498        }
1499    }
1500
1501    return allEq || allGoE1;
1502}
1503
1504void GrRenderTargetContext::drawPath(const GrClip& clip,
1505                                     GrPaint&& paint,
1506                                     GrAA aa,
1507                                     const SkMatrix& viewMatrix,
1508                                     const SkPath& path,
1509                                     const GrStyle& style) {
1510    ASSERT_SINGLE_OWNER
1511    RETURN_IF_ABANDONED
1512    SkDEBUGCODE(this->validate();)
1513    GR_AUDIT_TRAIL_AUTO_FRAME(fAuditTrail, "GrRenderTargetContext::drawPath");
1514
1515    if (path.isEmpty()) {
1516       if (path.isInverseFillType()) {
1517           this->drawPaint(clip, std::move(paint), viewMatrix);
1518       }
1519       return;
1520    }
1521
1522    AutoCheckFlush acf(this->drawingManager());
1523
1524    GrAAType aaType = this->chooseAAType(aa, GrAllowMixedSamples::kNo);
1525    if (GrAAType::kCoverage == aaType && !style.pathEffect()) {
1526        if (style.isSimpleFill() && !path.isConvex()) {
1527            // Concave AA paths are expensive - try to avoid them for special cases
1528            SkRect rects[2];
1529
1530            if (fills_as_nested_rects(viewMatrix, path, rects)) {
1531                std::unique_ptr<GrLegacyMeshDrawOp> op =
1532                        GrRectOpFactory::MakeAAFillNestedRects(paint.getColor(), viewMatrix, rects);
1533                if (op) {
1534                    GrPipelineBuilder pipelineBuilder(std::move(paint), aaType);
1535                    this->addLegacyMeshDrawOp(std::move(pipelineBuilder), clip, std::move(op));
1536                }
1537                return;
1538            }
1539        }
1540        SkRect ovalRect;
1541        bool isOval = path.isOval(&ovalRect);
1542
1543        if (isOval && !path.isInverseFillType()) {
1544            const GrShaderCaps* shaderCaps = fContext->caps()->shaderCaps();
1545            std::unique_ptr<GrDrawOp> op = GrOvalOpFactory::MakeOvalOp(
1546                    std::move(paint), viewMatrix, ovalRect, style.strokeRec(), shaderCaps);
1547            if (op) {
1548                this->addDrawOp(clip, std::move(op));
1549                return;
1550            }
1551        }
1552    }
1553
1554    // Note that internalDrawPath may sw-rasterize the path into a scratch texture.
1555    // Scratch textures can be recycled after they are returned to the texture
1556    // cache. This presents a potential hazard for buffered drawing. However,
1557    // the writePixels that uploads to the scratch will perform a flush so we're
1558    // OK.
1559    this->internalDrawPath(clip, std::move(paint), aa, viewMatrix, path, style);
1560}
1561
1562bool GrRenderTargetContextPriv::drawAndStencilPath(const GrClip& clip,
1563                                                   const GrUserStencilSettings* ss,
1564                                                   SkRegion::Op op,
1565                                                   bool invert,
1566                                                   GrAA aa,
1567                                                   const SkMatrix& viewMatrix,
1568                                                   const SkPath& path) {
1569    ASSERT_SINGLE_OWNER_PRIV
1570    RETURN_FALSE_IF_ABANDONED_PRIV
1571    SkDEBUGCODE(fRenderTargetContext->validate();)
1572    GR_AUDIT_TRAIL_AUTO_FRAME(fRenderTargetContext->fAuditTrail,
1573                              "GrRenderTargetContextPriv::drawAndStencilPath");
1574
1575    if (path.isEmpty() && path.isInverseFillType()) {
1576        this->drawAndStencilRect(clip, ss, op, invert, GrAA::kNo, SkMatrix::I(),
1577                                 SkRect::MakeIWH(fRenderTargetContext->width(),
1578                                                 fRenderTargetContext->height()));
1579        return true;
1580    }
1581
1582    AutoCheckFlush acf(fRenderTargetContext->drawingManager());
1583
1584    // An Assumption here is that path renderer would use some form of tweaking
1585    // the src color (either the input alpha or in the frag shader) to implement
1586    // aa. If we have some future driver-mojo path AA that can do the right
1587    // thing WRT to the blend then we'll need some query on the PR.
1588    GrAAType aaType = fRenderTargetContext->chooseAAType(aa, GrAllowMixedSamples::kNo);
1589    bool hasUserStencilSettings = !ss->isUnused();
1590
1591    GrShape shape(path, GrStyle::SimpleFill());
1592    GrPathRenderer::CanDrawPathArgs canDrawArgs;
1593    canDrawArgs.fCaps = fRenderTargetContext->drawingManager()->getContext()->caps();
1594    canDrawArgs.fViewMatrix = &viewMatrix;
1595    canDrawArgs.fShape = &shape;
1596    canDrawArgs.fAAType = aaType;
1597    canDrawArgs.fHasUserStencilSettings = hasUserStencilSettings;
1598
1599    // Don't allow the SW renderer
1600    GrPathRenderer* pr = fRenderTargetContext->drawingManager()->getPathRenderer(
1601            canDrawArgs, false, GrPathRendererChain::DrawType::kStencilAndColor);
1602    if (!pr) {
1603        return false;
1604    }
1605
1606    GrPaint paint;
1607    paint.setCoverageSetOpXPFactory(op, invert);
1608
1609    GrPathRenderer::DrawPathArgs args{
1610            fRenderTargetContext->drawingManager()->getContext(),
1611            std::move(paint),
1612            ss,
1613            fRenderTargetContext,
1614            &clip,
1615            &viewMatrix,
1616            &shape,
1617            aaType,
1618            fRenderTargetContext->isGammaCorrect()};
1619    pr->drawPath(args);
1620    return true;
1621}
1622
1623SkBudgeted GrRenderTargetContextPriv::isBudgeted() const {
1624    ASSERT_SINGLE_OWNER_PRIV
1625
1626    if (fRenderTargetContext->wasAbandoned()) {
1627        return SkBudgeted::kNo;
1628    }
1629
1630    SkDEBUGCODE(fRenderTargetContext->validate();)
1631
1632    return fRenderTargetContext->fRenderTargetProxy->isBudgeted();
1633}
1634
1635void GrRenderTargetContext::internalDrawPath(const GrClip& clip,
1636                                             GrPaint&& paint,
1637                                             GrAA aa,
1638                                             const SkMatrix& viewMatrix,
1639                                             const SkPath& path,
1640                                             const GrStyle& style) {
1641    ASSERT_SINGLE_OWNER
1642    RETURN_IF_ABANDONED
1643    SkASSERT(!path.isEmpty());
1644    GrShape shape;
1645    // NVPR cannot handle hairlines, so this would get picked up by a different stencil and
1646    // cover path renderer (i.e. default path renderer). The hairline renderer produces much
1647    // smoother hairlines than MSAA.
1648    GrAllowMixedSamples allowMixedSamples =
1649            style.isSimpleHairline() ? GrAllowMixedSamples::kNo : GrAllowMixedSamples::kYes;
1650    GrAAType aaType = this->chooseAAType(aa, allowMixedSamples);
1651    GrPathRenderer::CanDrawPathArgs canDrawArgs;
1652    canDrawArgs.fCaps = this->drawingManager()->getContext()->caps();
1653    canDrawArgs.fViewMatrix = &viewMatrix;
1654    canDrawArgs.fShape = &shape;
1655    canDrawArgs.fHasUserStencilSettings = false;
1656
1657    GrPathRenderer* pr;
1658    static constexpr GrPathRendererChain::DrawType kType = GrPathRendererChain::DrawType::kColor;
1659    do {
1660        shape = GrShape(path, style);
1661        if (shape.isEmpty()) {
1662            return;
1663        }
1664
1665        canDrawArgs.fAAType = aaType;
1666
1667        // Try a 1st time without applying any of the style to the geometry (and barring sw)
1668        pr = this->drawingManager()->getPathRenderer(canDrawArgs, false, kType);
1669        SkScalar styleScale =  GrStyle::MatrixToScaleFactor(viewMatrix);
1670
1671        if (!pr && shape.style().pathEffect()) {
1672            // It didn't work above, so try again with the path effect applied.
1673            shape = shape.applyStyle(GrStyle::Apply::kPathEffectOnly, styleScale);
1674            if (shape.isEmpty()) {
1675                return;
1676            }
1677            pr = this->drawingManager()->getPathRenderer(canDrawArgs, false, kType);
1678        }
1679        if (!pr) {
1680            if (shape.style().applies()) {
1681                shape = shape.applyStyle(GrStyle::Apply::kPathEffectAndStrokeRec, styleScale);
1682                if (shape.isEmpty()) {
1683                    return;
1684                }
1685            }
1686            // This time, allow SW renderer
1687            pr = this->drawingManager()->getPathRenderer(canDrawArgs, true, kType);
1688        }
1689        if (!pr && GrAATypeIsHW(aaType)) {
1690            // There are exceptional cases where we may wind up falling back to coverage based AA
1691            // when the target is MSAA (e.g. through disabling path renderers via GrContextOptions).
1692            aaType = GrAAType::kCoverage;
1693        } else {
1694            break;
1695        }
1696    } while(true);
1697
1698    if (!pr) {
1699#ifdef SK_DEBUG
1700        SkDebugf("Unable to find path renderer compatible with path.\n");
1701#endif
1702        return;
1703    }
1704
1705    GrPathRenderer::DrawPathArgs args{this->drawingManager()->getContext(),
1706                                      std::move(paint),
1707                                      &GrUserStencilSettings::kUnused,
1708                                      this,
1709                                      &clip,
1710                                      &viewMatrix,
1711                                      &shape,
1712                                      aaType,
1713                                      this->isGammaCorrect()};
1714    pr->drawPath(args);
1715}
1716
1717static void op_bounds(SkRect* bounds, const GrOp* op) {
1718    *bounds = op->bounds();
1719    if (op->hasZeroArea()) {
1720        if (op->hasAABloat()) {
1721            bounds->outset(0.5f, 0.5f);
1722        } else {
1723            // We don't know which way the particular GPU will snap lines or points at integer
1724            // coords. So we ensure that the bounds is large enough for either snap.
1725            SkRect before = *bounds;
1726            bounds->roundOut(bounds);
1727            if (bounds->fLeft == before.fLeft) {
1728                bounds->fLeft -= 1;
1729            }
1730            if (bounds->fTop == before.fTop) {
1731                bounds->fTop -= 1;
1732            }
1733            if (bounds->fRight == before.fRight) {
1734                bounds->fRight += 1;
1735            }
1736            if (bounds->fBottom == before.fBottom) {
1737                bounds->fBottom += 1;
1738            }
1739        }
1740    }
1741}
1742
1743uint32_t GrRenderTargetContext::addDrawOp(const GrClip& clip, std::unique_ptr<GrDrawOp> op) {
1744    ASSERT_SINGLE_OWNER
1745    if (this->drawingManager()->wasAbandoned()) {
1746        return SK_InvalidUniqueID;
1747    }
1748    SkDEBUGCODE(this->validate();)
1749    GR_AUDIT_TRAIL_AUTO_FRAME(fAuditTrail, "GrRenderTargetContext::addDrawOp");
1750
1751    // Setup clip
1752    SkRect bounds;
1753    op_bounds(&bounds, op.get());
1754    GrAppliedClip appliedClip;
1755    GrDrawOp::FixedFunctionFlags fixedFunctionFlags = op->fixedFunctionFlags();
1756    if (!clip.apply(fContext, this, fixedFunctionFlags & GrDrawOp::FixedFunctionFlags::kUsesHWAA,
1757                    fixedFunctionFlags & GrDrawOp::FixedFunctionFlags::kUsesStencil, &appliedClip,
1758                    &bounds)) {
1759        return SK_InvalidUniqueID;
1760    }
1761
1762    if (fixedFunctionFlags & GrDrawOp::FixedFunctionFlags::kUsesStencil ||
1763        appliedClip.hasStencilClip()) {
1764        // This forces instantiation of the render target.
1765        GrRenderTarget* rt = this->accessRenderTarget();
1766        if (!rt) {
1767            return SK_InvalidUniqueID;
1768        }
1769
1770        if (!fContext->resourceProvider()->attachStencilAttachment(rt)) {
1771            SkDebugf("ERROR creating stencil attachment. Draw skipped.\n");
1772            return SK_InvalidUniqueID;
1773        }
1774    }
1775
1776    GrXferProcessor::DstTexture dstTexture;
1777    if (op->xpRequiresDstTexture(*this->caps(), &appliedClip)) {
1778        if (!this->setupDstTexture(fRenderTargetProxy.get(), clip, op->bounds(), &dstTexture)) {
1779            return SK_InvalidUniqueID;
1780        }
1781    }
1782
1783    op->setClippedBounds(bounds);
1784    return this->getOpList()->addOp(std::move(op), *this->caps(),
1785                                    std::move(appliedClip), dstTexture);
1786}
1787
1788uint32_t GrRenderTargetContext::addLegacyMeshDrawOp(GrPipelineBuilder&& pipelineBuilder,
1789                                                    const GrClip& clip,
1790                                                    std::unique_ptr<GrLegacyMeshDrawOp> op) {
1791    ASSERT_SINGLE_OWNER
1792    if (this->drawingManager()->wasAbandoned()) {
1793        return SK_InvalidUniqueID;
1794    }
1795    SkDEBUGCODE(this->validate();)
1796    GR_AUDIT_TRAIL_AUTO_FRAME(fAuditTrail, "GrRenderTargetContext::addLegacyMeshDrawOp");
1797
1798    // Setup clip
1799    SkRect bounds;
1800    op_bounds(&bounds, op.get());
1801    GrAppliedClip appliedClip;
1802    if (!clip.apply(fContext, this, pipelineBuilder.isHWAntialias(),
1803                    pipelineBuilder.hasUserStencilSettings(), &appliedClip, &bounds)) {
1804        return SK_InvalidUniqueID;
1805    }
1806
1807    // This forces instantiation of the render target. Pipeline creation is moving to flush time
1808    // by which point instantiation must have occurred anyway.
1809    GrRenderTarget* rt = this->accessRenderTarget();
1810    if (!rt) {
1811        return SK_InvalidUniqueID;
1812    }
1813
1814    GrResourceProvider* resourceProvider = fContext->resourceProvider();
1815    bool usesStencil = pipelineBuilder.hasUserStencilSettings() || appliedClip.hasStencilClip();
1816    if (usesStencil) {
1817        if (!resourceProvider->attachStencilAttachment(this->accessRenderTarget())) {
1818            SkDebugf("ERROR creating stencil attachment. Draw skipped.\n");
1819            return SK_InvalidUniqueID;
1820        }
1821    }
1822
1823    bool isMixedSamples = GrFSAAType::kMixedSamples == this->fsaaType() &&
1824                          (pipelineBuilder.isHWAntialias() || usesStencil);
1825
1826    GrColor overrideColor;
1827    GrProcessorSet::Analysis analysis = op->analyzeUpdateAndRecordProcessors(
1828            &pipelineBuilder, &appliedClip, isMixedSamples, *this->caps(), &overrideColor);
1829
1830    GrPipeline::InitArgs args;
1831    pipelineBuilder.getPipelineInitArgs(&args);
1832    args.fAppliedClip = &appliedClip;
1833    args.fRenderTarget = rt;
1834    args.fCaps = this->caps();
1835
1836    if (analysis.requiresDstTexture()) {
1837        if (!this->setupDstTexture(fRenderTargetProxy.get(), clip, bounds, &args.fDstTexture)) {
1838            return SK_InvalidUniqueID;
1839        }
1840    }
1841    op->initPipeline(args, analysis, overrideColor);
1842
1843    // Add the pipeline dependencies on textures, etc before recording this op.
1844    op->addDependenciesTo(fRenderTargetProxy.get());
1845
1846    op->setClippedBounds(bounds);
1847    return this->getOpList()->addOp(std::move(op), *this->caps());
1848}
1849
1850bool GrRenderTargetContext::setupDstTexture(GrRenderTargetProxy* rtProxy, const GrClip& clip,
1851                                            const SkRect& opBounds,
1852                                            GrXferProcessor::DstTexture* dstTexture) {
1853    if (this->caps()->textureBarrierSupport()) {
1854        if (GrTextureProxy* texProxy = rtProxy->asTextureProxy()) {
1855            // MDB TODO: remove this instantiation. Blocked on making DstTexture be proxy-based
1856            sk_sp<GrTexture> tex(
1857                    sk_ref_sp(texProxy->instantiateTexture(fContext->resourceProvider())));
1858            if (!tex) {
1859                SkDebugf("setupDstTexture: instantiation of src texture failed.\n");
1860                return false;  // We have bigger problems now
1861            }
1862
1863            // The render target is a texture, so we can read from it directly in the shader. The XP
1864            // will be responsible to detect this situation and request a texture barrier.
1865            dstTexture->setTexture(std::move(tex));
1866            dstTexture->setOffset(0, 0);
1867            return true;
1868        }
1869    }
1870
1871    SkIRect copyRect = SkIRect::MakeWH(rtProxy->width(), rtProxy->height());
1872
1873    SkIRect clippedRect;
1874    clip.getConservativeBounds(rtProxy->width(), rtProxy->height(), &clippedRect);
1875    SkIRect drawIBounds;
1876    opBounds.roundOut(&drawIBounds);
1877    // Cover up for any precision issues by outsetting the op bounds a pixel in each direction.
1878    drawIBounds.outset(1, 1);
1879    if (!clippedRect.intersect(drawIBounds)) {
1880#ifdef SK_DEBUG
1881        GrCapsDebugf(this->caps(), "setupDstTexture: Missed an early reject bailing on draw.");
1882#endif
1883        return false;
1884    }
1885
1886    // MSAA consideration: When there is support for reading MSAA samples in the shader we could
1887    // have per-sample dst values by making the copy multisampled.
1888    GrSurfaceDesc desc;
1889    bool rectsMustMatch = false;
1890    bool disallowSubrect = false;
1891    if (!this->caps()->initDescForDstCopy(rtProxy, &desc, &rectsMustMatch, &disallowSubrect)) {
1892        desc.fOrigin = kBottomLeft_GrSurfaceOrigin;
1893        desc.fFlags = kRenderTarget_GrSurfaceFlag;
1894        desc.fConfig = rtProxy->config();
1895    }
1896
1897    if (!disallowSubrect) {
1898        copyRect = clippedRect;
1899    }
1900
1901    SkIPoint dstPoint, dstOffset;
1902    SkBackingFit fit;
1903    if (rectsMustMatch) {
1904        SkASSERT(desc.fOrigin == rtProxy->origin());
1905        desc.fWidth = rtProxy->width();
1906        desc.fHeight = rtProxy->height();
1907        dstPoint = {copyRect.fLeft, copyRect.fTop};
1908        dstOffset = {0, 0};
1909        fit = SkBackingFit::kExact;
1910    } else {
1911        desc.fWidth = copyRect.width();
1912        desc.fHeight = copyRect.height();
1913        dstPoint = {0, 0};
1914        dstOffset = {copyRect.fLeft, copyRect.fTop};
1915        fit = SkBackingFit::kApprox;
1916    }
1917
1918    sk_sp<GrSurfaceContext> sContext = fContext->contextPriv().makeDeferredSurfaceContext(
1919                                                                                desc,
1920                                                                                fit,
1921                                                                                SkBudgeted::kYes);
1922    if (!sContext) {
1923        SkDebugf("setupDstTexture: surfaceContext creation failed.\n");
1924        return false;
1925    }
1926
1927    if (!sContext->copy(rtProxy, copyRect, dstPoint)) {
1928        SkDebugf("setupDstTexture: copy failed.\n");
1929        return false;
1930    }
1931
1932    GrTextureProxy* copyProxy = sContext->asTextureProxy();
1933    // MDB TODO: remove this instantiation once DstTexture is proxy-backed
1934    sk_sp<GrTexture> copy(sk_ref_sp(copyProxy->instantiateTexture(fContext->resourceProvider())));
1935    if (!copy) {
1936        SkDebugf("setupDstTexture: instantiation of copied texture failed.\n");
1937        return false;
1938    }
1939
1940    dstTexture->setTexture(std::move(copy));
1941    dstTexture->setOffset(dstOffset);
1942    return true;
1943}
1944