Home | History | Annotate | Download | only in gpu
      1 /*
      2  * Copyright 2011 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 "SkGpuDevice.h"
      9 
     10 #include "GrBitmapTextureMaker.h"
     11 #include "GrBlurUtils.h"
     12 #include "GrContext.h"
     13 #include "GrGpu.h"
     14 #include "GrImageTextureMaker.h"
     15 #include "GrRenderTargetContextPriv.h"
     16 #include "GrStyle.h"
     17 #include "GrSurfaceProxyPriv.h"
     18 #include "GrTextureAdjuster.h"
     19 #include "GrTextureProxy.h"
     20 #include "GrTracing.h"
     21 #include "SkCanvasPriv.h"
     22 #include "SkDraw.h"
     23 #include "SkGlyphCache.h"
     24 #include "SkGr.h"
     25 #include "SkImageFilter.h"
     26 #include "SkImageFilterCache.h"
     27 #include "SkImageInfoPriv.h"
     28 #include "SkImage_Base.h"
     29 #include "SkLatticeIter.h"
     30 #include "SkMaskFilter.h"
     31 #include "SkPathEffect.h"
     32 #include "SkPicture.h"
     33 #include "SkPictureData.h"
     34 #include "SkRRect.h"
     35 #include "SkRasterClip.h"
     36 #include "SkReadPixelsRec.h"
     37 #include "SkRecord.h"
     38 #include "SkSpecialImage.h"
     39 #include "SkStroke.h"
     40 #include "SkSurface.h"
     41 #include "SkSurface_Gpu.h"
     42 #include "SkTLazy.h"
     43 #include "SkUtils.h"
     44 #include "SkVertState.h"
     45 #include "SkVertices.h"
     46 #include "SkWritePixelsRec.h"
     47 #include "effects/GrBicubicEffect.h"
     48 #include "effects/GrSimpleTextureEffect.h"
     49 #include "effects/GrTextureDomain.h"
     50 #include "../private/SkShadowFlags.h"
     51 #include "text/GrTextUtils.h"
     52 
     53 #if SK_SUPPORT_GPU
     54 
     55 #define ASSERT_SINGLE_OWNER \
     56     SkDEBUGCODE(GrSingleOwner::AutoEnforce debug_SingleOwner(fContext->debugSingleOwner());)
     57 
     58 #if 0
     59     extern bool (*gShouldDrawProc)();
     60     #define CHECK_SHOULD_DRAW()                                 \
     61         do {                                                    \
     62             if (gShouldDrawProc && !gShouldDrawProc()) return;  \
     63         } while (0)
     64 #else
     65 #define CHECK_SHOULD_DRAW()
     66 #endif
     67 
     68 ///////////////////////////////////////////////////////////////////////////////
     69 
     70 /** Checks that the alpha type is legal and gets constructor flags. Returns false if device creation
     71     should fail. */
     72 bool SkGpuDevice::CheckAlphaTypeAndGetFlags(
     73                         const SkImageInfo* info, SkGpuDevice::InitContents init, unsigned* flags) {
     74     *flags = 0;
     75     if (info) {
     76         switch (info->alphaType()) {
     77             case kPremul_SkAlphaType:
     78                 break;
     79             case kOpaque_SkAlphaType:
     80                 *flags |= SkGpuDevice::kIsOpaque_Flag;
     81                 break;
     82             default: // If it is unpremul or unknown don't try to render
     83                 return false;
     84         }
     85     }
     86     if (kClear_InitContents == init) {
     87         *flags |= kNeedClear_Flag;
     88     }
     89     return true;
     90 }
     91 
     92 sk_sp<SkGpuDevice> SkGpuDevice::Make(GrContext* context,
     93                                      sk_sp<GrRenderTargetContext> renderTargetContext,
     94                                      int width, int height,
     95                                      InitContents init) {
     96     if (!renderTargetContext || renderTargetContext->wasAbandoned()) {
     97         return nullptr;
     98     }
     99     unsigned flags;
    100     if (!CheckAlphaTypeAndGetFlags(nullptr, init, &flags)) {
    101         return nullptr;
    102     }
    103     return sk_sp<SkGpuDevice>(new SkGpuDevice(context, std::move(renderTargetContext),
    104                                               width, height, flags));
    105 }
    106 
    107 sk_sp<SkGpuDevice> SkGpuDevice::Make(GrContext* context, SkBudgeted budgeted,
    108                                      const SkImageInfo& info, int sampleCount,
    109                                      GrSurfaceOrigin origin,
    110                                      const SkSurfaceProps* props, InitContents init) {
    111     unsigned flags;
    112     if (!CheckAlphaTypeAndGetFlags(&info, init, &flags)) {
    113         return nullptr;
    114     }
    115 
    116     sk_sp<GrRenderTargetContext> renderTargetContext(MakeRenderTargetContext(context, budgeted,
    117                                                                              info, sampleCount,
    118                                                                              origin, props));
    119     if (!renderTargetContext) {
    120         return nullptr;
    121     }
    122 
    123     return sk_sp<SkGpuDevice>(new SkGpuDevice(context, std::move(renderTargetContext),
    124                                               info.width(), info.height(), flags));
    125 }
    126 
    127 static SkImageInfo make_info(GrRenderTargetContext* context, int w, int h, bool opaque) {
    128     SkColorType colorType;
    129     if (!GrPixelConfigToColorType(context->config(), &colorType)) {
    130         colorType = kUnknown_SkColorType;
    131     }
    132     return SkImageInfo::Make(w, h, colorType,
    133                              opaque ? kOpaque_SkAlphaType : kPremul_SkAlphaType,
    134                              context->refColorSpace());
    135 }
    136 
    137 SkGpuDevice::SkGpuDevice(GrContext* context, sk_sp<GrRenderTargetContext> renderTargetContext,
    138                          int width, int height, unsigned flags)
    139     : INHERITED(make_info(renderTargetContext.get(), width, height,
    140                           SkToBool(flags & kIsOpaque_Flag)), renderTargetContext->surfaceProps())
    141     , fContext(SkRef(context))
    142     , fRenderTargetContext(std::move(renderTargetContext))
    143 {
    144     fSize.set(width, height);
    145     fOpaque = SkToBool(flags & kIsOpaque_Flag);
    146 
    147     if (flags & kNeedClear_Flag) {
    148         this->clearAll();
    149     }
    150 }
    151 
    152 sk_sp<GrRenderTargetContext> SkGpuDevice::MakeRenderTargetContext(
    153                                                                GrContext* context,
    154                                                                SkBudgeted budgeted,
    155                                                                const SkImageInfo& origInfo,
    156                                                                int sampleCount,
    157                                                                GrSurfaceOrigin origin,
    158                                                                const SkSurfaceProps* surfaceProps) {
    159     if (kUnknown_SkColorType == origInfo.colorType() ||
    160         origInfo.width() < 0 || origInfo.height() < 0) {
    161         return nullptr;
    162     }
    163 
    164     if (!context) {
    165         return nullptr;
    166     }
    167 
    168     GrPixelConfig config = SkImageInfo2GrPixelConfig(origInfo, *context->caps());
    169     // This method is used to create SkGpuDevice's for SkSurface_Gpus. In this case
    170     // they need to be exact.
    171     return context->makeDeferredRenderTargetContext(
    172                                     SkBackingFit::kExact,
    173                                     origInfo.width(), origInfo.height(),
    174                                     config, origInfo.refColorSpace(), sampleCount,
    175                                     origin, surfaceProps, budgeted);
    176 }
    177 
    178 sk_sp<SkSpecialImage> SkGpuDevice::filterTexture(SkSpecialImage* srcImg,
    179                                                  int left, int top,
    180                                                  SkIPoint* offset,
    181                                                  const SkImageFilter* filter) {
    182     SkASSERT(srcImg->isTextureBacked());
    183     SkASSERT(filter);
    184 
    185     SkMatrix matrix = this->ctm();
    186     matrix.postTranslate(SkIntToScalar(-left), SkIntToScalar(-top));
    187     const SkIRect clipBounds = this->devClipBounds().makeOffset(-left, -top);
    188     sk_sp<SkImageFilterCache> cache(this->getImageFilterCache());
    189     SkImageFilter::OutputProperties outputProperties(fRenderTargetContext->getColorSpace());
    190     SkImageFilter::Context ctx(matrix, clipBounds, cache.get(), outputProperties);
    191 
    192     return filter->filterImage(srcImg, ctx, offset);
    193 }
    194 
    195 ///////////////////////////////////////////////////////////////////////////////
    196 
    197 bool SkGpuDevice::onReadPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRowBytes,
    198                                int x, int y) {
    199     ASSERT_SINGLE_OWNER
    200 
    201     if (!SkImageInfoValidConversion(dstInfo, this->imageInfo())) {
    202         return false;
    203     }
    204 
    205     SkReadPixelsRec rec(dstInfo, dstPixels, dstRowBytes, x, y);
    206     if (!rec.trim(this->width(), this->height())) {
    207         return false;
    208     }
    209 
    210     return fRenderTargetContext->readPixels(rec.fInfo, rec.fPixels, rec.fRowBytes, rec.fX, rec.fY);
    211 }
    212 
    213 bool SkGpuDevice::onWritePixels(const SkImageInfo& srcInfo, const void* srcPixels,
    214                                 size_t srcRowBytes, int x, int y) {
    215     ASSERT_SINGLE_OWNER
    216 
    217     if (!SkImageInfoValidConversion(this->imageInfo(), srcInfo)) {
    218         return false;
    219     }
    220 
    221     SkWritePixelsRec rec(srcInfo, srcPixels, srcRowBytes, x, y);
    222     if (!rec.trim(this->width(), this->height())) {
    223         return false;
    224     }
    225 
    226     return fRenderTargetContext->writePixels(rec.fInfo, rec.fPixels, rec.fRowBytes, rec.fX, rec.fY);
    227 }
    228 
    229 bool SkGpuDevice::onAccessPixels(SkPixmap* pmap) {
    230     ASSERT_SINGLE_OWNER
    231     return false;
    232 }
    233 
    234 GrRenderTargetContext* SkGpuDevice::accessRenderTargetContext() {
    235     ASSERT_SINGLE_OWNER
    236     return fRenderTargetContext.get();
    237 }
    238 
    239 void SkGpuDevice::clearAll() {
    240     ASSERT_SINGLE_OWNER
    241     GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "clearAll", fContext.get());
    242 
    243     SkIRect rect = SkIRect::MakeWH(this->width(), this->height());
    244     fRenderTargetContext->clear(&rect, 0x0, true);
    245 }
    246 
    247 void SkGpuDevice::replaceRenderTargetContext(bool shouldRetainContent) {
    248     ASSERT_SINGLE_OWNER
    249 
    250     SkBudgeted budgeted = fRenderTargetContext->priv().isBudgeted();
    251 
    252     // This entry point is used by SkSurface_Gpu::onCopyOnWrite so it must create a
    253     // kExact-backed render target context.
    254     sk_sp<GrRenderTargetContext> newRTC(MakeRenderTargetContext(
    255                                                             this->context(),
    256                                                             budgeted,
    257                                                             this->imageInfo(),
    258                                                             fRenderTargetContext->numColorSamples(),
    259                                                             fRenderTargetContext->origin(),
    260                                                             &this->surfaceProps()));
    261     if (!newRTC) {
    262         return;
    263     }
    264     SkASSERT(newRTC->asSurfaceProxy()->priv().isExact());
    265 
    266     if (shouldRetainContent) {
    267         if (fRenderTargetContext->wasAbandoned()) {
    268             return;
    269         }
    270         newRTC->copy(fRenderTargetContext->asSurfaceProxy());
    271     }
    272 
    273     fRenderTargetContext = newRTC;
    274 }
    275 
    276 ///////////////////////////////////////////////////////////////////////////////
    277 
    278 void SkGpuDevice::drawPaint(const SkPaint& paint) {
    279     ASSERT_SINGLE_OWNER
    280     CHECK_SHOULD_DRAW();
    281     GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawPaint", fContext.get());
    282 
    283     GrPaint grPaint;
    284     if (!SkPaintToGrPaint(this->context(), fRenderTargetContext.get(), paint, this->ctm(),
    285                           &grPaint)) {
    286         return;
    287     }
    288 
    289     fRenderTargetContext->drawPaint(this->clip(), std::move(grPaint), this->ctm());
    290 }
    291 
    292 // must be in SkCanvas::PointMode order
    293 static const GrPrimitiveType gPointMode2PrimitiveType[] = {
    294     GrPrimitiveType::kPoints,
    295     GrPrimitiveType::kLines,
    296     GrPrimitiveType::kLineStrip
    297 };
    298 
    299 void SkGpuDevice::drawPoints(SkCanvas::PointMode mode,
    300                              size_t count, const SkPoint pts[], const SkPaint& paint) {
    301     ASSERT_SINGLE_OWNER
    302     GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawPoints", fContext.get());
    303     CHECK_SHOULD_DRAW();
    304 
    305     SkScalar width = paint.getStrokeWidth();
    306     if (width < 0) {
    307         return;
    308     }
    309 
    310     if (paint.getPathEffect() && 2 == count && SkCanvas::kLines_PointMode == mode) {
    311         GrStyle style(paint, SkPaint::kStroke_Style);
    312         GrPaint grPaint;
    313         if (!SkPaintToGrPaint(this->context(), fRenderTargetContext.get(), paint, this->ctm(),
    314                               &grPaint)) {
    315             return;
    316         }
    317         SkPath path;
    318         path.setIsVolatile(true);
    319         path.moveTo(pts[0]);
    320         path.lineTo(pts[1]);
    321         fRenderTargetContext->drawPath(this->clip(), std::move(grPaint),
    322                                        GrBoolToAA(paint.isAntiAlias()), this->ctm(), path, style);
    323         return;
    324     }
    325 
    326     SkScalar scales[2];
    327     bool isHairline = (0 == width) || (1 == width && this->ctm().getMinMaxScales(scales) &&
    328                                        SkScalarNearlyEqual(scales[0], 1.f) &&
    329                                        SkScalarNearlyEqual(scales[1], 1.f));
    330     // we only handle non-antialiased hairlines and paints without path effects or mask filters,
    331     // else we let the SkDraw call our drawPath()
    332     if (!isHairline || paint.getPathEffect() || paint.getMaskFilter() || paint.isAntiAlias()) {
    333         SkRasterClip rc(this->devClipBounds());
    334         SkDraw draw;
    335         draw.fDst = SkPixmap(SkImageInfo::MakeUnknown(this->width(), this->height()), nullptr, 0);
    336         draw.fMatrix = &this->ctm();
    337         draw.fRC = &rc;
    338         draw.drawPoints(mode, count, pts, paint, this);
    339         return;
    340     }
    341 
    342     GrPrimitiveType primitiveType = gPointMode2PrimitiveType[mode];
    343 
    344     const SkMatrix* viewMatrix = &this->ctm();
    345 #ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
    346     // This offsetting in device space matches the expectations of the Android framework for non-AA
    347     // points and lines.
    348     SkMatrix tempMatrix;
    349     if (GrIsPrimTypeLines(primitiveType) || GrPrimitiveType::kPoints == primitiveType) {
    350         tempMatrix = *viewMatrix;
    351         static const SkScalar kOffset = 0.063f; // Just greater than 1/16.
    352         tempMatrix.postTranslate(kOffset, kOffset);
    353         viewMatrix = &tempMatrix;
    354     }
    355 #endif
    356 
    357     GrPaint grPaint;
    358     if (!SkPaintToGrPaint(this->context(), fRenderTargetContext.get(), paint, *viewMatrix,
    359                           &grPaint)) {
    360         return;
    361     }
    362 
    363     static constexpr SkVertices::VertexMode kIgnoredMode = SkVertices::kTriangles_VertexMode;
    364     sk_sp<SkVertices> vertices = SkVertices::MakeCopy(kIgnoredMode, SkToS32(count), pts, nullptr,
    365                                                       nullptr);
    366 
    367     fRenderTargetContext->drawVertices(this->clip(), std::move(grPaint), *viewMatrix,
    368                                        std::move(vertices), &primitiveType);
    369 }
    370 
    371 ///////////////////////////////////////////////////////////////////////////////
    372 
    373 void SkGpuDevice::drawRect(const SkRect& rect, const SkPaint& paint) {
    374     ASSERT_SINGLE_OWNER
    375     GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawRect", fContext.get());
    376     CHECK_SHOULD_DRAW();
    377 
    378 
    379     // A couple reasons we might need to call drawPath.
    380     if (paint.getMaskFilter() || paint.getPathEffect()) {
    381         SkPath path;
    382         path.setIsVolatile(true);
    383         path.addRect(rect);
    384         GrBlurUtils::drawPathWithMaskFilter(fContext.get(), fRenderTargetContext.get(),
    385                                             this->clip(), path, paint, this->ctm(), nullptr,
    386                                             this->devClipBounds(), true);
    387         return;
    388     }
    389 
    390     GrPaint grPaint;
    391     if (!SkPaintToGrPaint(this->context(), fRenderTargetContext.get(), paint, this->ctm(),
    392                           &grPaint)) {
    393         return;
    394     }
    395 
    396     GrStyle style(paint);
    397     fRenderTargetContext->drawRect(this->clip(), std::move(grPaint),
    398                                    GrBoolToAA(paint.isAntiAlias()), this->ctm(), rect, &style);
    399 }
    400 
    401 ///////////////////////////////////////////////////////////////////////////////
    402 
    403 void SkGpuDevice::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
    404     ASSERT_SINGLE_OWNER
    405     GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawRRect", fContext.get());
    406     CHECK_SHOULD_DRAW();
    407 
    408     GrPaint grPaint;
    409     if (!SkPaintToGrPaint(this->context(), fRenderTargetContext.get(), paint, this->ctm(),
    410                           &grPaint)) {
    411         return;
    412     }
    413 
    414     SkMaskFilter* mf = paint.getMaskFilter();
    415     if (mf && mf->asFragmentProcessor(nullptr)) {
    416         mf = nullptr; // already handled in SkPaintToGrPaint
    417     }
    418 
    419     GrStyle style(paint);
    420     if (mf) {
    421         // try to hit the fast path for drawing filtered round rects
    422 
    423         SkRRect devRRect;
    424         if (rrect.transform(this->ctm(), &devRRect)) {
    425             if (devRRect.allCornersCircular()) {
    426                 SkRect maskRect;
    427                 if (mf->canFilterMaskGPU(devRRect, this->devClipBounds(),
    428                                          this->ctm(), &maskRect)) {
    429                     SkIRect finalIRect;
    430                     maskRect.roundOut(&finalIRect);
    431 
    432                     // we used to test finalIRect for quickReject, but that seems unlikely
    433                     // given that the original shape was not rejected...
    434 
    435                     if (mf->directFilterRRectMaskGPU(this->context(), fRenderTargetContext.get(),
    436                                                      std::move(grPaint), this->clip(), this->ctm(),
    437                                                      style.strokeRec(), rrect, devRRect)) {
    438                         return;
    439                     }
    440                 }
    441 
    442             }
    443         }
    444     }
    445 
    446     if (mf || style.pathEffect()) {
    447         // The only mask filter the native rrect drawing code could've handle was taken
    448         // care of above.
    449         // A path effect will presumably transform this rrect into something else.
    450         SkPath path;
    451         path.setIsVolatile(true);
    452         path.addRRect(rrect);
    453         GrBlurUtils::drawPathWithMaskFilter(fContext.get(), fRenderTargetContext.get(),
    454                                             this->clip(), path, paint, this->ctm(), nullptr,
    455                                             this->devClipBounds(), true);
    456         return;
    457     }
    458 
    459     SkASSERT(!style.pathEffect());
    460 
    461     fRenderTargetContext->drawRRect(this->clip(), std::move(grPaint),
    462                                     GrBoolToAA(paint.isAntiAlias()), this->ctm(), rrect, style);
    463 }
    464 
    465 
    466 void SkGpuDevice::drawDRRect(const SkRRect& outer,
    467                              const SkRRect& inner, const SkPaint& paint) {
    468     ASSERT_SINGLE_OWNER
    469     GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawDRRect", fContext.get());
    470     CHECK_SHOULD_DRAW();
    471 
    472     if (outer.isEmpty()) {
    473        return;
    474     }
    475 
    476     if (inner.isEmpty()) {
    477         return this->drawRRect(outer, paint);
    478     }
    479 
    480     SkStrokeRec stroke(paint);
    481 
    482     if (stroke.isFillStyle() && !paint.getMaskFilter() && !paint.getPathEffect()) {
    483         GrPaint grPaint;
    484         if (!SkPaintToGrPaint(this->context(), fRenderTargetContext.get(), paint, this->ctm(),
    485                               &grPaint)) {
    486             return;
    487         }
    488 
    489         fRenderTargetContext->drawDRRect(this->clip(), std::move(grPaint),
    490                                          GrBoolToAA(paint.isAntiAlias()), this->ctm(), outer,
    491                                          inner);
    492         return;
    493     }
    494 
    495     SkPath path;
    496     path.setIsVolatile(true);
    497     path.addRRect(outer);
    498     path.addRRect(inner);
    499     path.setFillType(SkPath::kEvenOdd_FillType);
    500 
    501     GrBlurUtils::drawPathWithMaskFilter(fContext.get(), fRenderTargetContext.get(), this->clip(),
    502                                         path, paint, this->ctm(), nullptr, this->devClipBounds(),
    503                                         true);
    504 }
    505 
    506 
    507 /////////////////////////////////////////////////////////////////////////////
    508 
    509 void SkGpuDevice::drawRegion(const SkRegion& region, const SkPaint& paint) {
    510     if (paint.getMaskFilter()) {
    511         SkPath path;
    512         region.getBoundaryPath(&path);
    513         return this->drawPath(path, paint, nullptr, false);
    514     }
    515 
    516     GrPaint grPaint;
    517     if (!SkPaintToGrPaint(this->context(), fRenderTargetContext.get(), paint, this->ctm(),
    518                           &grPaint)) {
    519         return;
    520     }
    521 
    522     fRenderTargetContext->drawRegion(this->clip(), std::move(grPaint),
    523                                      GrBoolToAA(paint.isAntiAlias()), this->ctm(), region,
    524                                      GrStyle(paint));
    525 }
    526 
    527 void SkGpuDevice::drawOval(const SkRect& oval, const SkPaint& paint) {
    528     ASSERT_SINGLE_OWNER
    529     GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawOval", fContext.get());
    530     CHECK_SHOULD_DRAW();
    531 
    532     // Presumably the path effect warps this to something other than an oval
    533     if (paint.getPathEffect()) {
    534         SkPath path;
    535         path.setIsVolatile(true);
    536         path.addOval(oval);
    537         this->drawPath(path, paint, nullptr, true);
    538         return;
    539     }
    540 
    541     if (paint.getMaskFilter()) {
    542         // The RRect path can handle special case blurring
    543         SkRRect rr = SkRRect::MakeOval(oval);
    544         return this->drawRRect(rr, paint);
    545     }
    546 
    547     GrPaint grPaint;
    548     if (!SkPaintToGrPaint(this->context(), fRenderTargetContext.get(), paint, this->ctm(),
    549                           &grPaint)) {
    550         return;
    551     }
    552 
    553     fRenderTargetContext->drawOval(this->clip(), std::move(grPaint),
    554                                    GrBoolToAA(paint.isAntiAlias()), this->ctm(), oval,
    555                                    GrStyle(paint));
    556 }
    557 
    558 void SkGpuDevice::drawArc(const SkRect& oval, SkScalar startAngle,
    559                           SkScalar sweepAngle, bool useCenter, const SkPaint& paint) {
    560     ASSERT_SINGLE_OWNER
    561     GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawArc", fContext.get());
    562     CHECK_SHOULD_DRAW();
    563 
    564     if (paint.getMaskFilter()) {
    565         this->INHERITED::drawArc(oval, startAngle, sweepAngle, useCenter, paint);
    566         return;
    567     }
    568     GrPaint grPaint;
    569     if (!SkPaintToGrPaint(this->context(), fRenderTargetContext.get(), paint, this->ctm(),
    570                           &grPaint)) {
    571         return;
    572     }
    573 
    574     fRenderTargetContext->drawArc(this->clip(), std::move(grPaint), GrBoolToAA(paint.isAntiAlias()),
    575                                   this->ctm(), oval, startAngle, sweepAngle, useCenter,
    576                                   GrStyle(paint));
    577 }
    578 
    579 #include "SkMaskFilter.h"
    580 
    581 ///////////////////////////////////////////////////////////////////////////////
    582 void SkGpuDevice::drawStrokedLine(const SkPoint points[2],
    583                                   const SkPaint& origPaint) {
    584     ASSERT_SINGLE_OWNER
    585     GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawStrokedLine", fContext.get());
    586     CHECK_SHOULD_DRAW();
    587 
    588     // Adding support for round capping would require a
    589     // GrRenderTargetContext::fillRRectWithLocalMatrix entry point
    590     SkASSERT(SkPaint::kRound_Cap != origPaint.getStrokeCap());
    591     SkASSERT(SkPaint::kStroke_Style == origPaint.getStyle());
    592     SkASSERT(!origPaint.getPathEffect());
    593     SkASSERT(!origPaint.getMaskFilter());
    594 
    595     const SkScalar halfWidth = 0.5f * origPaint.getStrokeWidth();
    596     SkASSERT(halfWidth > 0);
    597 
    598     SkVector v = points[1] - points[0];
    599 
    600     SkScalar length = SkPoint::Normalize(&v);
    601     if (!length) {
    602         v.fX = 1.0f;
    603         v.fY = 0.0f;
    604     }
    605 
    606     SkPaint newPaint(origPaint);
    607     newPaint.setStyle(SkPaint::kFill_Style);
    608 
    609     SkScalar xtraLength = 0.0f;
    610     if (SkPaint::kButt_Cap != origPaint.getStrokeCap()) {
    611         xtraLength = halfWidth;
    612     }
    613 
    614     SkPoint mid = points[0] + points[1];
    615     mid.scale(0.5f);
    616 
    617     SkRect rect = SkRect::MakeLTRB(mid.fX-halfWidth, mid.fY - 0.5f*length - xtraLength,
    618                                    mid.fX+halfWidth, mid.fY + 0.5f*length + xtraLength);
    619     SkMatrix m;
    620     m.setSinCos(v.fX, -v.fY, mid.fX, mid.fY);
    621 
    622     SkMatrix local = m;
    623 
    624     m.postConcat(this->ctm());
    625 
    626     GrPaint grPaint;
    627     if (!SkPaintToGrPaint(this->context(), fRenderTargetContext.get(), newPaint, m, &grPaint)) {
    628         return;
    629     }
    630 
    631     fRenderTargetContext->fillRectWithLocalMatrix(
    632             this->clip(), std::move(grPaint), GrBoolToAA(newPaint.isAntiAlias()), m, rect, local);
    633 }
    634 
    635 void SkGpuDevice::drawPath(const SkPath& origSrcPath,
    636                            const SkPaint& paint, const SkMatrix* prePathMatrix,
    637                            bool pathIsMutable) {
    638     ASSERT_SINGLE_OWNER
    639     if (!origSrcPath.isInverseFillType() && !paint.getPathEffect() && !prePathMatrix) {
    640         SkPoint points[2];
    641         if (SkPaint::kStroke_Style == paint.getStyle() && paint.getStrokeWidth() > 0 &&
    642             !paint.getMaskFilter() && SkPaint::kRound_Cap != paint.getStrokeCap() &&
    643             this->ctm().preservesRightAngles() && origSrcPath.isLine(points)) {
    644             // Path-based stroking looks better for thin rects
    645             SkScalar strokeWidth = this->ctm().getMaxScale() * paint.getStrokeWidth();
    646             if (strokeWidth >= 1.0f) {
    647                 // Round capping support is currently disabled b.c. it would require a RRect
    648                 // GrDrawOp that takes a localMatrix.
    649                 this->drawStrokedLine(points, paint);
    650                 return;
    651             }
    652         }
    653         bool isClosed;
    654         SkRect rect;
    655         if (origSrcPath.isRect(&rect, &isClosed) && isClosed) {
    656             this->drawRect(rect, paint);
    657             return;
    658         }
    659         if (origSrcPath.isOval(&rect)) {
    660             this->drawOval(rect, paint);
    661             return;
    662         }
    663         SkRRect rrect;
    664         if (origSrcPath.isRRect(&rrect)) {
    665             this->drawRRect(rrect, paint);
    666             return;
    667         }
    668     }
    669 
    670     CHECK_SHOULD_DRAW();
    671     GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawPath", fContext.get());
    672 
    673     GrBlurUtils::drawPathWithMaskFilter(fContext.get(), fRenderTargetContext.get(), this->clip(),
    674                                         origSrcPath, paint, this->ctm(), prePathMatrix,
    675                                         this->devClipBounds(), pathIsMutable);
    676 }
    677 
    678 static const int kBmpSmallTileSize = 1 << 10;
    679 
    680 static inline int get_tile_count(const SkIRect& srcRect, int tileSize)  {
    681     int tilesX = (srcRect.fRight / tileSize) - (srcRect.fLeft / tileSize) + 1;
    682     int tilesY = (srcRect.fBottom / tileSize) - (srcRect.fTop / tileSize) + 1;
    683     return tilesX * tilesY;
    684 }
    685 
    686 static int determine_tile_size(const SkIRect& src, int maxTileSize) {
    687     if (maxTileSize <= kBmpSmallTileSize) {
    688         return maxTileSize;
    689     }
    690 
    691     size_t maxTileTotalTileSize = get_tile_count(src, maxTileSize);
    692     size_t smallTotalTileSize = get_tile_count(src, kBmpSmallTileSize);
    693 
    694     maxTileTotalTileSize *= maxTileSize * maxTileSize;
    695     smallTotalTileSize *= kBmpSmallTileSize * kBmpSmallTileSize;
    696 
    697     if (maxTileTotalTileSize > 2 * smallTotalTileSize) {
    698         return kBmpSmallTileSize;
    699     } else {
    700         return maxTileSize;
    701     }
    702 }
    703 
    704 // Given a bitmap, an optional src rect, and a context with a clip and matrix determine what
    705 // pixels from the bitmap are necessary.
    706 static void determine_clipped_src_rect(int width, int height,
    707                                        const GrClip& clip,
    708                                        const SkMatrix& viewMatrix,
    709                                        const SkMatrix& srcToDstRect,
    710                                        const SkISize& imageSize,
    711                                        const SkRect* srcRectPtr,
    712                                        SkIRect* clippedSrcIRect) {
    713     clip.getConservativeBounds(width, height, clippedSrcIRect, nullptr);
    714     SkMatrix inv = SkMatrix::Concat(viewMatrix, srcToDstRect);
    715     if (!inv.invert(&inv)) {
    716         clippedSrcIRect->setEmpty();
    717         return;
    718     }
    719     SkRect clippedSrcRect = SkRect::Make(*clippedSrcIRect);
    720     inv.mapRect(&clippedSrcRect);
    721     if (srcRectPtr) {
    722         if (!clippedSrcRect.intersect(*srcRectPtr)) {
    723             clippedSrcIRect->setEmpty();
    724             return;
    725         }
    726     }
    727     clippedSrcRect.roundOut(clippedSrcIRect);
    728     SkIRect bmpBounds = SkIRect::MakeSize(imageSize);
    729     if (!clippedSrcIRect->intersect(bmpBounds)) {
    730         clippedSrcIRect->setEmpty();
    731     }
    732 }
    733 
    734 bool SkGpuDevice::shouldTileImageID(uint32_t imageID, const SkIRect& imageRect,
    735                                     const SkMatrix& viewMatrix,
    736                                     const SkMatrix& srcToDstRect,
    737                                     const GrSamplerParams& params,
    738                                     const SkRect* srcRectPtr,
    739                                     int maxTileSize,
    740                                     int* tileSize,
    741                                     SkIRect* clippedSubset) const {
    742     ASSERT_SINGLE_OWNER
    743     // if it's larger than the max tile size, then we have no choice but tiling.
    744     if (imageRect.width() > maxTileSize || imageRect.height() > maxTileSize) {
    745         determine_clipped_src_rect(fRenderTargetContext->width(), fRenderTargetContext->height(),
    746                                    this->clip(), viewMatrix, srcToDstRect, imageRect.size(),
    747                                    srcRectPtr, clippedSubset);
    748         *tileSize = determine_tile_size(*clippedSubset, maxTileSize);
    749         return true;
    750     }
    751 
    752     // If the image would only produce 4 tiles of the smaller size, don't bother tiling it.
    753     const size_t area = imageRect.width() * imageRect.height();
    754     if (area < 4 * kBmpSmallTileSize * kBmpSmallTileSize) {
    755         return false;
    756     }
    757 
    758     // At this point we know we could do the draw by uploading the entire bitmap
    759     // as a texture. However, if the texture would be large compared to the
    760     // cache size and we don't require most of it for this draw then tile to
    761     // reduce the amount of upload and cache spill.
    762 
    763     // assumption here is that sw bitmap size is a good proxy for its size as
    764     // a texture
    765     size_t bmpSize = area * sizeof(SkPMColor);  // assume 32bit pixels
    766     size_t cacheSize;
    767     fContext->getResourceCacheLimits(nullptr, &cacheSize);
    768     if (bmpSize < cacheSize / 2) {
    769         return false;
    770     }
    771 
    772     // Figure out how much of the src we will need based on the src rect and clipping. Reject if
    773     // tiling memory savings would be < 50%.
    774     determine_clipped_src_rect(fRenderTargetContext->width(), fRenderTargetContext->height(),
    775                                this->clip(), viewMatrix, srcToDstRect, imageRect.size(), srcRectPtr,
    776                                clippedSubset);
    777     *tileSize = kBmpSmallTileSize; // already know whole bitmap fits in one max sized tile.
    778     size_t usedTileBytes = get_tile_count(*clippedSubset, kBmpSmallTileSize) *
    779                            kBmpSmallTileSize * kBmpSmallTileSize *
    780                            sizeof(SkPMColor);  // assume 32bit pixels;
    781 
    782     return usedTileBytes * 2 < bmpSize;
    783 }
    784 
    785 bool SkGpuDevice::shouldTileImage(const SkImage* image, const SkRect* srcRectPtr,
    786                                   SkCanvas::SrcRectConstraint constraint, SkFilterQuality quality,
    787                                   const SkMatrix& viewMatrix,
    788                                   const SkMatrix& srcToDstRect) const {
    789     ASSERT_SINGLE_OWNER
    790     // if image is explictly texture backed then just use the texture
    791     if (image->isTextureBacked()) {
    792         return false;
    793     }
    794 
    795     GrSamplerParams params;
    796     bool doBicubic;
    797     GrSamplerParams::FilterMode textureFilterMode =
    798                     GrSkFilterQualityToGrFilterMode(quality, viewMatrix, srcToDstRect, &doBicubic);
    799 
    800     int tileFilterPad;
    801     if (doBicubic) {
    802         tileFilterPad = GrBicubicEffect::kFilterTexelPad;
    803     } else if (GrSamplerParams::kNone_FilterMode == textureFilterMode) {
    804         tileFilterPad = 0;
    805     } else {
    806         tileFilterPad = 1;
    807     }
    808     params.setFilterMode(textureFilterMode);
    809 
    810     int maxTileSize = fContext->caps()->maxTileSize() - 2 * tileFilterPad;
    811 
    812     // these are output, which we safely ignore, as we just want to know the predicate
    813     int outTileSize;
    814     SkIRect outClippedSrcRect;
    815 
    816     return this->shouldTileImageID(image->unique(), image->bounds(), viewMatrix, srcToDstRect,
    817                                    params, srcRectPtr, maxTileSize, &outTileSize,
    818                                    &outClippedSrcRect);
    819 }
    820 
    821 void SkGpuDevice::drawBitmap(const SkBitmap& bitmap,
    822                              SkScalar x,
    823                              SkScalar y,
    824                              const SkPaint& paint) {
    825     SkMatrix m = SkMatrix::MakeTrans(x, y);
    826     ASSERT_SINGLE_OWNER
    827     CHECK_SHOULD_DRAW();
    828     SkMatrix viewMatrix;
    829     viewMatrix.setConcat(this->ctm(), m);
    830 
    831     int maxTileSize = fContext->caps()->maxTileSize();
    832 
    833     // The tile code path doesn't currently support AA, so if the paint asked for aa and we could
    834     // draw untiled, then we bypass checking for tiling purely for optimization reasons.
    835     bool drawAA = GrFSAAType::kUnifiedMSAA != fRenderTargetContext->fsaaType() &&
    836                   paint.isAntiAlias() && bitmap.width() <= maxTileSize &&
    837                   bitmap.height() <= maxTileSize;
    838 
    839     bool skipTileCheck = drawAA || paint.getMaskFilter();
    840 
    841     if (!skipTileCheck) {
    842         SkRect srcRect = SkRect::MakeIWH(bitmap.width(), bitmap.height());
    843         int tileSize;
    844         SkIRect clippedSrcRect;
    845 
    846         GrSamplerParams params;
    847         bool doBicubic;
    848         GrSamplerParams::FilterMode textureFilterMode =
    849             GrSkFilterQualityToGrFilterMode(paint.getFilterQuality(), viewMatrix, SkMatrix::I(),
    850                                             &doBicubic);
    851 
    852         int tileFilterPad;
    853 
    854         if (doBicubic) {
    855             tileFilterPad = GrBicubicEffect::kFilterTexelPad;
    856         } else if (GrSamplerParams::kNone_FilterMode == textureFilterMode) {
    857             tileFilterPad = 0;
    858         } else {
    859             tileFilterPad = 1;
    860         }
    861         params.setFilterMode(textureFilterMode);
    862 
    863         int maxTileSizeForFilter = fContext->caps()->maxTileSize() - 2 * tileFilterPad;
    864         if (this->shouldTileImageID(bitmap.getGenerationID(), bitmap.getSubset(), viewMatrix,
    865                                     SkMatrix::I(), params, &srcRect, maxTileSizeForFilter,
    866                                     &tileSize, &clippedSrcRect)) {
    867             this->drawTiledBitmap(bitmap, viewMatrix, SkMatrix::I(), srcRect, clippedSrcRect,
    868                                   params, paint, SkCanvas::kStrict_SrcRectConstraint, tileSize,
    869                                   doBicubic);
    870             return;
    871         }
    872     }
    873     GrBitmapTextureMaker maker(fContext.get(), bitmap);
    874     this->drawTextureProducer(&maker, nullptr, nullptr, SkCanvas::kStrict_SrcRectConstraint,
    875                               viewMatrix, this->clip(), paint);
    876 }
    877 
    878 // This method outsets 'iRect' by 'outset' all around and then clamps its extents to
    879 // 'clamp'. 'offset' is adjusted to remain positioned over the top-left corner
    880 // of 'iRect' for all possible outsets/clamps.
    881 static inline void clamped_outset_with_offset(SkIRect* iRect,
    882                                               int outset,
    883                                               SkPoint* offset,
    884                                               const SkIRect& clamp) {
    885     iRect->outset(outset, outset);
    886 
    887     int leftClampDelta = clamp.fLeft - iRect->fLeft;
    888     if (leftClampDelta > 0) {
    889         offset->fX -= outset - leftClampDelta;
    890         iRect->fLeft = clamp.fLeft;
    891     } else {
    892         offset->fX -= outset;
    893     }
    894 
    895     int topClampDelta = clamp.fTop - iRect->fTop;
    896     if (topClampDelta > 0) {
    897         offset->fY -= outset - topClampDelta;
    898         iRect->fTop = clamp.fTop;
    899     } else {
    900         offset->fY -= outset;
    901     }
    902 
    903     if (iRect->fRight > clamp.fRight) {
    904         iRect->fRight = clamp.fRight;
    905     }
    906     if (iRect->fBottom > clamp.fBottom) {
    907         iRect->fBottom = clamp.fBottom;
    908     }
    909 }
    910 
    911 // Break 'bitmap' into several tiles to draw it since it has already
    912 // been determined to be too large to fit in VRAM
    913 void SkGpuDevice::drawTiledBitmap(const SkBitmap& bitmap,
    914                                   const SkMatrix& viewMatrix,
    915                                   const SkMatrix& dstMatrix,
    916                                   const SkRect& srcRect,
    917                                   const SkIRect& clippedSrcIRect,
    918                                   const GrSamplerParams& params,
    919                                   const SkPaint& origPaint,
    920                                   SkCanvas::SrcRectConstraint constraint,
    921                                   int tileSize,
    922                                   bool bicubic) {
    923     ASSERT_SINGLE_OWNER
    924 
    925     // This is the funnel for all paths that draw tiled bitmaps/images. Log histogram entries.
    926     SK_HISTOGRAM_BOOLEAN("DrawTiled", true);
    927     LogDrawScaleFactor(viewMatrix, origPaint.getFilterQuality());
    928 
    929     const SkPaint* paint = &origPaint;
    930     SkPaint tempPaint;
    931     if (origPaint.isAntiAlias() && GrFSAAType::kUnifiedMSAA != fRenderTargetContext->fsaaType()) {
    932         // Drop antialiasing to avoid seams at tile boundaries.
    933         tempPaint = origPaint;
    934         tempPaint.setAntiAlias(false);
    935         paint = &tempPaint;
    936     }
    937     SkRect clippedSrcRect = SkRect::Make(clippedSrcIRect);
    938 
    939     int nx = bitmap.width() / tileSize;
    940     int ny = bitmap.height() / tileSize;
    941     for (int x = 0; x <= nx; x++) {
    942         for (int y = 0; y <= ny; y++) {
    943             SkRect tileR;
    944             tileR.set(SkIntToScalar(x * tileSize),
    945                       SkIntToScalar(y * tileSize),
    946                       SkIntToScalar((x + 1) * tileSize),
    947                       SkIntToScalar((y + 1) * tileSize));
    948 
    949             if (!SkRect::Intersects(tileR, clippedSrcRect)) {
    950                 continue;
    951             }
    952 
    953             if (!tileR.intersect(srcRect)) {
    954                 continue;
    955             }
    956 
    957             SkIRect iTileR;
    958             tileR.roundOut(&iTileR);
    959             SkVector offset = SkPoint::Make(SkIntToScalar(iTileR.fLeft),
    960                                             SkIntToScalar(iTileR.fTop));
    961             SkRect rectToDraw = tileR;
    962             dstMatrix.mapRect(&rectToDraw);
    963             if (GrSamplerParams::kNone_FilterMode != params.filterMode() || bicubic) {
    964                 SkIRect iClampRect;
    965 
    966                 if (SkCanvas::kFast_SrcRectConstraint == constraint) {
    967                     // In bleed mode we want to always expand the tile on all edges
    968                     // but stay within the bitmap bounds
    969                     iClampRect = SkIRect::MakeWH(bitmap.width(), bitmap.height());
    970                 } else {
    971                     // In texture-domain/clamp mode we only want to expand the
    972                     // tile on edges interior to "srcRect" (i.e., we want to
    973                     // not bleed across the original clamped edges)
    974                     srcRect.roundOut(&iClampRect);
    975                 }
    976                 int outset = bicubic ? GrBicubicEffect::kFilterTexelPad : 1;
    977                 clamped_outset_with_offset(&iTileR, outset, &offset, iClampRect);
    978             }
    979 
    980             SkBitmap tmpB;
    981             if (bitmap.extractSubset(&tmpB, iTileR)) {
    982                 // now offset it to make it "local" to our tmp bitmap
    983                 tileR.offset(-offset.fX, -offset.fY);
    984                 // de-optimized this determination
    985                 bool needsTextureDomain = true;
    986                 this->drawBitmapTile(tmpB,
    987                                      viewMatrix,
    988                                      rectToDraw,
    989                                      tileR,
    990                                      params,
    991                                      *paint,
    992                                      constraint,
    993                                      bicubic,
    994                                      needsTextureDomain);
    995             }
    996         }
    997     }
    998 }
    999 
   1000 void SkGpuDevice::drawBitmapTile(const SkBitmap& bitmap,
   1001                                  const SkMatrix& viewMatrix,
   1002                                  const SkRect& dstRect,
   1003                                  const SkRect& srcRect,
   1004                                  const GrSamplerParams& params,
   1005                                  const SkPaint& paint,
   1006                                  SkCanvas::SrcRectConstraint constraint,
   1007                                  bool bicubic,
   1008                                  bool needsTextureDomain) {
   1009     // We should have already handled bitmaps larger than the max texture size.
   1010     SkASSERT(bitmap.width() <= fContext->caps()->maxTextureSize() &&
   1011              bitmap.height() <= fContext->caps()->maxTextureSize());
   1012     // We should be respecting the max tile size by the time we get here.
   1013     SkASSERT(bitmap.width() <= fContext->caps()->maxTileSize() &&
   1014              bitmap.height() <= fContext->caps()->maxTileSize());
   1015 
   1016     SkASSERT(SkShader::kClamp_TileMode == params.getTileModeX() &&
   1017              SkShader::kClamp_TileMode == params.getTileModeY());
   1018 
   1019     sk_sp<GrTextureProxy> proxy = GrRefCachedBitmapTextureProxy(fContext.get(), bitmap,
   1020                                                                 params, nullptr);
   1021     if (!proxy) {
   1022         return;
   1023     }
   1024     sk_sp<GrColorSpaceXform> colorSpaceXform =
   1025         GrColorSpaceXform::Make(bitmap.colorSpace(), fRenderTargetContext->getColorSpace());
   1026 
   1027     // Compute a matrix that maps the rect we will draw to the src rect.
   1028     const SkMatrix texMatrix = SkMatrix::MakeRectToRect(dstRect, srcRect,
   1029                                                         SkMatrix::kFill_ScaleToFit);
   1030 
   1031     // Construct a GrPaint by setting the bitmap texture as the first effect and then configuring
   1032     // the rest from the SkPaint.
   1033     sk_sp<GrFragmentProcessor> fp;
   1034 
   1035     if (needsTextureDomain && (SkCanvas::kStrict_SrcRectConstraint == constraint)) {
   1036         // Use a constrained texture domain to avoid color bleeding
   1037         SkRect domain;
   1038         if (srcRect.width() > SK_Scalar1) {
   1039             domain.fLeft  = srcRect.fLeft + 0.5f;
   1040             domain.fRight = srcRect.fRight - 0.5f;
   1041         } else {
   1042             domain.fLeft = domain.fRight = srcRect.centerX();
   1043         }
   1044         if (srcRect.height() > SK_Scalar1) {
   1045             domain.fTop  = srcRect.fTop + 0.5f;
   1046             domain.fBottom = srcRect.fBottom - 0.5f;
   1047         } else {
   1048             domain.fTop = domain.fBottom = srcRect.centerY();
   1049         }
   1050         if (bicubic) {
   1051             fp = GrBicubicEffect::Make(std::move(proxy),
   1052                                        std::move(colorSpaceXform), texMatrix, domain);
   1053         } else {
   1054             fp = GrTextureDomainEffect::Make(std::move(proxy),
   1055                                              std::move(colorSpaceXform), texMatrix,
   1056                                              domain, GrTextureDomain::kClamp_Mode,
   1057                                              params.filterMode());
   1058         }
   1059     } else if (bicubic) {
   1060         SkASSERT(GrSamplerParams::kNone_FilterMode == params.filterMode());
   1061         SkShader::TileMode tileModes[2] = { params.getTileModeX(), params.getTileModeY() };
   1062         fp = GrBicubicEffect::Make(std::move(proxy),
   1063                                    std::move(colorSpaceXform), texMatrix, tileModes);
   1064     } else {
   1065         fp = GrSimpleTextureEffect::Make(std::move(proxy),
   1066                                          std::move(colorSpaceXform), texMatrix, params);
   1067     }
   1068 
   1069     GrPaint grPaint;
   1070     if (!SkPaintToGrPaintWithTexture(this->context(), fRenderTargetContext.get(), paint, viewMatrix,
   1071                                      std::move(fp), kAlpha_8_SkColorType == bitmap.colorType(),
   1072                                      &grPaint)) {
   1073         return;
   1074     }
   1075 
   1076     // Coverage-based AA would cause seams between tiles.
   1077     GrAA aa = GrBoolToAA(paint.isAntiAlias() &&
   1078                          GrFSAAType::kNone != fRenderTargetContext->fsaaType());
   1079     fRenderTargetContext->drawRect(this->clip(), std::move(grPaint), aa, viewMatrix, dstRect);
   1080 }
   1081 
   1082 void SkGpuDevice::drawSprite(const SkBitmap& bitmap,
   1083                              int left, int top, const SkPaint& paint) {
   1084     ASSERT_SINGLE_OWNER
   1085     CHECK_SHOULD_DRAW();
   1086     GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawSprite", fContext.get());
   1087 
   1088     if (fContext->abandoned()) {
   1089         return;
   1090     }
   1091 
   1092     sk_sp<SkSpecialImage> srcImg = this->makeSpecial(bitmap);
   1093     if (!srcImg) {
   1094         return;
   1095     }
   1096 
   1097     this->drawSpecial(srcImg.get(), left, top, paint, nullptr, SkMatrix::I());
   1098 }
   1099 
   1100 
   1101 void SkGpuDevice::drawSpecial(SkSpecialImage* special1, int left, int top, const SkPaint& paint,
   1102                               SkImage* clipImage,const SkMatrix& clipMatrix) {
   1103     ASSERT_SINGLE_OWNER
   1104     CHECK_SHOULD_DRAW();
   1105     GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawSpecial", fContext.get());
   1106 
   1107     // TODO: clipImage support.
   1108 
   1109     SkIPoint offset = { 0, 0 };
   1110 
   1111     sk_sp<SkSpecialImage> result;
   1112     if (paint.getImageFilter()) {
   1113         result = this->filterTexture(special1, left, top,
   1114                                       &offset,
   1115                                       paint.getImageFilter());
   1116         if (!result) {
   1117             return;
   1118         }
   1119     } else {
   1120         result = sk_ref_sp(special1);
   1121     }
   1122 
   1123     SkASSERT(result->isTextureBacked());
   1124     sk_sp<GrTextureProxy> proxy = result->asTextureProxyRef(this->context());
   1125     if (!proxy) {
   1126         return;
   1127     }
   1128 
   1129     const GrPixelConfig config = proxy->config();
   1130 
   1131     SkPaint tmpUnfiltered(paint);
   1132     tmpUnfiltered.setImageFilter(nullptr);
   1133 
   1134     sk_sp<GrColorSpaceXform> colorSpaceXform =
   1135         GrColorSpaceXform::Make(result->getColorSpace(), fRenderTargetContext->getColorSpace());
   1136 
   1137     sk_sp<GrFragmentProcessor> fp(GrSimpleTextureEffect::Make(std::move(proxy),
   1138                                                               std::move(colorSpaceXform),
   1139                                                               SkMatrix::I()));
   1140     if (GrPixelConfigIsAlphaOnly(config)) {
   1141         fp = GrFragmentProcessor::MakeInputPremulAndMulByOutput(std::move(fp));
   1142     } else {
   1143         fp = GrFragmentProcessor::MulOutputByInputAlpha(std::move(fp));
   1144     }
   1145 
   1146     GrPaint grPaint;
   1147     if (!SkPaintToGrPaintReplaceShader(this->context(), fRenderTargetContext.get(), tmpUnfiltered,
   1148                                        std::move(fp), &grPaint)) {
   1149         return;
   1150     }
   1151 
   1152     const SkIRect& subset = result->subset();
   1153 
   1154     fRenderTargetContext->fillRectToRect(
   1155             this->clip(),
   1156             std::move(grPaint),
   1157             GrBoolToAA(paint.isAntiAlias()),
   1158             SkMatrix::I(),
   1159             SkRect::Make(SkIRect::MakeXYWH(left + offset.fX, top + offset.fY, subset.width(),
   1160                                            subset.height())),
   1161             SkRect::Make(subset));
   1162 }
   1163 
   1164 void SkGpuDevice::drawBitmapRect(const SkBitmap& bitmap,
   1165                                  const SkRect* src, const SkRect& origDst,
   1166                                  const SkPaint& paint, SkCanvas::SrcRectConstraint constraint) {
   1167     ASSERT_SINGLE_OWNER
   1168     CHECK_SHOULD_DRAW();
   1169 
   1170     // The src rect is inferred to be the bmp bounds if not provided. Otherwise, the src rect must
   1171     // be clipped to the bmp bounds. To determine tiling parameters we need the filter mode which
   1172     // in turn requires knowing the src-to-dst mapping. If the src was clipped to the bmp bounds
   1173     // then we use the src-to-dst mapping to compute a new clipped dst rect.
   1174     const SkRect* dst = &origDst;
   1175     const SkRect bmpBounds = SkRect::MakeIWH(bitmap.width(), bitmap.height());
   1176     // Compute matrix from the two rectangles
   1177     if (!src) {
   1178         src = &bmpBounds;
   1179     }
   1180 
   1181     SkMatrix srcToDstMatrix;
   1182     if (!srcToDstMatrix.setRectToRect(*src, *dst, SkMatrix::kFill_ScaleToFit)) {
   1183         return;
   1184     }
   1185     SkRect tmpSrc, tmpDst;
   1186     if (src != &bmpBounds) {
   1187         if (!bmpBounds.contains(*src)) {
   1188             tmpSrc = *src;
   1189             if (!tmpSrc.intersect(bmpBounds)) {
   1190                 return; // nothing to draw
   1191             }
   1192             src = &tmpSrc;
   1193             srcToDstMatrix.mapRect(&tmpDst, *src);
   1194             dst = &tmpDst;
   1195         }
   1196     }
   1197 
   1198     int maxTileSize = fContext->caps()->maxTileSize();
   1199 
   1200     // The tile code path doesn't currently support AA, so if the paint asked for aa and we could
   1201     // draw untiled, then we bypass checking for tiling purely for optimization reasons.
   1202     bool useCoverageAA = GrFSAAType::kUnifiedMSAA != fRenderTargetContext->fsaaType() &&
   1203                          paint.isAntiAlias() && bitmap.width() <= maxTileSize &&
   1204                          bitmap.height() <= maxTileSize;
   1205 
   1206     bool skipTileCheck = useCoverageAA || paint.getMaskFilter();
   1207 
   1208     if (!skipTileCheck) {
   1209         int tileSize;
   1210         SkIRect clippedSrcRect;
   1211 
   1212         GrSamplerParams params;
   1213         bool doBicubic;
   1214         GrSamplerParams::FilterMode textureFilterMode =
   1215             GrSkFilterQualityToGrFilterMode(paint.getFilterQuality(), this->ctm(), srcToDstMatrix,
   1216                                             &doBicubic);
   1217 
   1218         int tileFilterPad;
   1219 
   1220         if (doBicubic) {
   1221             tileFilterPad = GrBicubicEffect::kFilterTexelPad;
   1222         } else if (GrSamplerParams::kNone_FilterMode == textureFilterMode) {
   1223             tileFilterPad = 0;
   1224         } else {
   1225             tileFilterPad = 1;
   1226         }
   1227         params.setFilterMode(textureFilterMode);
   1228 
   1229         int maxTileSizeForFilter = fContext->caps()->maxTileSize() - 2 * tileFilterPad;
   1230         if (this->shouldTileImageID(bitmap.getGenerationID(), bitmap.getSubset(), this->ctm(),
   1231                                     srcToDstMatrix, params, src, maxTileSizeForFilter, &tileSize,
   1232                                     &clippedSrcRect)) {
   1233             this->drawTiledBitmap(bitmap, this->ctm(), srcToDstMatrix, *src, clippedSrcRect,
   1234                                   params, paint, constraint, tileSize, doBicubic);
   1235             return;
   1236         }
   1237     }
   1238     GrBitmapTextureMaker maker(fContext.get(), bitmap);
   1239     this->drawTextureProducer(&maker, src, dst, constraint, this->ctm(), this->clip(), paint);
   1240 }
   1241 
   1242 sk_sp<SkSpecialImage> SkGpuDevice::makeSpecial(const SkBitmap& bitmap) {
   1243     // TODO: this makes a tight copy of 'bitmap' but it doesn't have to be (given SkSpecialImage's
   1244     // semantics). Since this is cached we would have to bake the fit into the cache key though.
   1245     sk_sp<GrTextureProxy> proxy = GrMakeCachedBitmapProxy(fContext->resourceProvider(), bitmap);
   1246     if (!proxy) {
   1247         return nullptr;
   1248     }
   1249 
   1250     const SkIRect rect = SkIRect::MakeWH(proxy->width(), proxy->height());
   1251 
   1252     // GrMakeCachedBitmapProxy creates a tight copy of 'bitmap' so we don't have to subset
   1253     // the special image
   1254     return SkSpecialImage::MakeDeferredFromGpu(fContext.get(),
   1255                                                rect,
   1256                                                bitmap.getGenerationID(),
   1257                                                std::move(proxy),
   1258                                                bitmap.refColorSpace(),
   1259                                                &this->surfaceProps());
   1260 }
   1261 
   1262 sk_sp<SkSpecialImage> SkGpuDevice::makeSpecial(const SkImage* image) {
   1263     SkPixmap pm;
   1264     if (image->isTextureBacked()) {
   1265         sk_sp<GrTextureProxy> proxy = as_IB(image)->asTextureProxyRef();
   1266 
   1267         return SkSpecialImage::MakeDeferredFromGpu(fContext.get(),
   1268                                                    SkIRect::MakeWH(image->width(), image->height()),
   1269                                                    image->uniqueID(),
   1270                                                    std::move(proxy),
   1271                                                    as_IB(image)->onImageInfo().refColorSpace(),
   1272                                                    &this->surfaceProps());
   1273     } else if (image->peekPixels(&pm)) {
   1274         SkBitmap bm;
   1275 
   1276         bm.installPixels(pm);
   1277         return this->makeSpecial(bm);
   1278     } else {
   1279         return nullptr;
   1280     }
   1281 }
   1282 
   1283 sk_sp<SkSpecialImage> SkGpuDevice::snapSpecial() {
   1284     sk_sp<GrTextureProxy> proxy(this->accessRenderTargetContext()->asTextureProxyRef());
   1285     if (!proxy) {
   1286         // When the device doesn't have a texture, we create a temporary texture.
   1287         // TODO: we should actually only copy the portion of the source needed to apply the image
   1288         // filter
   1289         proxy = GrSurfaceProxy::Copy(fContext.get(),
   1290                                      this->accessRenderTargetContext()->asSurfaceProxy(),
   1291                                      SkBudgeted::kYes);
   1292         if (!proxy) {
   1293             return nullptr;
   1294         }
   1295     }
   1296 
   1297     const SkImageInfo ii = this->imageInfo();
   1298     const SkIRect srcRect = SkIRect::MakeWH(ii.width(), ii.height());
   1299 
   1300     return SkSpecialImage::MakeDeferredFromGpu(fContext.get(),
   1301                                                srcRect,
   1302                                                kNeedNewImageUniqueID_SpecialImage,
   1303                                                std::move(proxy),
   1304                                                ii.refColorSpace(),
   1305                                                &this->surfaceProps());
   1306 }
   1307 
   1308 void SkGpuDevice::drawDevice(SkBaseDevice* device,
   1309                              int left, int top, const SkPaint& paint) {
   1310     SkASSERT(!paint.getImageFilter());
   1311 
   1312     ASSERT_SINGLE_OWNER
   1313     // clear of the source device must occur before CHECK_SHOULD_DRAW
   1314     GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawDevice", fContext.get());
   1315 
   1316     // drawDevice is defined to be in device coords.
   1317     CHECK_SHOULD_DRAW();
   1318 
   1319     SkGpuDevice* dev = static_cast<SkGpuDevice*>(device);
   1320     sk_sp<SkSpecialImage> srcImg(dev->snapSpecial());
   1321     if (!srcImg) {
   1322         return;
   1323     }
   1324 
   1325     this->drawSpecial(srcImg.get(), left, top, paint, nullptr, SkMatrix::I());
   1326 }
   1327 
   1328 void SkGpuDevice::drawImage(const SkImage* image, SkScalar x, SkScalar y,
   1329                             const SkPaint& paint) {
   1330     ASSERT_SINGLE_OWNER
   1331     SkMatrix viewMatrix = this->ctm();
   1332     viewMatrix.preTranslate(x, y);
   1333     uint32_t pinnedUniqueID;
   1334 
   1335     if (sk_sp<GrTextureProxy> proxy = as_IB(image)->refPinnedTextureProxy(&pinnedUniqueID)) {
   1336         CHECK_SHOULD_DRAW();
   1337         GrTextureAdjuster adjuster(this->context(), std::move(proxy),
   1338                                    image->alphaType(), image->bounds(),
   1339                                    pinnedUniqueID, as_IB(image)->onImageInfo().colorSpace());
   1340         this->drawTextureProducer(&adjuster, nullptr, nullptr, SkCanvas::kFast_SrcRectConstraint,
   1341                                   viewMatrix, this->clip(), paint);
   1342         return;
   1343     } else {
   1344         SkBitmap bm;
   1345         if (this->shouldTileImage(image, nullptr, SkCanvas::kFast_SrcRectConstraint,
   1346                                   paint.getFilterQuality(), this->ctm(), SkMatrix::I())) {
   1347             // only support tiling as bitmap at the moment, so force raster-version
   1348             if (!as_IB(image)->getROPixels(&bm, fRenderTargetContext->getColorSpace())) {
   1349                 return;
   1350             }
   1351             this->drawBitmap(bm, x, y, paint);
   1352         } else if (image->isLazyGenerated()) {
   1353             CHECK_SHOULD_DRAW();
   1354             GrImageTextureMaker maker(fContext.get(), image, SkImage::kAllow_CachingHint);
   1355             this->drawTextureProducer(&maker, nullptr, nullptr, SkCanvas::kFast_SrcRectConstraint,
   1356                                       viewMatrix, this->clip(), paint);
   1357         } else if (as_IB(image)->getROPixels(&bm, fRenderTargetContext->getColorSpace())) {
   1358             this->drawBitmap(bm, x, y, paint);
   1359         }
   1360     }
   1361 }
   1362 
   1363 void SkGpuDevice::drawImageRect(const SkImage* image, const SkRect* src,
   1364                                 const SkRect& dst, const SkPaint& paint,
   1365                                 SkCanvas::SrcRectConstraint constraint) {
   1366     ASSERT_SINGLE_OWNER
   1367     uint32_t pinnedUniqueID;
   1368     if (sk_sp<GrTextureProxy> proxy = as_IB(image)->refPinnedTextureProxy(&pinnedUniqueID)) {
   1369         CHECK_SHOULD_DRAW();
   1370         GrTextureAdjuster adjuster(this->context(), std::move(proxy),
   1371                                    image->alphaType(), image->bounds(), pinnedUniqueID,
   1372                                    as_IB(image)->onImageInfo().colorSpace());
   1373         this->drawTextureProducer(&adjuster, src, &dst, constraint, this->ctm(), this->clip(),
   1374                                   paint);
   1375         return;
   1376     }
   1377     SkBitmap bm;
   1378     SkMatrix srcToDstRect;
   1379     srcToDstRect.setRectToRect((src ? *src : SkRect::MakeIWH(image->width(), image->height())),
   1380                                dst, SkMatrix::kFill_ScaleToFit);
   1381     if (this->shouldTileImage(image, src, constraint, paint.getFilterQuality(), this->ctm(),
   1382                               srcToDstRect)) {
   1383         // only support tiling as bitmap at the moment, so force raster-version
   1384         if (!as_IB(image)->getROPixels(&bm, fRenderTargetContext->getColorSpace())) {
   1385             return;
   1386         }
   1387         this->drawBitmapRect(bm, src, dst, paint, constraint);
   1388     } else if (image->isLazyGenerated()) {
   1389         CHECK_SHOULD_DRAW();
   1390         GrImageTextureMaker maker(fContext.get(), image, SkImage::kAllow_CachingHint);
   1391         this->drawTextureProducer(&maker, src, &dst, constraint, this->ctm(), this->clip(), paint);
   1392     } else if (as_IB(image)->getROPixels(&bm, fRenderTargetContext->getColorSpace())) {
   1393         this->drawBitmapRect(bm, src, dst, paint, constraint);
   1394     }
   1395 }
   1396 
   1397 void SkGpuDevice::drawProducerNine(GrTextureProducer* producer,
   1398                                    const SkIRect& center, const SkRect& dst, const SkPaint& paint) {
   1399     GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawProducerNine", fContext.get());
   1400 
   1401     CHECK_SHOULD_DRAW();
   1402 
   1403     bool useFallback = paint.getMaskFilter() || paint.isAntiAlias() ||
   1404                        GrFSAAType::kUnifiedMSAA == fRenderTargetContext->fsaaType();
   1405     bool doBicubic;
   1406     GrSamplerParams::FilterMode textureFilterMode =
   1407         GrSkFilterQualityToGrFilterMode(paint.getFilterQuality(), this->ctm(), SkMatrix::I(),
   1408                                         &doBicubic);
   1409     if (useFallback || doBicubic || GrSamplerParams::kNone_FilterMode != textureFilterMode) {
   1410         SkLatticeIter iter(producer->width(), producer->height(), center, dst);
   1411 
   1412         SkRect srcR, dstR;
   1413         while (iter.next(&srcR, &dstR)) {
   1414             this->drawTextureProducer(producer, &srcR, &dstR, SkCanvas::kStrict_SrcRectConstraint,
   1415                                       this->ctm(), this->clip(), paint);
   1416         }
   1417         return;
   1418     }
   1419 
   1420     static const GrSamplerParams::FilterMode kMode = GrSamplerParams::kNone_FilterMode;
   1421     sk_sp<GrFragmentProcessor> fp(
   1422         producer->createFragmentProcessor(SkMatrix::I(),
   1423                                           SkRect::MakeIWH(producer->width(), producer->height()),
   1424                                           GrTextureProducer::kNo_FilterConstraint, true,
   1425                                           &kMode, fRenderTargetContext->getColorSpace()));
   1426     if (!fp) {
   1427         return;
   1428     }
   1429     GrPaint grPaint;
   1430     if (!SkPaintToGrPaintWithTexture(this->context(), fRenderTargetContext.get(), paint,
   1431                                      this->ctm(), std::move(fp), producer->isAlphaOnly(),
   1432                                      &grPaint)) {
   1433         return;
   1434     }
   1435 
   1436     std::unique_ptr<SkLatticeIter> iter(
   1437             new SkLatticeIter(producer->width(), producer->height(), center, dst));
   1438     fRenderTargetContext->drawImageLattice(this->clip(), std::move(grPaint), this->ctm(),
   1439                                            producer->width(), producer->height(), std::move(iter),
   1440                                            dst);
   1441 }
   1442 
   1443 void SkGpuDevice::drawImageNine(const SkImage* image,
   1444                                 const SkIRect& center, const SkRect& dst, const SkPaint& paint) {
   1445     ASSERT_SINGLE_OWNER
   1446     uint32_t pinnedUniqueID;
   1447     if (sk_sp<GrTextureProxy> proxy = as_IB(image)->refPinnedTextureProxy(&pinnedUniqueID)) {
   1448         CHECK_SHOULD_DRAW();
   1449         GrTextureAdjuster adjuster(this->context(), std::move(proxy),
   1450                                    image->alphaType(), image->bounds(),
   1451                                    pinnedUniqueID, as_IB(image)->onImageInfo().colorSpace());
   1452         this->drawProducerNine(&adjuster, center, dst, paint);
   1453     } else {
   1454         SkBitmap bm;
   1455         if (image->isLazyGenerated()) {
   1456             GrImageTextureMaker maker(fContext.get(), image, SkImage::kAllow_CachingHint);
   1457             this->drawProducerNine(&maker, center, dst, paint);
   1458         } else if (as_IB(image)->getROPixels(&bm, fRenderTargetContext->getColorSpace())) {
   1459             this->drawBitmapNine(bm, center, dst, paint);
   1460         }
   1461     }
   1462 }
   1463 
   1464 void SkGpuDevice::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center,
   1465                                  const SkRect& dst, const SkPaint& paint) {
   1466     ASSERT_SINGLE_OWNER
   1467     GrBitmapTextureMaker maker(fContext.get(), bitmap);
   1468     this->drawProducerNine(&maker, center, dst, paint);
   1469 }
   1470 
   1471 void SkGpuDevice::drawProducerLattice(GrTextureProducer* producer,
   1472                                       const SkCanvas::Lattice& lattice, const SkRect& dst,
   1473                                       const SkPaint& paint) {
   1474     GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawProducerLattice", fContext.get());
   1475 
   1476     CHECK_SHOULD_DRAW();
   1477 
   1478     static const GrSamplerParams::FilterMode kMode = GrSamplerParams::kNone_FilterMode;
   1479     sk_sp<GrFragmentProcessor> fp(
   1480         producer->createFragmentProcessor(SkMatrix::I(),
   1481                                           SkRect::MakeIWH(producer->width(), producer->height()),
   1482                                           GrTextureProducer::kNo_FilterConstraint, true,
   1483                                           &kMode, fRenderTargetContext->getColorSpace()));
   1484     if (!fp) {
   1485         return;
   1486     }
   1487     GrPaint grPaint;
   1488     if (!SkPaintToGrPaintWithTexture(this->context(), fRenderTargetContext.get(), paint,
   1489                                      this->ctm(), std::move(fp), producer->isAlphaOnly(),
   1490                                      &grPaint)) {
   1491         return;
   1492     }
   1493 
   1494     std::unique_ptr<SkLatticeIter> iter(
   1495             new SkLatticeIter(lattice, dst));
   1496     fRenderTargetContext->drawImageLattice(this->clip(), std::move(grPaint), this->ctm(),
   1497                                            producer->width(), producer->height(), std::move(iter),
   1498                                            dst);
   1499 }
   1500 
   1501 void SkGpuDevice::drawImageLattice(const SkImage* image,
   1502                                    const SkCanvas::Lattice& lattice, const SkRect& dst,
   1503                                    const SkPaint& paint) {
   1504     ASSERT_SINGLE_OWNER
   1505     uint32_t pinnedUniqueID;
   1506     if (sk_sp<GrTextureProxy> proxy = as_IB(image)->refPinnedTextureProxy(&pinnedUniqueID)) {
   1507         CHECK_SHOULD_DRAW();
   1508         GrTextureAdjuster adjuster(this->context(), std::move(proxy),
   1509                                    image->alphaType(), image->bounds(),
   1510                                    pinnedUniqueID, as_IB(image)->onImageInfo().colorSpace());
   1511         this->drawProducerLattice(&adjuster, lattice, dst, paint);
   1512     } else {
   1513         SkBitmap bm;
   1514         if (image->isLazyGenerated()) {
   1515             GrImageTextureMaker maker(fContext.get(), image, SkImage::kAllow_CachingHint);
   1516             this->drawProducerLattice(&maker, lattice, dst, paint);
   1517         } else if (as_IB(image)->getROPixels(&bm, fRenderTargetContext->getColorSpace())) {
   1518             this->drawBitmapLattice(bm, lattice, dst, paint);
   1519         }
   1520     }
   1521 }
   1522 
   1523 void SkGpuDevice::drawBitmapLattice(const SkBitmap& bitmap,
   1524                                     const SkCanvas::Lattice& lattice, const SkRect& dst,
   1525                                     const SkPaint& paint) {
   1526     ASSERT_SINGLE_OWNER
   1527     GrBitmapTextureMaker maker(fContext.get(), bitmap);
   1528     this->drawProducerLattice(&maker, lattice, dst, paint);
   1529 }
   1530 
   1531 static bool init_vertices_paint(GrContext* context, GrRenderTargetContext* rtc,
   1532                                 const SkPaint& skPaint,
   1533                                 const SkMatrix& matrix, SkBlendMode bmode,
   1534                                 bool hasTexs, bool hasColors, GrPaint* grPaint) {
   1535     if (hasTexs && skPaint.getShader()) {
   1536         if (hasColors) {
   1537             // When there are texs and colors the shader and colors are combined using bmode.
   1538             return SkPaintToGrPaintWithXfermode(context, rtc, skPaint, matrix, bmode, grPaint);
   1539         } else {
   1540             // We have a shader, but no colors to blend it against.
   1541             return SkPaintToGrPaint(context, rtc, skPaint, matrix, grPaint);
   1542         }
   1543     } else {
   1544         if (hasColors) {
   1545             // We have colors, but either have no shader or no texture coords (which implies that
   1546             // we should ignore the shader).
   1547             return SkPaintToGrPaintWithPrimitiveColor(context, rtc, skPaint, grPaint);
   1548         } else {
   1549             // No colors and no shaders. Just draw with the paint color.
   1550             return SkPaintToGrPaintNoShader(context, rtc, skPaint, grPaint);
   1551         }
   1552     }
   1553 }
   1554 
   1555 void SkGpuDevice::wireframeVertices(SkVertices::VertexMode vmode, int vertexCount,
   1556                                     const SkPoint vertices[], SkBlendMode bmode,
   1557                                     const uint16_t indices[], int indexCount,
   1558                                     const SkPaint& paint) {
   1559     ASSERT_SINGLE_OWNER
   1560     CHECK_SHOULD_DRAW();
   1561     GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "wireframeVertices", fContext.get());
   1562 
   1563     SkPaint copy(paint);
   1564     copy.setStyle(SkPaint::kStroke_Style);
   1565     copy.setStrokeWidth(0);
   1566 
   1567     GrPaint grPaint;
   1568     // we ignore the shader since we have no texture coordinates.
   1569     if (!SkPaintToGrPaintNoShader(this->context(), fRenderTargetContext.get(), copy, &grPaint)) {
   1570         return;
   1571     }
   1572 
   1573     int triangleCount = 0;
   1574     int n = (nullptr == indices) ? vertexCount : indexCount;
   1575     switch (vmode) {
   1576         case SkVertices::kTriangles_VertexMode:
   1577             triangleCount = n / 3;
   1578             break;
   1579         case SkVertices::kTriangleStrip_VertexMode:
   1580         case SkVertices::kTriangleFan_VertexMode:
   1581             triangleCount = n - 2;
   1582             break;
   1583     }
   1584 
   1585     VertState       state(vertexCount, indices, indexCount);
   1586     VertState::Proc vertProc = state.chooseProc(vmode);
   1587 
   1588     //number of indices for lines per triangle with kLines
   1589     indexCount = triangleCount * 6;
   1590 
   1591     static constexpr SkVertices::VertexMode kIgnoredMode = SkVertices::kTriangles_VertexMode;
   1592     SkVertices::Builder builder(kIgnoredMode, vertexCount, indexCount, 0);
   1593     memcpy(builder.positions(), vertices, vertexCount * sizeof(SkPoint));
   1594 
   1595     uint16_t* lineIndices = builder.indices();
   1596     int i = 0;
   1597     while (vertProc(&state)) {
   1598         lineIndices[i]     = state.f0;
   1599         lineIndices[i + 1] = state.f1;
   1600         lineIndices[i + 2] = state.f1;
   1601         lineIndices[i + 3] = state.f2;
   1602         lineIndices[i + 4] = state.f2;
   1603         lineIndices[i + 5] = state.f0;
   1604         i += 6;
   1605     }
   1606 
   1607     GrPrimitiveType primitiveType = GrPrimitiveType::kLines;
   1608     fRenderTargetContext->drawVertices(this->clip(),
   1609                                        std::move(grPaint),
   1610                                        this->ctm(),
   1611                                        builder.detach(),
   1612                                        &primitiveType);
   1613 }
   1614 
   1615 void SkGpuDevice::drawVertices(const SkVertices* vertices, SkBlendMode mode, const SkPaint& paint) {
   1616     ASSERT_SINGLE_OWNER
   1617     CHECK_SHOULD_DRAW();
   1618     GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawVertices", fContext.get());
   1619 
   1620     SkASSERT(vertices);
   1621     GrPaint grPaint;
   1622     bool hasColors = vertices->hasColors();
   1623     bool hasTexs = vertices->hasTexCoords();
   1624     if ((!hasTexs || !paint.getShader()) && !hasColors) {
   1625         // The dreaded wireframe mode. Fallback to drawVertices and go so slooooooow.
   1626         this->wireframeVertices(vertices->mode(), vertices->vertexCount(), vertices->positions(),
   1627                                 mode, vertices->indices(), vertices->indexCount(), paint);
   1628         return;
   1629     }
   1630     if (!init_vertices_paint(fContext.get(), fRenderTargetContext.get(), paint, this->ctm(),
   1631                              mode, hasTexs, hasColors, &grPaint)) {
   1632         return;
   1633     }
   1634     fRenderTargetContext->drawVertices(this->clip(), std::move(grPaint), this->ctm(),
   1635                                        sk_ref_sp(const_cast<SkVertices*>(vertices)));
   1636 }
   1637 
   1638 ///////////////////////////////////////////////////////////////////////////////
   1639 
   1640 void SkGpuDevice::drawShadow(const SkPath& path, const SkDrawShadowRec& rec) {
   1641 
   1642     ASSERT_SINGLE_OWNER
   1643     CHECK_SHOULD_DRAW();
   1644     GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawShadow", fContext.get());
   1645 
   1646     GrColor color = SkColorToPremulGrColor(rec.fColor);
   1647     if (!fRenderTargetContext->drawFastShadow(this->clip(), color, this->ctm(), path, rec)) {
   1648         // failed to find an accelerated case
   1649         this->INHERITED::drawShadow(path, rec);
   1650     }
   1651 }
   1652 
   1653 ///////////////////////////////////////////////////////////////////////////////
   1654 
   1655 void SkGpuDevice::drawAtlas(const SkImage* atlas, const SkRSXform xform[],
   1656                             const SkRect texRect[], const SkColor colors[], int count,
   1657                             SkBlendMode mode, const SkPaint& paint) {
   1658     ASSERT_SINGLE_OWNER
   1659     if (paint.isAntiAlias()) {
   1660         this->INHERITED::drawAtlas(atlas, xform, texRect, colors, count, mode, paint);
   1661         return;
   1662     }
   1663 
   1664     CHECK_SHOULD_DRAW();
   1665     GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawText", fContext.get());
   1666 
   1667     SkPaint p(paint);
   1668     p.setShader(atlas->makeShader());
   1669 
   1670     GrPaint grPaint;
   1671     if (colors) {
   1672         if (!SkPaintToGrPaintWithXfermode(this->context(), fRenderTargetContext.get(), p,
   1673                                           this->ctm(), (SkBlendMode)mode, &grPaint)) {
   1674             return;
   1675         }
   1676     } else {
   1677         if (!SkPaintToGrPaint(this->context(), fRenderTargetContext.get(), p, this->ctm(),
   1678                               &grPaint)) {
   1679             return;
   1680         }
   1681     }
   1682 
   1683     SkDEBUGCODE(this->validate();)
   1684     fRenderTargetContext->drawAtlas(
   1685             this->clip(), std::move(grPaint), this->ctm(), count, xform, texRect, colors);
   1686 }
   1687 
   1688 ///////////////////////////////////////////////////////////////////////////////
   1689 
   1690 void SkGpuDevice::drawText(const void* text,
   1691                            size_t byteLength, SkScalar x, SkScalar y,
   1692                            const SkPaint& paint) {
   1693     ASSERT_SINGLE_OWNER
   1694     CHECK_SHOULD_DRAW();
   1695     GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawText", fContext.get());
   1696     SkDEBUGCODE(this->validate();)
   1697 
   1698     fRenderTargetContext->drawText(this->clip(), paint, this->ctm(), (const char*)text, byteLength,
   1699                                    x, y, this->devClipBounds());
   1700 }
   1701 
   1702 void SkGpuDevice::drawPosText(const void* text, size_t byteLength,
   1703                               const SkScalar pos[], int scalarsPerPos,
   1704                               const SkPoint& offset, const SkPaint& paint) {
   1705     ASSERT_SINGLE_OWNER
   1706     GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawPosText", fContext.get());
   1707     CHECK_SHOULD_DRAW();
   1708     SkDEBUGCODE(this->validate();)
   1709 
   1710     fRenderTargetContext->drawPosText(this->clip(), paint, this->ctm(), (const char*)text,
   1711                                       byteLength, pos, scalarsPerPos, offset,
   1712                                       this->devClipBounds());
   1713 }
   1714 
   1715 void SkGpuDevice::drawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
   1716                                const SkPaint& paint, SkDrawFilter* drawFilter) {
   1717     ASSERT_SINGLE_OWNER
   1718     GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawTextBlob", fContext.get());
   1719     CHECK_SHOULD_DRAW();
   1720 
   1721     SkDEBUGCODE(this->validate();)
   1722 
   1723     fRenderTargetContext->drawTextBlob(this->clip(), paint, this->ctm(), blob, x, y, drawFilter,
   1724                                        this->devClipBounds());
   1725 }
   1726 
   1727 ///////////////////////////////////////////////////////////////////////////////
   1728 
   1729 bool SkGpuDevice::onShouldDisableLCD(const SkPaint& paint) const {
   1730     return GrTextUtils::ShouldDisableLCD(paint);
   1731 }
   1732 
   1733 ///////////////////////////////////////////////////////////////////////////////
   1734 
   1735 void SkGpuDevice::flush() {
   1736     this->flushAndSignalSemaphores(0, nullptr);
   1737 }
   1738 
   1739 bool SkGpuDevice::flushAndSignalSemaphores(int numSemaphores,
   1740                                            GrBackendSemaphore* signalSemaphores) {
   1741     ASSERT_SINGLE_OWNER
   1742 
   1743     return fRenderTargetContext->prepareForExternalIO(numSemaphores, signalSemaphores);
   1744 }
   1745 
   1746 bool SkGpuDevice::wait(int numSemaphores, const GrBackendSemaphore* waitSemaphores) {
   1747     ASSERT_SINGLE_OWNER
   1748 
   1749     return fRenderTargetContext->waitOnSemaphores(numSemaphores, waitSemaphores);
   1750 }
   1751 
   1752 ///////////////////////////////////////////////////////////////////////////////
   1753 
   1754 SkBaseDevice* SkGpuDevice::onCreateDevice(const CreateInfo& cinfo, const SkPaint*) {
   1755     ASSERT_SINGLE_OWNER
   1756 
   1757     SkSurfaceProps props(this->surfaceProps().flags(), cinfo.fPixelGeometry);
   1758 
   1759     // layers are never drawn in repeat modes, so we can request an approx
   1760     // match and ignore any padding.
   1761     SkBackingFit fit = kNever_TileUsage == cinfo.fTileUsage ? SkBackingFit::kApprox
   1762                                                             : SkBackingFit::kExact;
   1763 
   1764     sk_sp<GrRenderTargetContext> rtc(fContext->makeDeferredRenderTargetContext(
   1765                                                    fit,
   1766                                                    cinfo.fInfo.width(), cinfo.fInfo.height(),
   1767                                                    fRenderTargetContext->config(),
   1768                                                    fRenderTargetContext->refColorSpace(),
   1769                                                    fRenderTargetContext->numStencilSamples(),
   1770                                                    kBottomLeft_GrSurfaceOrigin,
   1771                                                    &props));
   1772     if (!rtc) {
   1773         return nullptr;
   1774     }
   1775 
   1776     // Skia's convention is to only clear a device if it is non-opaque.
   1777     InitContents init = cinfo.fInfo.isOpaque() ? kUninit_InitContents : kClear_InitContents;
   1778 
   1779     return SkGpuDevice::Make(fContext.get(), std::move(rtc),
   1780                              cinfo.fInfo.width(), cinfo.fInfo.height(), init).release();
   1781 }
   1782 
   1783 sk_sp<SkSurface> SkGpuDevice::makeSurface(const SkImageInfo& info, const SkSurfaceProps& props) {
   1784     ASSERT_SINGLE_OWNER
   1785     // TODO: Change the signature of newSurface to take a budgeted parameter.
   1786     static const SkBudgeted kBudgeted = SkBudgeted::kNo;
   1787     return SkSurface::MakeRenderTarget(fContext.get(), kBudgeted, info,
   1788                                        fRenderTargetContext->numStencilSamples(),
   1789                                        fRenderTargetContext->origin(), &props);
   1790 }
   1791 
   1792 SkImageFilterCache* SkGpuDevice::getImageFilterCache() {
   1793     ASSERT_SINGLE_OWNER
   1794     // We always return a transient cache, so it is freed after each
   1795     // filter traversal.
   1796     return SkImageFilterCache::Create(SkImageFilterCache::kDefaultTransientSize);
   1797 }
   1798 
   1799 #endif
   1800