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