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