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