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