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