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