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