Home | History | Annotate | Download | only in gpu
      1 
      2 /*
      3  * Copyright 2015 Google Inc.
      4  *
      5  * Use of this source code is governed by a BSD-style license that can be
      6  * found in the LICENSE file.
      7  */
      8 
      9 #include "GrBatchTest.h"
     10 #include "GrColor.h"
     11 #include "GrDrawContext.h"
     12 #include "GrDrawingManager.h"
     13 #include "GrOvalRenderer.h"
     14 #include "GrPathRenderer.h"
     15 #include "GrRenderTarget.h"
     16 #include "GrRenderTargetPriv.h"
     17 #include "GrResourceProvider.h"
     18 #include "SkSurfacePriv.h"
     19 
     20 #include "batches/GrBatch.h"
     21 #include "batches/GrDrawAtlasBatch.h"
     22 #include "batches/GrDrawVerticesBatch.h"
     23 #include "batches/GrRectBatchFactory.h"
     24 #include "batches/GrNinePatch.h" // TODO Factory
     25 
     26 #include "text/GrAtlasTextContext.h"
     27 #include "text/GrStencilAndCoverTextContext.h"
     28 
     29 #include "../private/GrAuditTrail.h"
     30 
     31 #define ASSERT_OWNED_RESOURCE(R) SkASSERT(!(R) || (R)->getContext() == fDrawingManager->getContext())
     32 #define ASSERT_SINGLE_OWNER \
     33     SkDEBUGCODE(GrSingleOwner::AutoEnforce debug_SingleOwner(fSingleOwner);)
     34 #define RETURN_IF_ABANDONED        if (fDrawingManager->abandoned()) { return; }
     35 #define RETURN_FALSE_IF_ABANDONED  if (fDrawingManager->abandoned()) { return false; }
     36 #define RETURN_NULL_IF_ABANDONED   if (fDrawingManager->abandoned()) { return nullptr; }
     37 
     38 class AutoCheckFlush {
     39 public:
     40     AutoCheckFlush(GrDrawingManager* drawingManager) : fDrawingManager(drawingManager) {
     41         SkASSERT(fDrawingManager);
     42     }
     43     ~AutoCheckFlush() { fDrawingManager->getContext()->flushIfNecessary(); }
     44 
     45 private:
     46     GrDrawingManager* fDrawingManager;
     47 };
     48 
     49 // In MDB mode the reffing of the 'getLastDrawTarget' call's result allows in-progress
     50 // drawTargets to be picked up and added to by drawContexts lower in the call
     51 // stack. When this occurs with a closed drawTarget, a new one will be allocated
     52 // when the drawContext attempts to use it (via getDrawTarget).
     53 GrDrawContext::GrDrawContext(GrContext* context,
     54                              GrDrawingManager* drawingMgr,
     55                              GrRenderTarget* rt,
     56                              const SkSurfaceProps* surfaceProps,
     57                              GrAuditTrail* auditTrail,
     58                              GrSingleOwner* singleOwner)
     59     : fDrawingManager(drawingMgr)
     60     , fRenderTarget(rt)
     61     , fDrawTarget(SkSafeRef(rt->getLastDrawTarget()))
     62     , fContext(context)
     63     , fSurfaceProps(SkSurfacePropsCopyOrDefault(surfaceProps))
     64     , fAuditTrail(auditTrail)
     65 #ifdef SK_DEBUG
     66     , fSingleOwner(singleOwner)
     67 #endif
     68 {
     69     SkDEBUGCODE(this->validate();)
     70 }
     71 
     72 #ifdef SK_DEBUG
     73 void GrDrawContext::validate() const {
     74     SkASSERT(fRenderTarget);
     75     ASSERT_OWNED_RESOURCE(fRenderTarget);
     76 
     77     if (fDrawTarget && !fDrawTarget->isClosed()) {
     78         SkASSERT(fRenderTarget->getLastDrawTarget() == fDrawTarget);
     79     }
     80 }
     81 #endif
     82 
     83 GrDrawContext::~GrDrawContext() {
     84     ASSERT_SINGLE_OWNER
     85     SkSafeUnref(fDrawTarget);
     86 }
     87 
     88 GrDrawTarget* GrDrawContext::getDrawTarget() {
     89     ASSERT_SINGLE_OWNER
     90     SkDEBUGCODE(this->validate();)
     91 
     92     if (!fDrawTarget || fDrawTarget->isClosed()) {
     93         fDrawTarget = fDrawingManager->newDrawTarget(fRenderTarget);
     94     }
     95 
     96     return fDrawTarget;
     97 }
     98 
     99 bool GrDrawContext::copySurface(GrSurface* src, const SkIRect& srcRect, const SkIPoint& dstPoint) {
    100     ASSERT_SINGLE_OWNER
    101     RETURN_FALSE_IF_ABANDONED
    102     SkDEBUGCODE(this->validate();)
    103     GR_AUDIT_TRAIL_AUTO_FRAME(fAuditTrail, "GrDrawContext::copySurface");
    104 
    105     return this->getDrawTarget()->copySurface(fRenderTarget, src, srcRect, dstPoint);
    106 }
    107 
    108 void GrDrawContext::drawText(const GrClip& clip, const GrPaint& grPaint,
    109                              const SkPaint& skPaint,
    110                              const SkMatrix& viewMatrix,
    111                              const char text[], size_t byteLength,
    112                              SkScalar x, SkScalar y, const SkIRect& clipBounds) {
    113     ASSERT_SINGLE_OWNER
    114     RETURN_IF_ABANDONED
    115     SkDEBUGCODE(this->validate();)
    116     GR_AUDIT_TRAIL_AUTO_FRAME(fAuditTrail, "GrDrawContext::drawText");
    117 
    118     if (!fAtlasTextContext) {
    119         fAtlasTextContext.reset(GrAtlasTextContext::Create());
    120     }
    121 
    122     fAtlasTextContext->drawText(fContext, this, clip, grPaint, skPaint, viewMatrix, fSurfaceProps,
    123                                 text, byteLength, x, y, clipBounds);
    124 }
    125 
    126 void GrDrawContext::drawPosText(const GrClip& clip, const GrPaint& grPaint,
    127                                 const SkPaint& skPaint,
    128                                 const SkMatrix& viewMatrix,
    129                                 const char text[], size_t byteLength,
    130                                 const SkScalar pos[], int scalarsPerPosition,
    131                                 const SkPoint& offset, const SkIRect& clipBounds) {
    132     ASSERT_SINGLE_OWNER
    133     RETURN_IF_ABANDONED
    134     SkDEBUGCODE(this->validate();)
    135     GR_AUDIT_TRAIL_AUTO_FRAME(fAuditTrail, "GrDrawContext::drawPosText");
    136 
    137     if (!fAtlasTextContext) {
    138         fAtlasTextContext.reset(GrAtlasTextContext::Create());
    139     }
    140 
    141     fAtlasTextContext->drawPosText(fContext, this, clip, grPaint, skPaint, viewMatrix,
    142                                    fSurfaceProps, text, byteLength, pos, scalarsPerPosition,
    143                                    offset, clipBounds);
    144 
    145 }
    146 
    147 void GrDrawContext::drawTextBlob(const GrClip& clip, const SkPaint& skPaint,
    148                                  const SkMatrix& viewMatrix, const SkTextBlob* blob,
    149                                  SkScalar x, SkScalar y,
    150                                  SkDrawFilter* filter, const SkIRect& clipBounds) {
    151     ASSERT_SINGLE_OWNER
    152     RETURN_IF_ABANDONED
    153     SkDEBUGCODE(this->validate();)
    154     GR_AUDIT_TRAIL_AUTO_FRAME(fAuditTrail, "GrDrawContext::drawTextBlob");
    155 
    156     if (!fAtlasTextContext) {
    157         fAtlasTextContext.reset(GrAtlasTextContext::Create());
    158     }
    159 
    160     fAtlasTextContext->drawTextBlob(fContext, this, clip, skPaint, viewMatrix, fSurfaceProps, blob,
    161                                     x, y, filter, clipBounds);
    162 }
    163 
    164 void GrDrawContext::discard() {
    165     ASSERT_SINGLE_OWNER
    166     RETURN_IF_ABANDONED
    167     SkDEBUGCODE(this->validate();)
    168     GR_AUDIT_TRAIL_AUTO_FRAME(fAuditTrail, "GrDrawContext::discard");
    169 
    170     AutoCheckFlush acf(fDrawingManager);
    171     this->getDrawTarget()->discard(fRenderTarget);
    172 }
    173 
    174 void GrDrawContext::clear(const SkIRect* rect,
    175                           const GrColor color,
    176                           bool canIgnoreRect) {
    177     ASSERT_SINGLE_OWNER
    178     RETURN_IF_ABANDONED
    179     SkDEBUGCODE(this->validate();)
    180     GR_AUDIT_TRAIL_AUTO_FRAME(fAuditTrail, "GrDrawContext::clear");
    181 
    182     AutoCheckFlush acf(fDrawingManager);
    183     this->getDrawTarget()->clear(rect, color, canIgnoreRect, fRenderTarget);
    184 }
    185 
    186 
    187 void GrDrawContext::drawPaint(const GrClip& clip,
    188                               const GrPaint& origPaint,
    189                               const SkMatrix& viewMatrix) {
    190     ASSERT_SINGLE_OWNER
    191     RETURN_IF_ABANDONED
    192     SkDEBUGCODE(this->validate();)
    193     GR_AUDIT_TRAIL_AUTO_FRAME(fAuditTrail, "GrDrawContext::drawPaint");
    194 
    195     // set rect to be big enough to fill the space, but not super-huge, so we
    196     // don't overflow fixed-point implementations
    197     SkRect r;
    198     r.setLTRB(0, 0,
    199               SkIntToScalar(fRenderTarget->width()),
    200               SkIntToScalar(fRenderTarget->height()));
    201     SkTCopyOnFirstWrite<GrPaint> paint(origPaint);
    202 
    203     // by definition this fills the entire clip, no need for AA
    204     if (paint->isAntiAlias()) {
    205         paint.writable()->setAntiAlias(false);
    206     }
    207 
    208     bool isPerspective = viewMatrix.hasPerspective();
    209 
    210     // We attempt to map r by the inverse matrix and draw that. mapRect will
    211     // map the four corners and bound them with a new rect. This will not
    212     // produce a correct result for some perspective matrices.
    213     if (!isPerspective) {
    214         SkMatrix inverse;
    215         if (!viewMatrix.invert(&inverse)) {
    216             SkDebugf("Could not invert matrix\n");
    217             return;
    218         }
    219         inverse.mapRect(&r);
    220         this->drawRect(clip, *paint, viewMatrix, r);
    221     } else {
    222         SkMatrix localMatrix;
    223         if (!viewMatrix.invert(&localMatrix)) {
    224             SkDebugf("Could not invert matrix\n");
    225             return;
    226         }
    227 
    228         AutoCheckFlush acf(fDrawingManager);
    229 
    230         GrPipelineBuilder pipelineBuilder(*paint, fRenderTarget, clip);
    231         SkAutoTUnref<GrDrawBatch> batch(
    232                 GrRectBatchFactory::CreateNonAAFill(paint->getColor(), SkMatrix::I(), r, nullptr,
    233                                                     &localMatrix));
    234         this->getDrawTarget()->drawBatch(pipelineBuilder, batch);
    235     }
    236 }
    237 
    238 static inline bool rect_contains_inclusive(const SkRect& rect, const SkPoint& point) {
    239     return point.fX >= rect.fLeft && point.fX <= rect.fRight &&
    240            point.fY >= rect.fTop && point.fY <= rect.fBottom;
    241 }
    242 
    243 static bool view_matrix_ok_for_aa_fill_rect(const SkMatrix& viewMatrix) {
    244     return viewMatrix.preservesRightAngles();
    245 }
    246 
    247 static bool should_apply_coverage_aa(const GrPaint& paint, GrRenderTarget* rt) {
    248     return paint.isAntiAlias() && !rt->isUnifiedMultisampled();
    249 }
    250 
    251 void GrDrawContext::drawRect(const GrClip& clip,
    252                              const GrPaint& paint,
    253                              const SkMatrix& viewMatrix,
    254                              const SkRect& rect,
    255                              const GrStrokeInfo* strokeInfo) {
    256     ASSERT_SINGLE_OWNER
    257     RETURN_IF_ABANDONED
    258     SkDEBUGCODE(this->validate();)
    259     GR_AUDIT_TRAIL_AUTO_FRAME(fAuditTrail, "GrDrawContext::drawRect");
    260 
    261     // Dashing should've been devolved to a path in SkGpuDevice
    262     SkASSERT(!strokeInfo || !strokeInfo->isDashed());
    263 
    264     AutoCheckFlush acf(fDrawingManager);
    265 
    266     SkScalar width = nullptr == strokeInfo ? -1 : strokeInfo->getWidth();
    267 
    268     // Check if this is a full RT draw and can be replaced with a clear. We don't bother checking
    269     // cases where the RT is fully inside a stroke.
    270     if (width < 0) {
    271         SkRect rtRect;
    272         fRenderTarget->getBoundsRect(&rtRect);
    273         SkRect clipSpaceRTRect = rtRect;
    274         bool checkClip = GrClip::kWideOpen_ClipType != clip.clipType();
    275         if (checkClip) {
    276             clipSpaceRTRect.offset(SkIntToScalar(clip.origin().fX),
    277                                    SkIntToScalar(clip.origin().fY));
    278         }
    279         // Does the clip contain the entire RT?
    280         if (!checkClip || clip.quickContains(clipSpaceRTRect)) {
    281             SkMatrix invM;
    282             if (!viewMatrix.invert(&invM)) {
    283                 return;
    284             }
    285             // Does the rect bound the RT?
    286             SkPoint srcSpaceRTQuad[4];
    287             invM.mapRectToQuad(srcSpaceRTQuad, rtRect);
    288             if (rect_contains_inclusive(rect, srcSpaceRTQuad[0]) &&
    289                 rect_contains_inclusive(rect, srcSpaceRTQuad[1]) &&
    290                 rect_contains_inclusive(rect, srcSpaceRTQuad[2]) &&
    291                 rect_contains_inclusive(rect, srcSpaceRTQuad[3])) {
    292                 // Will it blend?
    293                 GrColor clearColor;
    294                 if (paint.isConstantBlendedColor(&clearColor)) {
    295                     this->getDrawTarget()->clear(nullptr, clearColor, true, fRenderTarget);
    296                     return;
    297                 }
    298             }
    299         }
    300     }
    301 
    302     GrPipelineBuilder pipelineBuilder(paint, fRenderTarget, clip);
    303     GrColor color = paint.getColor();
    304 
    305     SkAutoTUnref<GrDrawBatch> batch;
    306     if (should_apply_coverage_aa(paint, fRenderTarget)) {
    307         if (width >= 0) {
    308             // The stroke path needs the rect to remain axis aligned (no rotation or skew).
    309             if (viewMatrix.rectStaysRect()) {
    310                 batch.reset(GrRectBatchFactory::CreateAAStroke(color, viewMatrix, rect,
    311                                                                *strokeInfo));
    312             }
    313         } else {
    314             // The fill path can handle rotation but not skew.
    315             if (view_matrix_ok_for_aa_fill_rect(viewMatrix)) {
    316                 SkRect devBoundRect;
    317                 viewMatrix.mapRect(&devBoundRect, rect);
    318                 batch.reset(GrRectBatchFactory::CreateAAFill(color, viewMatrix, rect,
    319                                                              devBoundRect));
    320             }
    321         }
    322         if (!batch) {
    323             SkPath path;
    324             path.setIsVolatile(true);
    325             path.addRect(rect);
    326             this->internalDrawPath(&pipelineBuilder, viewMatrix, color, true, path, *strokeInfo);
    327             SkASSERT(paint.isAntiAlias());
    328             return;
    329         }
    330     } else if (width >= 0) {
    331         // Non-AA hairlines are snapped to pixel centers to make which pixels are hit deterministic
    332         bool snapToPixelCenters = (0 == width && !fRenderTarget->isUnifiedMultisampled());
    333         batch.reset(GrRectBatchFactory::CreateNonAAStroke(color, viewMatrix, rect, width,
    334                                                           snapToPixelCenters));
    335 
    336         // Depending on sub-pixel coordinates and the particular GPU, we may lose a corner of
    337         // hairline rects. We jam all the vertices to pixel centers to avoid this, but not when MSAA
    338         // is enabled because it can cause ugly artifacts.
    339         pipelineBuilder.setState(GrPipelineBuilder::kSnapVerticesToPixelCenters_Flag,
    340                                  snapToPixelCenters);
    341     } else {
    342         // filled BW rect
    343         batch.reset(GrRectBatchFactory::CreateNonAAFill(color, viewMatrix, rect, nullptr, nullptr));
    344     }
    345     this->getDrawTarget()->drawBatch(pipelineBuilder, batch);
    346 }
    347 
    348 void GrDrawContext::fillRectToRect(const GrClip& clip,
    349                                    const GrPaint& paint,
    350                                    const SkMatrix& viewMatrix,
    351                                    const SkRect& rectToDraw,
    352                                    const SkRect& localRect) {
    353     ASSERT_SINGLE_OWNER
    354     RETURN_IF_ABANDONED
    355     SkDEBUGCODE(this->validate();)
    356     GR_AUDIT_TRAIL_AUTO_FRAME(fAuditTrail, "GrDrawContext::fillRectToRect");
    357 
    358     AutoCheckFlush acf(fDrawingManager);
    359 
    360     GrPipelineBuilder pipelineBuilder(paint, fRenderTarget, clip);
    361     SkAutoTUnref<GrDrawBatch> batch;
    362     if (should_apply_coverage_aa(paint, fRenderTarget) &&
    363         view_matrix_ok_for_aa_fill_rect(viewMatrix)) {
    364         batch.reset(GrAAFillRectBatch::CreateWithLocalRect(paint.getColor(), viewMatrix, rectToDraw,
    365                                                            localRect));
    366     } else {
    367         batch.reset(GrRectBatchFactory::CreateNonAAFill(paint.getColor(), viewMatrix, rectToDraw,
    368                                                         &localRect, nullptr));
    369     }
    370 
    371     if (batch) {
    372         this->drawBatch(&pipelineBuilder, batch);
    373     }
    374 }
    375 
    376 void GrDrawContext::fillRectWithLocalMatrix(const GrClip& clip,
    377                                             const GrPaint& paint,
    378                                             const SkMatrix& viewMatrix,
    379                                             const SkRect& rectToDraw,
    380                                             const SkMatrix& localMatrix) {
    381     ASSERT_SINGLE_OWNER
    382     RETURN_IF_ABANDONED
    383     SkDEBUGCODE(this->validate();)
    384     GR_AUDIT_TRAIL_AUTO_FRAME(fAuditTrail, "GrDrawContext::fillRectWithLocalMatrix");
    385 
    386     AutoCheckFlush acf(fDrawingManager);
    387 
    388     GrPipelineBuilder pipelineBuilder(paint, fRenderTarget, clip);
    389 
    390     SkAutoTUnref<GrDrawBatch> batch;
    391     if (should_apply_coverage_aa(paint, fRenderTarget) &&
    392         view_matrix_ok_for_aa_fill_rect(viewMatrix)) {
    393         batch.reset(GrAAFillRectBatch::Create(paint.getColor(), viewMatrix, localMatrix,
    394                                               rectToDraw));
    395     } else {
    396         batch.reset(GrRectBatchFactory::CreateNonAAFill(paint.getColor(), viewMatrix, rectToDraw,
    397                                                         nullptr, &localMatrix));
    398     }
    399     this->getDrawTarget()->drawBatch(pipelineBuilder, batch);
    400 }
    401 
    402 void GrDrawContext::drawVertices(const GrClip& clip,
    403                                  const GrPaint& paint,
    404                                  const SkMatrix& viewMatrix,
    405                                  GrPrimitiveType primitiveType,
    406                                  int vertexCount,
    407                                  const SkPoint positions[],
    408                                  const SkPoint texCoords[],
    409                                  const GrColor colors[],
    410                                  const uint16_t indices[],
    411                                  int indexCount) {
    412     ASSERT_SINGLE_OWNER
    413     RETURN_IF_ABANDONED
    414     SkDEBUGCODE(this->validate();)
    415     GR_AUDIT_TRAIL_AUTO_FRAME(fAuditTrail, "GrDrawContext::drawVertices");
    416 
    417     AutoCheckFlush acf(fDrawingManager);
    418 
    419     GrPipelineBuilder pipelineBuilder(paint, fRenderTarget, clip);
    420 
    421     // TODO clients should give us bounds
    422     SkRect bounds;
    423     if (!bounds.setBoundsCheck(positions, vertexCount)) {
    424         SkDebugf("drawVertices call empty bounds\n");
    425         return;
    426     }
    427 
    428     viewMatrix.mapRect(&bounds);
    429 
    430     // If we don't have AA then we outset for a half pixel in each direction to account for
    431     // snapping. We also do this for the "hair" primitive types: lines and points since they have
    432     // a 1 pixel thickness in device space.
    433     if (!paint.isAntiAlias() || GrIsPrimTypeLines(primitiveType) ||
    434         kPoints_GrPrimitiveType == primitiveType) {
    435         bounds.outset(0.5f, 0.5f);
    436     }
    437 
    438     GrDrawVerticesBatch::Geometry geometry;
    439     geometry.fColor = paint.getColor();
    440     SkAutoTUnref<GrDrawBatch> batch(GrDrawVerticesBatch::Create(geometry, primitiveType, viewMatrix,
    441                                                                 positions, vertexCount, indices,
    442                                                                 indexCount, colors, texCoords,
    443                                                                 bounds));
    444 
    445     this->getDrawTarget()->drawBatch(pipelineBuilder, batch);
    446 }
    447 
    448 ///////////////////////////////////////////////////////////////////////////////
    449 
    450 void GrDrawContext::drawAtlas(const GrClip& clip,
    451                               const GrPaint& paint,
    452                               const SkMatrix& viewMatrix,
    453                               int spriteCount,
    454                               const SkRSXform xform[],
    455                               const SkRect texRect[],
    456                               const SkColor colors[]) {
    457     ASSERT_SINGLE_OWNER
    458     RETURN_IF_ABANDONED
    459     SkDEBUGCODE(this->validate();)
    460     GR_AUDIT_TRAIL_AUTO_FRAME(fAuditTrail, "GrDrawContext::drawAtlas");
    461 
    462     AutoCheckFlush acf(fDrawingManager);
    463 
    464     GrPipelineBuilder pipelineBuilder(paint, fRenderTarget, clip);
    465 
    466     GrDrawAtlasBatch::Geometry geometry;
    467     geometry.fColor = paint.getColor();
    468     SkAutoTUnref<GrDrawBatch> batch(GrDrawAtlasBatch::Create(geometry, viewMatrix, spriteCount,
    469                                                              xform, texRect, colors));
    470 
    471     this->getDrawTarget()->drawBatch(pipelineBuilder, batch);
    472 }
    473 
    474 ///////////////////////////////////////////////////////////////////////////////
    475 
    476 void GrDrawContext::drawRRect(const GrClip& clip,
    477                               const GrPaint& paint,
    478                               const SkMatrix& viewMatrix,
    479                               const SkRRect& rrect,
    480                               const GrStrokeInfo& strokeInfo) {
    481     ASSERT_SINGLE_OWNER
    482     RETURN_IF_ABANDONED
    483     SkDEBUGCODE(this->validate();)
    484     GR_AUDIT_TRAIL_AUTO_FRAME(fAuditTrail, "GrDrawContext::drawRRect");
    485 
    486     if (rrect.isEmpty()) {
    487        return;
    488     }
    489 
    490     SkASSERT(!strokeInfo.isDashed()); // this should've been devolved to a path in SkGpuDevice
    491 
    492     AutoCheckFlush acf(fDrawingManager);
    493 
    494     GrPipelineBuilder pipelineBuilder(paint, fRenderTarget, clip);
    495     GrColor color = paint.getColor();
    496 
    497     if (should_apply_coverage_aa(paint, fRenderTarget)) {
    498         GrShaderCaps* shaderCaps = fContext->caps()->shaderCaps();
    499 
    500         SkAutoTUnref<GrDrawBatch> batch(GrOvalRenderer::CreateRRectBatch(color,
    501                                                                          viewMatrix,
    502                                                                          rrect,
    503                                                                          strokeInfo,
    504                                                                          shaderCaps));
    505         if (batch) {
    506             this->getDrawTarget()->drawBatch(pipelineBuilder, batch);
    507             return;
    508         }
    509     }
    510 
    511     SkPath path;
    512     path.setIsVolatile(true);
    513     path.addRRect(rrect);
    514     this->internalDrawPath(&pipelineBuilder, viewMatrix, color,
    515                            paint.isAntiAlias(), path, strokeInfo);
    516 }
    517 
    518 ///////////////////////////////////////////////////////////////////////////////
    519 
    520 void GrDrawContext::drawOval(const GrClip& clip,
    521                              const GrPaint& paint,
    522                              const SkMatrix& viewMatrix,
    523                              const SkRect& oval,
    524                              const GrStrokeInfo& strokeInfo) {
    525     ASSERT_SINGLE_OWNER
    526     RETURN_IF_ABANDONED
    527     SkDEBUGCODE(this->validate();)
    528     GR_AUDIT_TRAIL_AUTO_FRAME(fAuditTrail, "GrDrawContext::drawOval");
    529 
    530     if (oval.isEmpty()) {
    531        return;
    532     }
    533 
    534     SkASSERT(!strokeInfo.isDashed()); // this should've been devolved to a path in SkGpuDevice
    535 
    536     AutoCheckFlush acf(fDrawingManager);
    537 
    538     GrPipelineBuilder pipelineBuilder(paint, fRenderTarget, clip);
    539     GrColor color = paint.getColor();
    540 
    541     if (should_apply_coverage_aa(paint, fRenderTarget)) {
    542         GrShaderCaps* shaderCaps = fContext->caps()->shaderCaps();
    543         SkAutoTUnref<GrDrawBatch> batch(GrOvalRenderer::CreateOvalBatch(color,
    544                                                                         viewMatrix,
    545                                                                         oval,
    546                                                                         strokeInfo,
    547                                                                         shaderCaps));
    548         if (batch) {
    549             this->getDrawTarget()->drawBatch(pipelineBuilder, batch);
    550             return;
    551         }
    552     }
    553 
    554     SkPath path;
    555     path.setIsVolatile(true);
    556     path.addOval(oval);
    557     this->internalDrawPath(&pipelineBuilder, viewMatrix, color,
    558                            paint.isAntiAlias(), path, strokeInfo);
    559 }
    560 
    561 void GrDrawContext::drawImageNine(const GrClip& clip,
    562                                   const GrPaint& paint,
    563                                   const SkMatrix& viewMatrix,
    564                                   int imageWidth,
    565                                   int imageHeight,
    566                                   const SkIRect& center,
    567                                   const SkRect& dst) {
    568     ASSERT_SINGLE_OWNER
    569     RETURN_IF_ABANDONED
    570     SkDEBUGCODE(this->validate();)
    571     GR_AUDIT_TRAIL_AUTO_FRAME(fAuditTrail, "GrDrawContext::drawImageNine");
    572 
    573     AutoCheckFlush acf(fDrawingManager);
    574 
    575     SkAutoTUnref<GrDrawBatch> batch(GrNinePatch::CreateNonAA(paint.getColor(), viewMatrix,
    576                                                              imageWidth, imageHeight,
    577                                                              center, dst));
    578 
    579     GrPipelineBuilder pipelineBuilder(paint, fRenderTarget, clip);
    580     this->getDrawTarget()->drawBatch(pipelineBuilder, batch);
    581 }
    582 
    583 
    584 // Can 'path' be drawn as a pair of filled nested rectangles?
    585 static bool is_nested_rects(const SkMatrix& viewMatrix,
    586                             const SkPath& path,
    587                             const SkStrokeRec& stroke,
    588                             SkRect rects[2]) {
    589     SkASSERT(stroke.isFillStyle());
    590 
    591     if (path.isInverseFillType()) {
    592         return false;
    593     }
    594 
    595     // TODO: this restriction could be lifted if we were willing to apply
    596     // the matrix to all the points individually rather than just to the rect
    597     if (!viewMatrix.rectStaysRect()) {
    598         return false;
    599     }
    600 
    601     SkPath::Direction dirs[2];
    602     if (!path.isNestedFillRects(rects, dirs)) {
    603         return false;
    604     }
    605 
    606     if (SkPath::kWinding_FillType == path.getFillType() && dirs[0] == dirs[1]) {
    607         // The two rects need to be wound opposite to each other
    608         return false;
    609     }
    610 
    611     // Right now, nested rects where the margin is not the same width
    612     // all around do not render correctly
    613     const SkScalar* outer = rects[0].asScalars();
    614     const SkScalar* inner = rects[1].asScalars();
    615 
    616     bool allEq = true;
    617 
    618     SkScalar margin = SkScalarAbs(outer[0] - inner[0]);
    619     bool allGoE1 = margin >= SK_Scalar1;
    620 
    621     for (int i = 1; i < 4; ++i) {
    622         SkScalar temp = SkScalarAbs(outer[i] - inner[i]);
    623         if (temp < SK_Scalar1) {
    624             allGoE1 = false;
    625         }
    626         if (!SkScalarNearlyEqual(margin, temp)) {
    627             allEq = false;
    628         }
    629     }
    630 
    631     return allEq || allGoE1;
    632 }
    633 
    634 void GrDrawContext::drawBatch(const GrClip& clip,
    635                               const GrPaint& paint, GrDrawBatch* batch) {
    636     ASSERT_SINGLE_OWNER
    637     RETURN_IF_ABANDONED
    638     SkDEBUGCODE(this->validate();)
    639     GR_AUDIT_TRAIL_AUTO_FRAME(fAuditTrail, "GrDrawContext::drawBatch");
    640 
    641     AutoCheckFlush acf(fDrawingManager);
    642 
    643     GrPipelineBuilder pipelineBuilder(paint, fRenderTarget, clip);
    644     this->getDrawTarget()->drawBatch(pipelineBuilder, batch);
    645 }
    646 
    647 void GrDrawContext::drawPathBatch(const GrPipelineBuilder& pipelineBuilder,
    648                                   GrDrawPathBatchBase* batch) {
    649     ASSERT_SINGLE_OWNER
    650     RETURN_IF_ABANDONED
    651     SkDEBUGCODE(this->validate();)
    652     GR_AUDIT_TRAIL_AUTO_FRAME(fAuditTrail, "GrDrawContext::drawPathBatch");
    653 
    654     AutoCheckFlush acf(fDrawingManager);
    655 
    656     this->getDrawTarget()->drawPathBatch(pipelineBuilder, batch);
    657 }
    658 
    659 void GrDrawContext::drawPath(const GrClip& clip,
    660                              const GrPaint& paint,
    661                              const SkMatrix& viewMatrix,
    662                              const SkPath& path,
    663                              const GrStrokeInfo& strokeInfo) {
    664     ASSERT_SINGLE_OWNER
    665     RETURN_IF_ABANDONED
    666     SkDEBUGCODE(this->validate();)
    667     GR_AUDIT_TRAIL_AUTO_FRAME(fAuditTrail, "GrDrawContext::drawPath");
    668 
    669     if (path.isEmpty()) {
    670        if (path.isInverseFillType()) {
    671            this->drawPaint(clip, paint, viewMatrix);
    672        }
    673        return;
    674     }
    675 
    676     GrColor color = paint.getColor();
    677 
    678     // Note that internalDrawPath may sw-rasterize the path into a scratch texture.
    679     // Scratch textures can be recycled after they are returned to the texture
    680     // cache. This presents a potential hazard for buffered drawing. However,
    681     // the writePixels that uploads to the scratch will perform a flush so we're
    682     // OK.
    683     AutoCheckFlush acf(fDrawingManager);
    684 
    685     GrPipelineBuilder pipelineBuilder(paint, fRenderTarget, clip);
    686     if (should_apply_coverage_aa(paint, fRenderTarget) && !strokeInfo.isDashed()) {
    687         if (strokeInfo.getWidth() < 0 && !path.isConvex()) {
    688             // Concave AA paths are expensive - try to avoid them for special cases
    689             SkRect rects[2];
    690 
    691             if (is_nested_rects(viewMatrix, path, strokeInfo, rects)) {
    692                 SkAutoTUnref<GrDrawBatch> batch(GrRectBatchFactory::CreateAAFillNestedRects(
    693                     color, viewMatrix, rects));
    694                 this->getDrawTarget()->drawBatch(pipelineBuilder, batch);
    695                 return;
    696             }
    697         }
    698         SkRect ovalRect;
    699         bool isOval = path.isOval(&ovalRect);
    700 
    701         if (isOval && !path.isInverseFillType()) {
    702             GrShaderCaps* shaderCaps = fContext->caps()->shaderCaps();
    703             SkAutoTUnref<GrDrawBatch> batch(GrOvalRenderer::CreateOvalBatch(color,
    704                                                                             viewMatrix,
    705                                                                             ovalRect,
    706                                                                             strokeInfo,
    707                                                                             shaderCaps));
    708             if (batch) {
    709                 this->getDrawTarget()->drawBatch(pipelineBuilder, batch);
    710                 return;
    711             }
    712         }
    713     }
    714     this->internalDrawPath(&pipelineBuilder, viewMatrix, color,
    715                            paint.isAntiAlias(), path, strokeInfo);
    716 }
    717 
    718 void GrDrawContext::internalDrawPath(GrPipelineBuilder* pipelineBuilder,
    719                                      const SkMatrix& viewMatrix,
    720                                      GrColor color,
    721                                      bool useAA,
    722                                      const SkPath& path,
    723                                      const GrStrokeInfo& strokeInfo) {
    724     ASSERT_SINGLE_OWNER
    725     RETURN_IF_ABANDONED
    726     SkASSERT(!path.isEmpty());
    727 
    728     // An Assumption here is that path renderer would use some form of tweaking
    729     // the src color (either the input alpha or in the frag shader) to implement
    730     // aa. If we have some future driver-mojo path AA that can do the right
    731     // thing WRT to the blend then we'll need some query on the PR.
    732     bool useCoverageAA = useAA &&
    733         !pipelineBuilder->getRenderTarget()->isUnifiedMultisampled();
    734     bool isStencilDisabled = pipelineBuilder->getStencil().isDisabled();
    735     bool isStencilBufferMSAA = pipelineBuilder->getRenderTarget()->isStencilBufferMultisampled();
    736 
    737     const GrPathRendererChain::DrawType type =
    738         useCoverageAA ? GrPathRendererChain::kColorAntiAlias_DrawType
    739                       : GrPathRendererChain::kColor_DrawType;
    740 
    741     const SkPath* pathPtr = &path;
    742     SkTLazy<SkPath> tmpPath;
    743     const GrStrokeInfo* strokeInfoPtr = &strokeInfo;
    744 
    745     GrPathRenderer::CanDrawPathArgs canDrawArgs;
    746     canDrawArgs.fShaderCaps = fDrawingManager->getContext()->caps()->shaderCaps();
    747     canDrawArgs.fViewMatrix = &viewMatrix;
    748     canDrawArgs.fPath = pathPtr;
    749     canDrawArgs.fStroke = strokeInfoPtr;
    750     canDrawArgs.fAntiAlias = useCoverageAA;
    751     canDrawArgs.fIsStencilDisabled = isStencilDisabled;
    752     canDrawArgs.fIsStencilBufferMSAA = isStencilBufferMSAA;
    753 
    754     // Try a 1st time without stroking the path and without allowing the SW renderer
    755     GrPathRenderer* pr = fDrawingManager->getPathRenderer(canDrawArgs, false, type);
    756 
    757     GrStrokeInfo dashlessStrokeInfo(strokeInfo, false);
    758     if (nullptr == pr && strokeInfo.isDashed()) {
    759         // It didn't work above, so try again with dashed stroke converted to a dashless stroke.
    760         if (!strokeInfo.applyDashToPath(tmpPath.init(), &dashlessStrokeInfo, *pathPtr)) {
    761             return;
    762         }
    763         pathPtr = tmpPath.get();
    764         if (pathPtr->isEmpty()) {
    765             return;
    766         }
    767         strokeInfoPtr = &dashlessStrokeInfo;
    768 
    769         canDrawArgs.fPath = pathPtr;
    770         canDrawArgs.fStroke = strokeInfoPtr;
    771 
    772         pr = fDrawingManager->getPathRenderer(canDrawArgs, false, type);
    773     }
    774 
    775     if (nullptr == pr) {
    776         if (!GrPathRenderer::IsStrokeHairlineOrEquivalent(*strokeInfoPtr, viewMatrix, nullptr) &&
    777             !strokeInfoPtr->isFillStyle()) {
    778             // It didn't work above, so try again with stroke converted to a fill.
    779             if (!tmpPath.isValid()) {
    780                 tmpPath.init();
    781             }
    782             dashlessStrokeInfo.setResScale(SkScalarAbs(viewMatrix.getMaxScale()));
    783             if (!dashlessStrokeInfo.applyToPath(tmpPath.get(), *pathPtr)) {
    784                 return;
    785             }
    786             pathPtr = tmpPath.get();
    787             if (pathPtr->isEmpty()) {
    788                 return;
    789             }
    790             dashlessStrokeInfo.setFillStyle();
    791             strokeInfoPtr = &dashlessStrokeInfo;
    792         }
    793 
    794         canDrawArgs.fPath = pathPtr;
    795         canDrawArgs.fStroke = strokeInfoPtr;
    796 
    797         // This time, allow SW renderer
    798         pr = fDrawingManager->getPathRenderer(canDrawArgs, true, type);
    799     }
    800 
    801     if (nullptr == pr) {
    802 #ifdef SK_DEBUG
    803         SkDebugf("Unable to find path renderer compatible with path.\n");
    804 #endif
    805         return;
    806     }
    807 
    808     GrPathRenderer::DrawPathArgs args;
    809     args.fTarget = this->getDrawTarget();
    810     args.fResourceProvider = fDrawingManager->getContext()->resourceProvider();
    811     args.fPipelineBuilder = pipelineBuilder;
    812     args.fColor = color;
    813     args.fViewMatrix = &viewMatrix;
    814     args.fPath = pathPtr;
    815     args.fStroke = strokeInfoPtr;
    816     args.fAntiAlias = useCoverageAA;
    817     pr->drawPath(args);
    818 }
    819 
    820 void GrDrawContext::drawBatch(GrPipelineBuilder* pipelineBuilder, GrDrawBatch* batch) {
    821     ASSERT_SINGLE_OWNER
    822     RETURN_IF_ABANDONED
    823     SkDEBUGCODE(this->validate();)
    824     GR_AUDIT_TRAIL_AUTO_FRAME(fAuditTrail, "GrDrawContext::drawBatch");
    825 
    826     this->getDrawTarget()->drawBatch(*pipelineBuilder, batch);
    827 }
    828