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