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 "GrBlurUtils.h"
11 #include "GrContext.h"
12 #include "SkDraw.h"
13 #include "GrGpu.h"
14 #include "GrGpuResourcePriv.h"
15 #include "GrImageIDTextureAdjuster.h"
16 #include "GrLayerHoister.h"
17 #include "GrRecordReplaceDraw.h"
18 #include "GrStrokeInfo.h"
19 #include "GrTracing.h"
20 #include "SkCanvasPriv.h"
21 #include "SkErrorInternals.h"
22 #include "SkGlyphCache.h"
23 #include "SkGrTexturePixelRef.h"
24 #include "SkGr.h"
25 #include "SkGrPriv.h"
26 #include "SkImage_Base.h"
27 #include "SkImageCacherator.h"
28 #include "SkImageFilter.h"
29 #include "SkLayerInfo.h"
30 #include "SkMaskFilter.h"
31 #include "SkNinePatchIter.h"
32 #include "SkPathEffect.h"
33 #include "SkPicture.h"
34 #include "SkPictureData.h"
35 #include "SkRRect.h"
36 #include "SkRecord.h"
37 #include "SkStroke.h"
38 #include "SkSurface.h"
39 #include "SkSurface_Gpu.h"
40 #include "SkTLazy.h"
41 #include "SkUtils.h"
42 #include "SkVertState.h"
43 #include "SkXfermode.h"
44 #include "batches/GrRectBatchFactory.h"
45 #include "effects/GrBicubicEffect.h"
46 #include "effects/GrDashingEffect.h"
47 #include "effects/GrRRectEffect.h"
48 #include "effects/GrSimpleTextureEffect.h"
49 #include "effects/GrTextureDomain.h"
50 #include "text/GrTextUtils.h"
51 
52 #if SK_SUPPORT_GPU
53 
54 #define ASSERT_SINGLE_OWNER \
55     SkDEBUGCODE(GrSingleOwner::AutoEnforce debug_SingleOwner(fContext->debugSingleOwner());)
56 
57 enum { kDefaultImageFilterCacheSize = 32 * 1024 * 1024 };
58 
59 #if 0
60     extern bool (*gShouldDrawProc)();
61     #define CHECK_SHOULD_DRAW(draw)                             \
62         do {                                                    \
63             if (gShouldDrawProc && !gShouldDrawProc()) return;  \
64             this->prepareDraw(draw);                            \
65         } while (0)
66 #else
67     #define CHECK_SHOULD_DRAW(draw) this->prepareDraw(draw)
68 #endif
69 
70 ///////////////////////////////////////////////////////////////////////////////
71 
72 #define CHECK_FOR_ANNOTATION(paint) \
73     do { if (paint.getAnnotation()) { return; } } while (0)
74 
75 ///////////////////////////////////////////////////////////////////////////////
76 
77 // Helper for turning a bitmap into a texture. If the bitmap is GrTexture backed this
78 // just accesses the backing GrTexture. Otherwise, it creates a cached texture
79 // representation and releases it in the destructor.
80 class AutoBitmapTexture : public SkNoncopyable {
81 public:
AutoBitmapTexture()82     AutoBitmapTexture() {}
83 
AutoBitmapTexture(GrContext * context,const SkBitmap & bitmap,const GrTextureParams & params,GrTexture ** texture)84     AutoBitmapTexture(GrContext* context,
85                       const SkBitmap& bitmap,
86                       const GrTextureParams& params,
87                       GrTexture** texture) {
88         SkASSERT(texture);
89         *texture = this->set(context, bitmap, params);
90     }
91 
set(GrContext * context,const SkBitmap & bitmap,const GrTextureParams & params)92     GrTexture* set(GrContext* context,
93                    const SkBitmap& bitmap,
94                    const GrTextureParams& params) {
95         // Either get the texture directly from the bitmap, or else use the cache and
96         // remember to unref it.
97         if (GrTexture* bmpTexture = bitmap.getTexture()) {
98             fTexture.reset(nullptr);
99             return bmpTexture;
100         } else {
101             fTexture.reset(GrRefCachedBitmapTexture(context, bitmap, params));
102             return fTexture.get();
103         }
104     }
105 
106 private:
107     SkAutoTUnref<GrTexture> fTexture;
108 };
109 
110 ///////////////////////////////////////////////////////////////////////////////
111 
112 /** Checks that the alpha type is legal and gets constructor flags. Returns false if device creation
113     should fail. */
CheckAlphaTypeAndGetFlags(const SkImageInfo * info,SkGpuDevice::InitContents init,unsigned * flags)114 bool SkGpuDevice::CheckAlphaTypeAndGetFlags(
115                         const SkImageInfo* info, SkGpuDevice::InitContents init, unsigned* flags) {
116     *flags = 0;
117     if (info) {
118         switch (info->alphaType()) {
119             case kPremul_SkAlphaType:
120                 break;
121             case kOpaque_SkAlphaType:
122                 *flags |= SkGpuDevice::kIsOpaque_Flag;
123                 break;
124             default: // If it is unpremul or unknown don't try to render
125                 return false;
126         }
127     }
128     if (kClear_InitContents == init) {
129         *flags |= kNeedClear_Flag;
130     }
131     return true;
132 }
133 
Create(GrRenderTarget * rt,const SkSurfaceProps * props,InitContents init)134 SkGpuDevice* SkGpuDevice::Create(GrRenderTarget* rt, const SkSurfaceProps* props,
135                                  InitContents init) {
136     return SkGpuDevice::Create(rt, rt->width(), rt->height(), props, init);
137 }
138 
Create(GrRenderTarget * rt,int width,int height,const SkSurfaceProps * props,InitContents init)139 SkGpuDevice* SkGpuDevice::Create(GrRenderTarget* rt, int width, int height,
140                                  const SkSurfaceProps* props, InitContents init) {
141     if (!rt || rt->wasDestroyed()) {
142         return nullptr;
143     }
144     unsigned flags;
145     if (!CheckAlphaTypeAndGetFlags(nullptr, init, &flags)) {
146         return nullptr;
147     }
148     return new SkGpuDevice(rt, width, height, props, flags);
149 }
150 
Create(GrContext * context,SkBudgeted budgeted,const SkImageInfo & info,int sampleCount,const SkSurfaceProps * props,InitContents init,GrTextureStorageAllocator customAllocator)151 SkGpuDevice* SkGpuDevice::Create(GrContext* context, SkBudgeted budgeted,
152                                  const SkImageInfo& info, int sampleCount,
153                                  const SkSurfaceProps* props, InitContents init,
154                                  GrTextureStorageAllocator customAllocator) {
155     unsigned flags;
156     if (!CheckAlphaTypeAndGetFlags(&info, init, &flags)) {
157         return nullptr;
158     }
159 
160     SkAutoTUnref<GrRenderTarget> rt(CreateRenderTarget(
161             context, budgeted, info, sampleCount, customAllocator));
162     if (nullptr == rt) {
163         return nullptr;
164     }
165 
166     return new SkGpuDevice(rt, info.width(), info.height(), props, flags);
167 }
168 
SkGpuDevice(GrRenderTarget * rt,int width,int height,const SkSurfaceProps * props,unsigned flags)169 SkGpuDevice::SkGpuDevice(GrRenderTarget* rt, int width, int height,
170                          const SkSurfaceProps* props, unsigned flags)
171     : INHERITED(SkSurfacePropsCopyOrDefault(props))
172     , fContext(SkRef(rt->getContext()))
173     , fRenderTarget(SkRef(rt)) {
174     fOpaque = SkToBool(flags & kIsOpaque_Flag);
175 
176     SkAlphaType at = fOpaque ? kOpaque_SkAlphaType : kPremul_SkAlphaType;
177     SkImageInfo info = rt->surfacePriv().info(at).makeWH(width, height);
178     SkPixelRef* pr = new SkGrPixelRef(info, rt);
179     fLegacyBitmap.setInfo(info);
180     fLegacyBitmap.setPixelRef(pr)->unref();
181 
182     fDrawContext.reset(this->context()->drawContext(rt, &this->surfaceProps()));
183     if (flags & kNeedClear_Flag) {
184         this->clearAll();
185     }
186 }
187 
CreateRenderTarget(GrContext * context,SkBudgeted budgeted,const SkImageInfo & origInfo,int sampleCount,GrTextureStorageAllocator textureStorageAllocator)188 GrRenderTarget* SkGpuDevice::CreateRenderTarget(
189         GrContext* context, SkBudgeted budgeted, const SkImageInfo& origInfo,
190         int sampleCount, GrTextureStorageAllocator textureStorageAllocator) {
191     if (kUnknown_SkColorType == origInfo.colorType() ||
192         origInfo.width() < 0 || origInfo.height() < 0) {
193         return nullptr;
194     }
195 
196     if (!context) {
197         return nullptr;
198     }
199 
200     SkColorType ct = origInfo.colorType();
201     SkAlphaType at = origInfo.alphaType();
202     if (kRGB_565_SkColorType == ct) {
203         at = kOpaque_SkAlphaType;  // force this setting
204     } else if (ct != kBGRA_8888_SkColorType && ct != kRGBA_8888_SkColorType) {
205         // Fall back from whatever ct was to default of kRGBA or kBGRA which is aliased as kN32
206         ct = kN32_SkColorType;
207     }
208     if (kOpaque_SkAlphaType != at) {
209         at = kPremul_SkAlphaType;  // force this setting
210     }
211     const SkImageInfo info = SkImageInfo::Make(origInfo.width(), origInfo.height(), ct, at);
212 
213     GrSurfaceDesc desc;
214     desc.fFlags = kRenderTarget_GrSurfaceFlag;
215     desc.fWidth = info.width();
216     desc.fHeight = info.height();
217     desc.fConfig = SkImageInfo2GrPixelConfig(info);
218     desc.fSampleCnt = sampleCount;
219     desc.fTextureStorageAllocator = textureStorageAllocator;
220     GrTexture* texture = context->textureProvider()->createTexture(desc, budgeted, nullptr, 0);
221     if (nullptr == texture) {
222         return nullptr;
223     }
224     SkASSERT(nullptr != texture->asRenderTarget());
225     return texture->asRenderTarget();
226 }
227 
228 ///////////////////////////////////////////////////////////////////////////////
229 
onReadPixels(const SkImageInfo & dstInfo,void * dstPixels,size_t dstRowBytes,int x,int y)230 bool SkGpuDevice::onReadPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRowBytes,
231                                int x, int y) {
232     ASSERT_SINGLE_OWNER
233 
234     // TODO: teach fRenderTarget to take ImageInfo directly to specify the src pixels
235     GrPixelConfig config = SkImageInfo2GrPixelConfig(dstInfo);
236     if (kUnknown_GrPixelConfig == config) {
237         return false;
238     }
239 
240     uint32_t flags = 0;
241     if (kUnpremul_SkAlphaType == dstInfo.alphaType()) {
242         flags = GrContext::kUnpremul_PixelOpsFlag;
243     }
244     return fRenderTarget->readPixels(x, y, dstInfo.width(), dstInfo.height(), config, dstPixels,
245                                      dstRowBytes, flags);
246 }
247 
onWritePixels(const SkImageInfo & info,const void * pixels,size_t rowBytes,int x,int y)248 bool SkGpuDevice::onWritePixels(const SkImageInfo& info, const void* pixels, size_t rowBytes,
249                                 int x, int y) {
250     ASSERT_SINGLE_OWNER
251     // TODO: teach fRenderTarget to take ImageInfo directly to specify the src pixels
252     GrPixelConfig config = SkImageInfo2GrPixelConfig(info);
253     if (kUnknown_GrPixelConfig == config) {
254         return false;
255     }
256     uint32_t flags = 0;
257     if (kUnpremul_SkAlphaType == info.alphaType()) {
258         flags = GrContext::kUnpremul_PixelOpsFlag;
259     }
260     fRenderTarget->writePixels(x, y, info.width(), info.height(), config, pixels, rowBytes, flags);
261 
262     // need to bump our genID for compatibility with clients that "know" we have a bitmap
263     fLegacyBitmap.notifyPixelsChanged();
264 
265     return true;
266 }
267 
onAccessBitmap()268 const SkBitmap& SkGpuDevice::onAccessBitmap() {
269     ASSERT_SINGLE_OWNER
270     return fLegacyBitmap;
271 }
272 
onAccessPixels(SkPixmap * pmap)273 bool SkGpuDevice::onAccessPixels(SkPixmap* pmap) {
274     ASSERT_SINGLE_OWNER
275     // For compatibility with clients the know we're backed w/ a bitmap, and want to inspect its
276     // genID. When we can hide/remove that fact, we can eliminate this call to notify.
277     // ... ugh.
278     fLegacyBitmap.notifyPixelsChanged();
279     return false;
280 }
281 
onAttachToCanvas(SkCanvas * canvas)282 void SkGpuDevice::onAttachToCanvas(SkCanvas* canvas) {
283     ASSERT_SINGLE_OWNER
284     INHERITED::onAttachToCanvas(canvas);
285 
286     // Canvas promises that this ptr is valid until onDetachFromCanvas is called
287     fClipStack.reset(SkRef(canvas->getClipStack()));
288 }
289 
onDetachFromCanvas()290 void SkGpuDevice::onDetachFromCanvas() {
291     ASSERT_SINGLE_OWNER
292     INHERITED::onDetachFromCanvas();
293     fClip.reset();
294     fClipStack.reset(nullptr);
295 }
296 
297 // call this every draw call, to ensure that the context reflects our state,
298 // and not the state from some other canvas/device
prepareDraw(const SkDraw & draw)299 void SkGpuDevice::prepareDraw(const SkDraw& draw) {
300     ASSERT_SINGLE_OWNER
301     SkASSERT(fClipStack.get());
302 
303     SkASSERT(draw.fClipStack && draw.fClipStack == fClipStack);
304 
305     fClip.setClipStack(fClipStack, &this->getOrigin());
306 }
307 
accessRenderTarget()308 GrRenderTarget* SkGpuDevice::accessRenderTarget() {
309     ASSERT_SINGLE_OWNER
310     return fRenderTarget;
311 }
312 
clearAll()313 void SkGpuDevice::clearAll() {
314     ASSERT_SINGLE_OWNER
315     GrColor color = 0;
316     GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "clearAll", fContext);
317     SkIRect rect = SkIRect::MakeWH(this->width(), this->height());
318     fDrawContext->clear(&rect, color, true);
319 }
320 
replaceRenderTarget(bool shouldRetainContent)321 void SkGpuDevice::replaceRenderTarget(bool shouldRetainContent) {
322     ASSERT_SINGLE_OWNER
323 
324     SkBudgeted budgeted = fRenderTarget->resourcePriv().isBudgeted();
325 
326     SkAutoTUnref<GrRenderTarget> newRT(CreateRenderTarget(
327         this->context(), budgeted, this->imageInfo(), fRenderTarget->desc().fSampleCnt,
328         fRenderTarget->desc().fTextureStorageAllocator));
329 
330     if (nullptr == newRT) {
331         return;
332     }
333 
334     if (shouldRetainContent) {
335         if (fRenderTarget->wasDestroyed()) {
336             return;
337         }
338         this->context()->copySurface(newRT, fRenderTarget);
339     }
340 
341     SkASSERT(fRenderTarget != newRT);
342 
343     fRenderTarget.reset(newRT.detach());
344 
345 #ifdef SK_DEBUG
346     SkImageInfo info = fRenderTarget->surfacePriv().info(fOpaque ? kOpaque_SkAlphaType :
347                                                                    kPremul_SkAlphaType);
348     SkASSERT(info == fLegacyBitmap.info());
349 #endif
350     SkPixelRef* pr = new SkGrPixelRef(fLegacyBitmap.info(), fRenderTarget);
351     fLegacyBitmap.setPixelRef(pr)->unref();
352 
353     fDrawContext.reset(this->context()->drawContext(fRenderTarget, &this->surfaceProps()));
354 }
355 
356 ///////////////////////////////////////////////////////////////////////////////
357 
drawPaint(const SkDraw & draw,const SkPaint & paint)358 void SkGpuDevice::drawPaint(const SkDraw& draw, const SkPaint& paint) {
359     ASSERT_SINGLE_OWNER
360     CHECK_SHOULD_DRAW(draw);
361     GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawPaint", fContext);
362 
363     GrPaint grPaint;
364     if (!SkPaintToGrPaint(this->context(), paint, *draw.fMatrix, &grPaint)) {
365         return;
366     }
367 
368     fDrawContext->drawPaint(fClip, grPaint, *draw.fMatrix);
369 }
370 
371 // must be in SkCanvas::PointMode order
372 static const GrPrimitiveType gPointMode2PrimtiveType[] = {
373     kPoints_GrPrimitiveType,
374     kLines_GrPrimitiveType,
375     kLineStrip_GrPrimitiveType
376 };
377 
378 // suppress antialiasing on axis-aligned integer-coordinate lines
needs_antialiasing(SkCanvas::PointMode mode,size_t count,const SkPoint pts[])379 static bool needs_antialiasing(SkCanvas::PointMode mode, size_t count, const SkPoint pts[]) {
380     if (mode == SkCanvas::PointMode::kPoints_PointMode) {
381         return false;
382     }
383     if (count == 2) {
384         // We do not antialias as long as the primary axis of the line is integer-aligned, even if
385         // the other coordinates are not. This does mean the two end pixels of the line will be
386         // sharp even when they shouldn't be, but turning antialiasing on (as things stand
387         // currently) means that the line will turn into a two-pixel-wide blur. While obviously a
388         // more complete fix is possible down the road, for the time being we accept the error on
389         // the two end pixels as being the lesser of two evils.
390         if (pts[0].fX == pts[1].fX) {
391             return ((int) pts[0].fX) != pts[0].fX;
392         }
393         if (pts[0].fY == pts[1].fY) {
394             return ((int) pts[0].fY) != pts[0].fY;
395         }
396     }
397     return true;
398 }
399 
drawPoints(const SkDraw & draw,SkCanvas::PointMode mode,size_t count,const SkPoint pts[],const SkPaint & paint)400 void SkGpuDevice::drawPoints(const SkDraw& draw, SkCanvas::PointMode mode,
401                              size_t count, const SkPoint pts[], const SkPaint& paint) {
402     ASSERT_SINGLE_OWNER
403     GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawPoints", fContext);
404     CHECK_FOR_ANNOTATION(paint);
405     CHECK_SHOULD_DRAW(draw);
406 
407     SkScalar width = paint.getStrokeWidth();
408     if (width < 0) {
409         return;
410     }
411 
412     if (paint.getPathEffect() && 2 == count && SkCanvas::kLines_PointMode == mode) {
413         GrStrokeInfo strokeInfo(paint, SkPaint::kStroke_Style);
414         GrPaint grPaint;
415         if (!SkPaintToGrPaint(this->context(), paint, *draw.fMatrix, &grPaint)) {
416             return;
417         }
418         SkPath path;
419         path.setIsVolatile(true);
420         path.moveTo(pts[0]);
421         path.lineTo(pts[1]);
422         fDrawContext->drawPath(fClip, grPaint, *draw.fMatrix, path, strokeInfo);
423         return;
424     }
425 
426     // we only handle non-antialiased hairlines and paints without path effects or mask filters,
427     // else we let the SkDraw call our drawPath()
428     if (width > 0 || paint.getPathEffect() || paint.getMaskFilter() ||
429         (paint.isAntiAlias() && needs_antialiasing(mode, count, pts))) {
430         draw.drawPoints(mode, count, pts, paint, true);
431         return;
432     }
433 
434     GrPaint grPaint;
435     if (!SkPaintToGrPaint(this->context(), paint, *draw.fMatrix, &grPaint)) {
436         return;
437     }
438 
439     fDrawContext->drawVertices(fClip,
440                                grPaint,
441                                *draw.fMatrix,
442                                gPointMode2PrimtiveType[mode],
443                                SkToS32(count),
444                                (SkPoint*)pts,
445                                nullptr,
446                                nullptr,
447                                nullptr,
448                                0);
449 }
450 
451 ///////////////////////////////////////////////////////////////////////////////
452 
drawRect(const SkDraw & draw,const SkRect & rect,const SkPaint & paint)453 void SkGpuDevice::drawRect(const SkDraw& draw, const SkRect& rect, const SkPaint& paint) {
454     ASSERT_SINGLE_OWNER
455     GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawRect", fContext);
456     CHECK_FOR_ANNOTATION(paint);
457     CHECK_SHOULD_DRAW(draw);
458 
459     bool doStroke = paint.getStyle() != SkPaint::kFill_Style;
460     SkScalar width = paint.getStrokeWidth();
461 
462     /*
463         We have special code for hairline strokes, miter-strokes, bevel-stroke
464         and fills. Anything else we just call our path code.
465      */
466     bool usePath = doStroke && width > 0 &&
467                    (paint.getStrokeJoin() == SkPaint::kRound_Join ||
468                     (paint.getStrokeJoin() == SkPaint::kBevel_Join && rect.isEmpty()));
469 
470     // a few other reasons we might need to call drawPath...
471     if (paint.getMaskFilter() || paint.getPathEffect() ||
472         paint.getStyle() == SkPaint::kStrokeAndFill_Style) { // we can't both stroke and fill rects
473         usePath = true;
474     }
475 
476     if (usePath) {
477         SkPath path;
478         path.setIsVolatile(true);
479         path.addRect(rect);
480         GrBlurUtils::drawPathWithMaskFilter(fContext, fDrawContext,
481                                             fClip, path, paint,
482                                             *draw.fMatrix, nullptr,
483                                             draw.fClip->getBounds(), true);
484         return;
485     }
486 
487     GrPaint grPaint;
488     if (!SkPaintToGrPaint(this->context(), paint, *draw.fMatrix, &grPaint)) {
489         return;
490     }
491 
492     GrStrokeInfo strokeInfo(paint);
493 
494     fDrawContext->drawRect(fClip, grPaint, *draw.fMatrix, rect, &strokeInfo);
495 }
496 
497 ///////////////////////////////////////////////////////////////////////////////
498 
drawRRect(const SkDraw & draw,const SkRRect & rect,const SkPaint & paint)499 void SkGpuDevice::drawRRect(const SkDraw& draw, const SkRRect& rect,
500                             const SkPaint& paint) {
501     ASSERT_SINGLE_OWNER
502     GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawRRect", fContext);
503     CHECK_FOR_ANNOTATION(paint);
504     CHECK_SHOULD_DRAW(draw);
505 
506     GrPaint grPaint;
507     if (!SkPaintToGrPaint(this->context(), paint, *draw.fMatrix, &grPaint)) {
508         return;
509     }
510 
511     GrStrokeInfo strokeInfo(paint);
512     if (paint.getMaskFilter()) {
513         // try to hit the fast path for drawing filtered round rects
514 
515         SkRRect devRRect;
516         if (rect.transform(*draw.fMatrix, &devRRect)) {
517             if (devRRect.allCornersCircular()) {
518                 SkRect maskRect;
519                 if (paint.getMaskFilter()->canFilterMaskGPU(devRRect,
520                                                             draw.fClip->getBounds(),
521                                                             *draw.fMatrix,
522                                                             &maskRect)) {
523                     SkIRect finalIRect;
524                     maskRect.roundOut(&finalIRect);
525                     if (draw.fClip->quickReject(finalIRect)) {
526                         // clipped out
527                         return;
528                     }
529                     if (paint.getMaskFilter()->directFilterRRectMaskGPU(fContext->textureProvider(),
530                                                                         fDrawContext,
531                                                                         &grPaint,
532                                                                         fClip,
533                                                                         *draw.fMatrix,
534                                                                         strokeInfo,
535                                                                         devRRect)) {
536                         return;
537                     }
538                 }
539 
540             }
541         }
542     }
543 
544     if (paint.getMaskFilter() || paint.getPathEffect()) {
545         // The only mask filter the native rrect drawing code could've handle was taken
546         // care of above.
547         // A path effect will presumably transform this rrect into something else.
548         SkPath path;
549         path.setIsVolatile(true);
550         path.addRRect(rect);
551         GrBlurUtils::drawPathWithMaskFilter(fContext, fDrawContext,
552                                             fClip, path, paint,
553                                             *draw.fMatrix, nullptr,
554                                             draw.fClip->getBounds(), true);
555         return;
556     }
557 
558     SkASSERT(!strokeInfo.isDashed());
559 
560     fDrawContext->drawRRect(fClip, grPaint, *draw.fMatrix, rect, strokeInfo);
561 }
562 
drawFilledDRRect(const SkMatrix & viewMatrix,const SkRRect & origOuter,const SkRRect & origInner,const SkPaint & paint)563 bool SkGpuDevice::drawFilledDRRect(const SkMatrix& viewMatrix, const SkRRect& origOuter,
564                                    const SkRRect& origInner, const SkPaint& paint) {
565     SkASSERT(!origInner.isEmpty());
566     SkASSERT(!origOuter.isEmpty());
567 
568     bool applyAA = paint.isAntiAlias() && !fRenderTarget->isUnifiedMultisampled();
569 
570     GrPrimitiveEdgeType innerEdgeType = applyAA ? kInverseFillAA_GrProcessorEdgeType :
571                                                   kInverseFillBW_GrProcessorEdgeType;
572     GrPrimitiveEdgeType outerEdgeType = applyAA ? kFillAA_GrProcessorEdgeType :
573                                                   kFillBW_GrProcessorEdgeType;
574 
575     SkTCopyOnFirstWrite<SkRRect> inner(origInner), outer(origOuter);
576     SkMatrix inverseVM;
577     if (!viewMatrix.isIdentity()) {
578         if (!origInner.transform(viewMatrix, inner.writable())) {
579             return false;
580         }
581         if (!origOuter.transform(viewMatrix, outer.writable())) {
582             return false;
583         }
584         if (!viewMatrix.invert(&inverseVM)) {
585             return false;
586         }
587     } else {
588         inverseVM.reset();
589     }
590 
591     GrPaint grPaint;
592 
593     if (!SkPaintToGrPaint(this->context(), paint, viewMatrix, &grPaint)) {
594         return false;
595     }
596 
597     grPaint.setAntiAlias(false);
598 
599     // TODO these need to be a geometry processors
600     SkAutoTUnref<GrFragmentProcessor> innerEffect(GrRRectEffect::Create(innerEdgeType, *inner));
601     if (!innerEffect) {
602         return false;
603     }
604 
605     SkAutoTUnref<GrFragmentProcessor> outerEffect(GrRRectEffect::Create(outerEdgeType, *outer));
606     if (!outerEffect) {
607         return false;
608     }
609 
610     grPaint.addCoverageFragmentProcessor(innerEffect);
611     grPaint.addCoverageFragmentProcessor(outerEffect);
612 
613     SkRect bounds = outer->getBounds();
614     if (applyAA) {
615         bounds.outset(SK_ScalarHalf, SK_ScalarHalf);
616     }
617 
618     fDrawContext->fillRectWithLocalMatrix(fClip, grPaint, SkMatrix::I(), bounds, inverseVM);
619     return true;
620 }
621 
622 
drawDRRect(const SkDraw & draw,const SkRRect & outer,const SkRRect & inner,const SkPaint & paint)623 void SkGpuDevice::drawDRRect(const SkDraw& draw, const SkRRect& outer,
624                              const SkRRect& inner, const SkPaint& paint) {
625     ASSERT_SINGLE_OWNER
626     GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawDRRect", fContext);
627     CHECK_FOR_ANNOTATION(paint);
628     CHECK_SHOULD_DRAW(draw);
629 
630     if (outer.isEmpty()) {
631        return;
632     }
633 
634     if (inner.isEmpty()) {
635         return this->drawRRect(draw, outer, paint);
636     }
637 
638     SkStrokeRec stroke(paint);
639 
640     if (stroke.isFillStyle() && !paint.getMaskFilter() && !paint.getPathEffect()) {
641         if (this->drawFilledDRRect(*draw.fMatrix, outer, inner, paint)) {
642             return;
643         }
644     }
645 
646     SkPath path;
647     path.setIsVolatile(true);
648     path.addRRect(outer);
649     path.addRRect(inner);
650     path.setFillType(SkPath::kEvenOdd_FillType);
651 
652     GrBlurUtils::drawPathWithMaskFilter(fContext, fDrawContext,
653                                         fClip, path, paint,
654                                         *draw.fMatrix, nullptr,
655                                         draw.fClip->getBounds(), true);
656 }
657 
658 
659 /////////////////////////////////////////////////////////////////////////////
660 
drawOval(const SkDraw & draw,const SkRect & oval,const SkPaint & paint)661 void SkGpuDevice::drawOval(const SkDraw& draw, const SkRect& oval, const SkPaint& paint) {
662     ASSERT_SINGLE_OWNER
663     GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawOval", fContext);
664     CHECK_FOR_ANNOTATION(paint);
665     CHECK_SHOULD_DRAW(draw);
666 
667     // Presumably the path effect warps this to something other than an oval
668     if (paint.getPathEffect()) {
669         SkPath path;
670         path.setIsVolatile(true);
671         path.addOval(oval);
672         this->drawPath(draw, path, paint, nullptr, true);
673         return;
674     }
675 
676     if (paint.getMaskFilter()) {
677         // The RRect path can handle special case blurring
678         SkRRect rr = SkRRect::MakeOval(oval);
679         return this->drawRRect(draw, rr, paint);
680     }
681 
682     GrPaint grPaint;
683     if (!SkPaintToGrPaint(this->context(), paint, *draw.fMatrix, &grPaint)) {
684         return;
685     }
686 
687     GrStrokeInfo strokeInfo(paint);
688     SkASSERT(!strokeInfo.isDashed());
689 
690     fDrawContext->drawOval(fClip, grPaint, *draw.fMatrix, oval, strokeInfo);
691 }
692 
693 #include "SkMaskFilter.h"
694 
695 ///////////////////////////////////////////////////////////////////////////////
696 
drawPath(const SkDraw & draw,const SkPath & origSrcPath,const SkPaint & paint,const SkMatrix * prePathMatrix,bool pathIsMutable)697 void SkGpuDevice::drawPath(const SkDraw& draw, const SkPath& origSrcPath,
698                            const SkPaint& paint, const SkMatrix* prePathMatrix,
699                            bool pathIsMutable) {
700     ASSERT_SINGLE_OWNER
701     if (!origSrcPath.isInverseFillType() && !paint.getPathEffect() && !prePathMatrix) {
702         bool isClosed;
703         SkRect rect;
704         if (origSrcPath.isRect(&rect, &isClosed) && isClosed) {
705             this->drawRect(draw, rect, paint);
706             return;
707         }
708         if (origSrcPath.isOval(&rect)) {
709             this->drawOval(draw, rect, paint);
710             return;
711         }
712         SkRRect rrect;
713         if (origSrcPath.isRRect(&rrect)) {
714             this->drawRRect(draw, rrect, paint);
715             return;
716         }
717     }
718 
719     CHECK_FOR_ANNOTATION(paint);
720     CHECK_SHOULD_DRAW(draw);
721     GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawPath", fContext);
722 
723     GrBlurUtils::drawPathWithMaskFilter(fContext, fDrawContext,
724                                         fClip, origSrcPath, paint,
725                                         *draw.fMatrix, prePathMatrix,
726                                         draw.fClip->getBounds(), pathIsMutable);
727 }
728 
729 static const int kBmpSmallTileSize = 1 << 10;
730 
get_tile_count(const SkIRect & srcRect,int tileSize)731 static inline int get_tile_count(const SkIRect& srcRect, int tileSize)  {
732     int tilesX = (srcRect.fRight / tileSize) - (srcRect.fLeft / tileSize) + 1;
733     int tilesY = (srcRect.fBottom / tileSize) - (srcRect.fTop / tileSize) + 1;
734     return tilesX * tilesY;
735 }
736 
determine_tile_size(const SkIRect & src,int maxTileSize)737 static int determine_tile_size(const SkIRect& src, int maxTileSize) {
738     if (maxTileSize <= kBmpSmallTileSize) {
739         return maxTileSize;
740     }
741 
742     size_t maxTileTotalTileSize = get_tile_count(src, maxTileSize);
743     size_t smallTotalTileSize = get_tile_count(src, kBmpSmallTileSize);
744 
745     maxTileTotalTileSize *= maxTileSize * maxTileSize;
746     smallTotalTileSize *= kBmpSmallTileSize * kBmpSmallTileSize;
747 
748     if (maxTileTotalTileSize > 2 * smallTotalTileSize) {
749         return kBmpSmallTileSize;
750     } else {
751         return maxTileSize;
752     }
753 }
754 
755 // Given a bitmap, an optional src rect, and a context with a clip and matrix determine what
756 // pixels from the bitmap are necessary.
determine_clipped_src_rect(const GrRenderTarget * rt,const GrClip & clip,const SkMatrix & viewMatrix,const SkISize & imageSize,const SkRect * srcRectPtr,SkIRect * clippedSrcIRect)757 static void determine_clipped_src_rect(const GrRenderTarget* rt,
758                                        const GrClip& clip,
759                                        const SkMatrix& viewMatrix,
760                                        const SkISize& imageSize,
761                                        const SkRect* srcRectPtr,
762                                        SkIRect* clippedSrcIRect) {
763     clip.getConservativeBounds(rt->width(), rt->height(), clippedSrcIRect, nullptr);
764     SkMatrix inv;
765     if (!viewMatrix.invert(&inv)) {
766         clippedSrcIRect->setEmpty();
767         return;
768     }
769     SkRect clippedSrcRect = SkRect::Make(*clippedSrcIRect);
770     inv.mapRect(&clippedSrcRect);
771     if (srcRectPtr) {
772         // we've setup src space 0,0 to map to the top left of the src rect.
773         clippedSrcRect.offset(srcRectPtr->fLeft, srcRectPtr->fTop);
774         if (!clippedSrcRect.intersect(*srcRectPtr)) {
775             clippedSrcIRect->setEmpty();
776             return;
777         }
778     }
779     clippedSrcRect.roundOut(clippedSrcIRect);
780     SkIRect bmpBounds = SkIRect::MakeSize(imageSize);
781     if (!clippedSrcIRect->intersect(bmpBounds)) {
782         clippedSrcIRect->setEmpty();
783     }
784 }
785 
shouldTileImageID(uint32_t imageID,const SkIRect & imageRect,const SkMatrix & viewMatrix,const GrTextureParams & params,const SkRect * srcRectPtr,int maxTileSize,int * tileSize,SkIRect * clippedSubset) const786 bool SkGpuDevice::shouldTileImageID(uint32_t imageID, const SkIRect& imageRect,
787                                     const SkMatrix& viewMatrix,
788                                     const GrTextureParams& params,
789                                     const SkRect* srcRectPtr,
790                                     int maxTileSize,
791                                     int* tileSize,
792                                     SkIRect* clippedSubset) const {
793     ASSERT_SINGLE_OWNER
794     // if it's larger than the max tile size, then we have no choice but tiling.
795     if (imageRect.width() > maxTileSize || imageRect.height() > maxTileSize) {
796         determine_clipped_src_rect(fRenderTarget, fClip, viewMatrix, imageRect.size(),
797                                    srcRectPtr, clippedSubset);
798         *tileSize = determine_tile_size(*clippedSubset, maxTileSize);
799         return true;
800     }
801 
802     // If the image would only produce 4 tiles of the smaller size, don't bother tiling it.
803     const size_t area = imageRect.width() * imageRect.height();
804     if (area < 4 * kBmpSmallTileSize * kBmpSmallTileSize) {
805         return false;
806     }
807 
808     // At this point we know we could do the draw by uploading the entire bitmap
809     // as a texture. However, if the texture would be large compared to the
810     // cache size and we don't require most of it for this draw then tile to
811     // reduce the amount of upload and cache spill.
812 
813     // assumption here is that sw bitmap size is a good proxy for its size as
814     // a texture
815     size_t bmpSize = area * sizeof(SkPMColor);  // assume 32bit pixels
816     size_t cacheSize;
817     fContext->getResourceCacheLimits(nullptr, &cacheSize);
818     if (bmpSize < cacheSize / 2) {
819         return false;
820     }
821 
822     // Figure out how much of the src we will need based on the src rect and clipping. Reject if
823     // tiling memory savings would be < 50%.
824     determine_clipped_src_rect(fRenderTarget, fClip, viewMatrix, imageRect.size(), srcRectPtr,
825                                clippedSubset);
826     *tileSize = kBmpSmallTileSize; // already know whole bitmap fits in one max sized tile.
827     size_t usedTileBytes = get_tile_count(*clippedSubset, kBmpSmallTileSize) *
828                            kBmpSmallTileSize * kBmpSmallTileSize;
829 
830     return usedTileBytes < 2 * bmpSize;
831 }
832 
shouldTileBitmap(const SkBitmap & bitmap,const SkMatrix & viewMatrix,const GrTextureParams & params,const SkRect * srcRectPtr,int maxTileSize,int * tileSize,SkIRect * clippedSrcRect) const833 bool SkGpuDevice::shouldTileBitmap(const SkBitmap& bitmap,
834                                    const SkMatrix& viewMatrix,
835                                    const GrTextureParams& params,
836                                    const SkRect* srcRectPtr,
837                                    int maxTileSize,
838                                    int* tileSize,
839                                    SkIRect* clippedSrcRect) const {
840     ASSERT_SINGLE_OWNER
841     // if bitmap is explictly texture backed then just use the texture
842     if (bitmap.getTexture()) {
843         return false;
844     }
845 
846     return this->shouldTileImageID(bitmap.getGenerationID(), bitmap.getSubset(), viewMatrix, params,
847                                    srcRectPtr, maxTileSize, tileSize, clippedSrcRect);
848 }
849 
shouldTileImage(const SkImage * image,const SkRect * srcRectPtr,SkCanvas::SrcRectConstraint constraint,SkFilterQuality quality,const SkMatrix & viewMatrix) const850 bool SkGpuDevice::shouldTileImage(const SkImage* image, const SkRect* srcRectPtr,
851                                   SkCanvas::SrcRectConstraint constraint, SkFilterQuality quality,
852                                   const SkMatrix& viewMatrix) const {
853     ASSERT_SINGLE_OWNER
854     // if image is explictly texture backed then just use the texture
855     if (as_IB(image)->peekTexture()) {
856         return false;
857     }
858 
859     GrTextureParams params;
860     bool doBicubic;
861     GrTextureParams::FilterMode textureFilterMode =
862                     GrSkFilterQualityToGrFilterMode(quality, viewMatrix, SkMatrix::I(), &doBicubic);
863 
864     int tileFilterPad;
865     if (doBicubic) {
866         tileFilterPad = GrBicubicEffect::kFilterTexelPad;
867     } else if (GrTextureParams::kNone_FilterMode == textureFilterMode) {
868         tileFilterPad = 0;
869     } else {
870         tileFilterPad = 1;
871     }
872     params.setFilterMode(textureFilterMode);
873 
874     int maxTileSize = fContext->caps()->maxTileSize() - 2 * tileFilterPad;
875 
876     // these are output, which we safely ignore, as we just want to know the predicate
877     int outTileSize;
878     SkIRect outClippedSrcRect;
879 
880     return this->shouldTileImageID(image->unique(), image->bounds(), viewMatrix, params, srcRectPtr,
881                                    maxTileSize, &outTileSize, &outClippedSrcRect);
882 }
883 
drawBitmap(const SkDraw & origDraw,const SkBitmap & bitmap,const SkMatrix & m,const SkPaint & paint)884 void SkGpuDevice::drawBitmap(const SkDraw& origDraw,
885                              const SkBitmap& bitmap,
886                              const SkMatrix& m,
887                              const SkPaint& paint) {
888     ASSERT_SINGLE_OWNER
889     CHECK_SHOULD_DRAW(origDraw);
890     SkMatrix viewMatrix;
891     viewMatrix.setConcat(*origDraw.fMatrix, m);
892     if (bitmap.getTexture()) {
893         GrBitmapTextureAdjuster adjuster(&bitmap);
894         // We can use kFast here because we know texture-backed bitmaps don't support extractSubset.
895         this->drawTextureProducer(&adjuster, nullptr, nullptr, SkCanvas::kFast_SrcRectConstraint,
896                                   viewMatrix, fClip, paint);
897         return;
898     }
899     int maxTileSize = fContext->caps()->maxTileSize();
900 
901     // The tile code path doesn't currently support AA, so if the paint asked for aa and we could
902     // draw untiled, then we bypass checking for tiling purely for optimization reasons.
903     bool drawAA = !fRenderTarget->isUnifiedMultisampled() &&
904                   paint.isAntiAlias() &&
905                   bitmap.width() <= maxTileSize &&
906                   bitmap.height() <= maxTileSize;
907 
908     bool skipTileCheck = drawAA || paint.getMaskFilter();
909 
910     if (!skipTileCheck) {
911         SkRect srcRect = SkRect::MakeIWH(bitmap.width(), bitmap.height());
912         int tileSize;
913         SkIRect clippedSrcRect;
914 
915         GrTextureParams params;
916         bool doBicubic;
917         GrTextureParams::FilterMode textureFilterMode =
918             GrSkFilterQualityToGrFilterMode(paint.getFilterQuality(), viewMatrix, SkMatrix::I(),
919                                             &doBicubic);
920 
921         int tileFilterPad;
922 
923         if (doBicubic) {
924             tileFilterPad = GrBicubicEffect::kFilterTexelPad;
925         } else if (GrTextureParams::kNone_FilterMode == textureFilterMode) {
926             tileFilterPad = 0;
927         } else {
928             tileFilterPad = 1;
929         }
930         params.setFilterMode(textureFilterMode);
931 
932         int maxTileSizeForFilter = fContext->caps()->maxTileSize() - 2 * tileFilterPad;
933         if (this->shouldTileBitmap(bitmap, viewMatrix, params, &srcRect,
934                                    maxTileSizeForFilter, &tileSize, &clippedSrcRect)) {
935             this->drawTiledBitmap(bitmap, viewMatrix, srcRect, clippedSrcRect, params, paint,
936                                   SkCanvas::kStrict_SrcRectConstraint, tileSize, doBicubic);
937             return;
938         }
939     }
940     GrBitmapTextureMaker maker(fContext, bitmap);
941     this->drawTextureProducer(&maker, nullptr, nullptr, SkCanvas::kStrict_SrcRectConstraint,
942                               viewMatrix, fClip, paint);
943 }
944 
945 // This method outsets 'iRect' by 'outset' all around and then clamps its extents to
946 // 'clamp'. 'offset' is adjusted to remain positioned over the top-left corner
947 // of 'iRect' for all possible outsets/clamps.
clamped_outset_with_offset(SkIRect * iRect,int outset,SkPoint * offset,const SkIRect & clamp)948 static inline void clamped_outset_with_offset(SkIRect* iRect,
949                                               int outset,
950                                               SkPoint* offset,
951                                               const SkIRect& clamp) {
952     iRect->outset(outset, outset);
953 
954     int leftClampDelta = clamp.fLeft - iRect->fLeft;
955     if (leftClampDelta > 0) {
956         offset->fX -= outset - leftClampDelta;
957         iRect->fLeft = clamp.fLeft;
958     } else {
959         offset->fX -= outset;
960     }
961 
962     int topClampDelta = clamp.fTop - iRect->fTop;
963     if (topClampDelta > 0) {
964         offset->fY -= outset - topClampDelta;
965         iRect->fTop = clamp.fTop;
966     } else {
967         offset->fY -= outset;
968     }
969 
970     if (iRect->fRight > clamp.fRight) {
971         iRect->fRight = clamp.fRight;
972     }
973     if (iRect->fBottom > clamp.fBottom) {
974         iRect->fBottom = clamp.fBottom;
975     }
976 }
977 
978 // Break 'bitmap' into several tiles to draw it since it has already
979 // been determined to be too large to fit in VRAM
drawTiledBitmap(const SkBitmap & bitmap,const SkMatrix & viewMatrix,const SkRect & srcRect,const SkIRect & clippedSrcIRect,const GrTextureParams & params,const SkPaint & origPaint,SkCanvas::SrcRectConstraint constraint,int tileSize,bool bicubic)980 void SkGpuDevice::drawTiledBitmap(const SkBitmap& bitmap,
981                                   const SkMatrix& viewMatrix,
982                                   const SkRect& srcRect,
983                                   const SkIRect& clippedSrcIRect,
984                                   const GrTextureParams& params,
985                                   const SkPaint& origPaint,
986                                   SkCanvas::SrcRectConstraint constraint,
987                                   int tileSize,
988                                   bool bicubic) {
989     ASSERT_SINGLE_OWNER
990 
991     // This is the funnel for all paths that draw tiled bitmaps/images. Log histogram entry.
992     SK_HISTOGRAM_BOOLEAN("DrawTiled", true);
993 
994     // The following pixel lock is technically redundant, but it is desirable
995     // to lock outside of the tile loop to prevent redecoding the whole image
996     // at each tile in cases where 'bitmap' holds an SkDiscardablePixelRef that
997     // is larger than the limit of the discardable memory pool.
998     SkAutoLockPixels alp(bitmap);
999 
1000     const SkPaint* paint = &origPaint;
1001     SkPaint tempPaint;
1002     if (origPaint.isAntiAlias() && !fRenderTarget->isUnifiedMultisampled()) {
1003         // Drop antialiasing to avoid seams at tile boundaries.
1004         tempPaint = origPaint;
1005         tempPaint.setAntiAlias(false);
1006         paint = &tempPaint;
1007     }
1008     SkRect clippedSrcRect = SkRect::Make(clippedSrcIRect);
1009 
1010     int nx = bitmap.width() / tileSize;
1011     int ny = bitmap.height() / tileSize;
1012     for (int x = 0; x <= nx; x++) {
1013         for (int y = 0; y <= ny; y++) {
1014             SkRect tileR;
1015             tileR.set(SkIntToScalar(x * tileSize),
1016                       SkIntToScalar(y * tileSize),
1017                       SkIntToScalar((x + 1) * tileSize),
1018                       SkIntToScalar((y + 1) * tileSize));
1019 
1020             if (!SkRect::Intersects(tileR, clippedSrcRect)) {
1021                 continue;
1022             }
1023 
1024             if (!tileR.intersect(srcRect)) {
1025                 continue;
1026             }
1027 
1028             SkBitmap tmpB;
1029             SkIRect iTileR;
1030             tileR.roundOut(&iTileR);
1031             SkPoint offset = SkPoint::Make(SkIntToScalar(iTileR.fLeft),
1032                                            SkIntToScalar(iTileR.fTop));
1033 
1034             // Adjust the context matrix to draw at the right x,y in device space
1035             SkMatrix viewM = viewMatrix;
1036             SkMatrix tmpM;
1037             tmpM.setTranslate(offset.fX - srcRect.fLeft, offset.fY - srcRect.fTop);
1038             viewM.preConcat(tmpM);
1039 
1040             if (GrTextureParams::kNone_FilterMode != params.filterMode() || bicubic) {
1041                 SkIRect iClampRect;
1042 
1043                 if (SkCanvas::kFast_SrcRectConstraint == constraint) {
1044                     // In bleed mode we want to always expand the tile on all edges
1045                     // but stay within the bitmap bounds
1046                     iClampRect = SkIRect::MakeWH(bitmap.width(), bitmap.height());
1047                 } else {
1048                     // In texture-domain/clamp mode we only want to expand the
1049                     // tile on edges interior to "srcRect" (i.e., we want to
1050                     // not bleed across the original clamped edges)
1051                     srcRect.roundOut(&iClampRect);
1052                 }
1053                 int outset = bicubic ? GrBicubicEffect::kFilterTexelPad : 1;
1054                 clamped_outset_with_offset(&iTileR, outset, &offset, iClampRect);
1055             }
1056 
1057             if (bitmap.extractSubset(&tmpB, iTileR)) {
1058                 // now offset it to make it "local" to our tmp bitmap
1059                 tileR.offset(-offset.fX, -offset.fY);
1060                 GrTextureParams paramsTemp = params;
1061                 // de-optimized this determination
1062                 bool needsTextureDomain = true;
1063                 this->internalDrawBitmap(tmpB,
1064                                          viewM,
1065                                          tileR,
1066                                          paramsTemp,
1067                                          *paint,
1068                                          constraint,
1069                                          bicubic,
1070                                          needsTextureDomain);
1071             }
1072         }
1073     }
1074 }
1075 
1076 /*
1077  *  This is called by drawBitmap(), which has to handle images that may be too
1078  *  large to be represented by a single texture.
1079  *
1080  *  internalDrawBitmap assumes that the specified bitmap will fit in a texture
1081  *  and that non-texture portion of the GrPaint has already been setup.
1082  */
internalDrawBitmap(const SkBitmap & bitmap,const SkMatrix & viewMatrix,const SkRect & srcRect,const GrTextureParams & params,const SkPaint & paint,SkCanvas::SrcRectConstraint constraint,bool bicubic,bool needsTextureDomain)1083 void SkGpuDevice::internalDrawBitmap(const SkBitmap& bitmap,
1084                                      const SkMatrix& viewMatrix,
1085                                      const SkRect& srcRect,
1086                                      const GrTextureParams& params,
1087                                      const SkPaint& paint,
1088                                      SkCanvas::SrcRectConstraint constraint,
1089                                      bool bicubic,
1090                                      bool needsTextureDomain) {
1091     // We should have already handled bitmaps larger than the max texture size.
1092     SkASSERT(bitmap.width() <= fContext->caps()->maxTextureSize() &&
1093              bitmap.height() <= fContext->caps()->maxTextureSize());
1094     // Unless the bitmap is inherently texture-backed, we should be respecting the max tile size
1095     // by the time we get here.
1096     SkASSERT(bitmap.getTexture() ||
1097              (bitmap.width() <= fContext->caps()->maxTileSize() &&
1098               bitmap.height() <= fContext->caps()->maxTileSize()));
1099 
1100     GrTexture* texture;
1101     AutoBitmapTexture abt(fContext, bitmap, params, &texture);
1102     if (nullptr == texture) {
1103         return;
1104     }
1105 
1106     SkRect dstRect = {0, 0, srcRect.width(), srcRect.height() };
1107     SkRect paintRect;
1108     SkScalar wInv = SkScalarInvert(SkIntToScalar(texture->width()));
1109     SkScalar hInv = SkScalarInvert(SkIntToScalar(texture->height()));
1110     paintRect.setLTRB(SkScalarMul(srcRect.fLeft,   wInv),
1111                       SkScalarMul(srcRect.fTop,    hInv),
1112                       SkScalarMul(srcRect.fRight,  wInv),
1113                       SkScalarMul(srcRect.fBottom, hInv));
1114 
1115     SkMatrix texMatrix;
1116     texMatrix.reset();
1117     if (kAlpha_8_SkColorType == bitmap.colorType() && paint.getShader()) {
1118         // In cases where we are doing an A8 bitmap draw with a shader installed, we cannot use
1119         // local coords with the bitmap draw since it may mess up texture look ups for the shader.
1120         // Thus we need to pass in the transform matrix directly to the texture processor used for
1121         // the bitmap draw.
1122         texMatrix.setScale(wInv, hInv);
1123     }
1124 
1125     SkRect textureDomain = SkRect::MakeEmpty();
1126 
1127     // Construct a GrPaint by setting the bitmap texture as the first effect and then configuring
1128     // the rest from the SkPaint.
1129     SkAutoTUnref<const GrFragmentProcessor> fp;
1130 
1131     if (needsTextureDomain && (SkCanvas::kStrict_SrcRectConstraint == constraint)) {
1132         // Use a constrained texture domain to avoid color bleeding
1133         SkScalar left, top, right, bottom;
1134         if (srcRect.width() > SK_Scalar1) {
1135             SkScalar border = SK_ScalarHalf / texture->width();
1136             left = paintRect.left() + border;
1137             right = paintRect.right() - border;
1138         } else {
1139             left = right = SkScalarHalf(paintRect.left() + paintRect.right());
1140         }
1141         if (srcRect.height() > SK_Scalar1) {
1142             SkScalar border = SK_ScalarHalf / texture->height();
1143             top = paintRect.top() + border;
1144             bottom = paintRect.bottom() - border;
1145         } else {
1146             top = bottom = SkScalarHalf(paintRect.top() + paintRect.bottom());
1147         }
1148         textureDomain.setLTRB(left, top, right, bottom);
1149         if (bicubic) {
1150             fp.reset(GrBicubicEffect::Create(texture, texMatrix, textureDomain));
1151         } else {
1152             fp.reset(GrTextureDomainEffect::Create(texture,
1153                                                    texMatrix,
1154                                                    textureDomain,
1155                                                    GrTextureDomain::kClamp_Mode,
1156                                                    params.filterMode()));
1157         }
1158     } else if (bicubic) {
1159         SkASSERT(GrTextureParams::kNone_FilterMode == params.filterMode());
1160         SkShader::TileMode tileModes[2] = { params.getTileModeX(), params.getTileModeY() };
1161         fp.reset(GrBicubicEffect::Create(texture, texMatrix, tileModes));
1162     } else {
1163         fp.reset(GrSimpleTextureEffect::Create(texture, texMatrix, params));
1164     }
1165 
1166     GrPaint grPaint;
1167     if (!SkPaintToGrPaintWithTexture(this->context(), paint, viewMatrix, fp,
1168                                      kAlpha_8_SkColorType == bitmap.colorType(), &grPaint)) {
1169         return;
1170     }
1171 
1172     if (kAlpha_8_SkColorType == bitmap.colorType() && paint.getShader()) {
1173         // We don't have local coords in this case and have previously set the transform
1174         // matrices directly on the texture processor.
1175         fDrawContext->drawRect(fClip, grPaint, viewMatrix, dstRect);
1176     } else {
1177         fDrawContext->fillRectToRect(fClip, grPaint, viewMatrix, dstRect, paintRect);
1178     }
1179 }
1180 
filterTexture(GrContext * context,GrTexture * texture,int width,int height,const SkImageFilter * filter,const SkImageFilter::Context & ctx,SkBitmap * result,SkIPoint * offset)1181 bool SkGpuDevice::filterTexture(GrContext* context, GrTexture* texture,
1182                                 int width, int height,
1183                                 const SkImageFilter* filter,
1184                                 const SkImageFilter::Context& ctx,
1185                                 SkBitmap* result, SkIPoint* offset) {
1186     ASSERT_SINGLE_OWNER
1187     SkASSERT(filter);
1188 
1189     SkImageFilter::DeviceProxy proxy(this);
1190 
1191     if (filter->canFilterImageGPU()) {
1192         SkBitmap bm;
1193         GrWrapTextureInBitmap(texture, width, height, false, &bm);
1194         return filter->filterImageGPUDeprecated(&proxy, bm, ctx, result, offset);
1195     } else {
1196         return false;
1197     }
1198 }
1199 
drawSprite(const SkDraw & draw,const SkBitmap & bitmap,int left,int top,const SkPaint & paint)1200 void SkGpuDevice::drawSprite(const SkDraw& draw, const SkBitmap& bitmap,
1201                              int left, int top, const SkPaint& paint) {
1202     ASSERT_SINGLE_OWNER
1203     // drawSprite is defined to be in device coords.
1204     CHECK_SHOULD_DRAW(draw);
1205 
1206     SkAutoLockPixels alp(bitmap, !bitmap.getTexture());
1207     if (!bitmap.getTexture() && !bitmap.readyToDraw()) {
1208         return;
1209     }
1210 
1211     int w = bitmap.width();
1212     int h = bitmap.height();
1213 
1214     GrTexture* texture;
1215     // draw sprite neither filters nor tiles.
1216     AutoBitmapTexture abt(fContext, bitmap, GrTextureParams::ClampNoFilter(), &texture);
1217     if (!texture) {
1218         return;
1219     }
1220 
1221     bool alphaOnly = kAlpha_8_SkColorType == bitmap.colorType();
1222 
1223     SkImageFilter* filter = paint.getImageFilter();
1224     // This bitmap will own the filtered result as a texture.
1225     SkBitmap filteredBitmap;
1226 
1227     if (filter) {
1228         SkIPoint offset = SkIPoint::Make(0, 0);
1229         SkMatrix matrix(*draw.fMatrix);
1230         matrix.postTranslate(SkIntToScalar(-left), SkIntToScalar(-top));
1231         SkIRect clipBounds = draw.fClip->getBounds().makeOffset(-left, -top);
1232         SkAutoTUnref<SkImageFilter::Cache> cache(getImageFilterCache());
1233         // This cache is transient, and is freed (along with all its contained
1234         // textures) when it goes out of scope.
1235         SkImageFilter::Context ctx(matrix, clipBounds, cache);
1236         if (this->filterTexture(fContext, texture, w, h, filter, ctx, &filteredBitmap,
1237                                 &offset)) {
1238             texture = (GrTexture*) filteredBitmap.getTexture();
1239             w = filteredBitmap.width();
1240             h = filteredBitmap.height();
1241             left += offset.x();
1242             top += offset.y();
1243         } else {
1244             return;
1245         }
1246         SkASSERT(!GrPixelConfigIsAlphaOnly(texture->config()));
1247         alphaOnly = false;
1248     }
1249 
1250     GrPaint grPaint;
1251     SkAutoTUnref<const GrFragmentProcessor> fp(
1252         GrSimpleTextureEffect::Create(texture, SkMatrix::I()));
1253     if (alphaOnly) {
1254         fp.reset(GrFragmentProcessor::MulOutputByInputUnpremulColor(fp));
1255     } else {
1256         fp.reset(GrFragmentProcessor::MulOutputByInputAlpha(fp));
1257     }
1258     if (!SkPaintToGrPaintReplaceShader(this->context(), paint, fp, &grPaint)) {
1259         return;
1260     }
1261 
1262     fDrawContext->fillRectToRect(fClip,
1263                                  grPaint,
1264                                  SkMatrix::I(),
1265                                  SkRect::MakeXYWH(SkIntToScalar(left),
1266                                                   SkIntToScalar(top),
1267                                                   SkIntToScalar(w),
1268                                                   SkIntToScalar(h)),
1269                                  SkRect::MakeXYWH(0,
1270                                                   0,
1271                                                   SK_Scalar1 * w / texture->width(),
1272                                                   SK_Scalar1 * h / texture->height()));
1273 }
1274 
drawBitmapRect(const SkDraw & draw,const SkBitmap & bitmap,const SkRect * src,const SkRect & origDst,const SkPaint & paint,SkCanvas::SrcRectConstraint constraint)1275 void SkGpuDevice::drawBitmapRect(const SkDraw& draw, const SkBitmap& bitmap,
1276                                  const SkRect* src, const SkRect& origDst,
1277                                  const SkPaint& paint, SkCanvas::SrcRectConstraint constraint) {
1278     ASSERT_SINGLE_OWNER
1279     CHECK_SHOULD_DRAW(draw);
1280     if (bitmap.getTexture()) {
1281         GrBitmapTextureAdjuster adjuster(&bitmap);
1282         this->drawTextureProducer(&adjuster, src, &origDst, constraint, *draw.fMatrix, fClip,
1283                                   paint);
1284         return;
1285     }
1286     // The src rect is inferred to be the bmp bounds if not provided. Otherwise, the src rect must
1287     // be clipped to the bmp bounds. To determine tiling parameters we need the filter mode which
1288     // in turn requires knowing the src-to-dst mapping. If the src was clipped to the bmp bounds
1289     // then we use the src-to-dst mapping to compute a new clipped dst rect.
1290     const SkRect* dst = &origDst;
1291     const SkRect bmpBounds = SkRect::MakeIWH(bitmap.width(), bitmap.height());
1292     // Compute matrix from the two rectangles
1293     if (!src) {
1294         src = &bmpBounds;
1295     }
1296 
1297     SkMatrix srcToDstMatrix;
1298     if (!srcToDstMatrix.setRectToRect(*src, *dst, SkMatrix::kFill_ScaleToFit)) {
1299         return;
1300     }
1301     SkRect tmpSrc, tmpDst;
1302     if (src != &bmpBounds) {
1303         if (!bmpBounds.contains(*src)) {
1304             tmpSrc = *src;
1305             if (!tmpSrc.intersect(bmpBounds)) {
1306                 return; // nothing to draw
1307             }
1308             src = &tmpSrc;
1309             srcToDstMatrix.mapRect(&tmpDst, *src);
1310             dst = &tmpDst;
1311         }
1312     }
1313 
1314     int maxTileSize = fContext->caps()->maxTileSize();
1315 
1316     // The tile code path doesn't currently support AA, so if the paint asked for aa and we could
1317     // draw untiled, then we bypass checking for tiling purely for optimization reasons.
1318     bool drawAA = !fRenderTarget->isUnifiedMultisampled() &&
1319         paint.isAntiAlias() &&
1320         bitmap.width() <= maxTileSize &&
1321         bitmap.height() <= maxTileSize;
1322 
1323     bool skipTileCheck = drawAA || paint.getMaskFilter();
1324 
1325     if (!skipTileCheck) {
1326         int tileSize;
1327         SkIRect clippedSrcRect;
1328 
1329         GrTextureParams params;
1330         bool doBicubic;
1331         GrTextureParams::FilterMode textureFilterMode =
1332             GrSkFilterQualityToGrFilterMode(paint.getFilterQuality(), *draw.fMatrix, srcToDstMatrix,
1333                                             &doBicubic);
1334 
1335         int tileFilterPad;
1336 
1337         if (doBicubic) {
1338             tileFilterPad = GrBicubicEffect::kFilterTexelPad;
1339         } else if (GrTextureParams::kNone_FilterMode == textureFilterMode) {
1340             tileFilterPad = 0;
1341         } else {
1342             tileFilterPad = 1;
1343         }
1344         params.setFilterMode(textureFilterMode);
1345 
1346         int maxTileSizeForFilter = fContext->caps()->maxTileSize() - 2 * tileFilterPad;
1347         // Fold the dst rect into the view matrix. This is only OK because we don't get here if
1348         // we have a mask filter.
1349         SkMatrix viewMatrix = *draw.fMatrix;
1350         viewMatrix.preTranslate(dst->fLeft, dst->fTop);
1351         viewMatrix.preScale(dst->width()/src->width(), dst->height()/src->height());
1352         if (this->shouldTileBitmap(bitmap, viewMatrix, params, src,
1353                                    maxTileSizeForFilter, &tileSize, &clippedSrcRect)) {
1354             this->drawTiledBitmap(bitmap, viewMatrix, *src, clippedSrcRect, params, paint,
1355                                   constraint, tileSize, doBicubic);
1356             return;
1357         }
1358     }
1359     GrBitmapTextureMaker maker(fContext, bitmap);
1360     this->drawTextureProducer(&maker, src, dst, constraint, *draw.fMatrix, fClip, paint);
1361 }
1362 
drawDevice(const SkDraw & draw,SkBaseDevice * device,int x,int y,const SkPaint & paint)1363 void SkGpuDevice::drawDevice(const SkDraw& draw, SkBaseDevice* device,
1364                              int x, int y, const SkPaint& paint) {
1365     ASSERT_SINGLE_OWNER
1366     // clear of the source device must occur before CHECK_SHOULD_DRAW
1367     GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawDevice", fContext);
1368     SkGpuDevice* dev = static_cast<SkGpuDevice*>(device);
1369 
1370     // drawDevice is defined to be in device coords.
1371     CHECK_SHOULD_DRAW(draw);
1372 
1373     GrRenderTarget* devRT = dev->accessRenderTarget();
1374     GrTexture* devTex;
1375     if (nullptr == (devTex = devRT->asTexture())) {
1376         return;
1377     }
1378 
1379     const SkImageInfo ii = dev->imageInfo();
1380     int w = ii.width();
1381     int h = ii.height();
1382 
1383     SkImageFilter* filter = paint.getImageFilter();
1384     // This bitmap will own the filtered result as a texture.
1385     SkBitmap filteredBitmap;
1386 
1387     if (filter) {
1388         SkIPoint offset = SkIPoint::Make(0, 0);
1389         SkMatrix matrix(*draw.fMatrix);
1390         matrix.postTranslate(SkIntToScalar(-x), SkIntToScalar(-y));
1391         SkIRect clipBounds = draw.fClip->getBounds().makeOffset(-x, -y);
1392         // This cache is transient, and is freed (along with all its contained
1393         // textures) when it goes out of scope.
1394         SkAutoTUnref<SkImageFilter::Cache> cache(getImageFilterCache());
1395         SkImageFilter::Context ctx(matrix, clipBounds, cache);
1396         if (this->filterTexture(fContext, devTex, device->width(), device->height(),
1397                                 filter, ctx, &filteredBitmap, &offset)) {
1398             devTex = filteredBitmap.getTexture();
1399             w = filteredBitmap.width();
1400             h = filteredBitmap.height();
1401             x += offset.fX;
1402             y += offset.fY;
1403         } else {
1404             return;
1405         }
1406     }
1407 
1408     GrPaint grPaint;
1409     SkAutoTUnref<const GrFragmentProcessor> fp(
1410         GrSimpleTextureEffect::Create(devTex, SkMatrix::I()));
1411     if (GrPixelConfigIsAlphaOnly(devTex->config())) {
1412         // Can this happen?
1413         fp.reset(GrFragmentProcessor::MulOutputByInputUnpremulColor(fp));
1414    } else {
1415         fp.reset(GrFragmentProcessor::MulOutputByInputAlpha(fp));
1416     }
1417 
1418     if (!SkPaintToGrPaintReplaceShader(this->context(), paint, fp, &grPaint)) {
1419         return;
1420     }
1421 
1422     SkRect dstRect = SkRect::MakeXYWH(SkIntToScalar(x),
1423                                       SkIntToScalar(y),
1424                                       SkIntToScalar(w),
1425                                       SkIntToScalar(h));
1426 
1427     // The device being drawn may not fill up its texture (e.g. saveLayer uses approximate
1428     // scratch texture).
1429     SkRect srcRect = SkRect::MakeWH(SK_Scalar1 * w / devTex->width(),
1430                                     SK_Scalar1 * h / devTex->height());
1431 
1432     fDrawContext->fillRectToRect(fClip, grPaint, SkMatrix::I(), dstRect, srcRect);
1433 }
1434 
canHandleImageFilter(const SkImageFilter * filter)1435 bool SkGpuDevice::canHandleImageFilter(const SkImageFilter* filter) {
1436     ASSERT_SINGLE_OWNER
1437     return filter->canFilterImageGPU();
1438 }
1439 
filterImage(const SkImageFilter * filter,const SkBitmap & src,const SkImageFilter::Context & ctx,SkBitmap * result,SkIPoint * offset)1440 bool SkGpuDevice::filterImage(const SkImageFilter* filter, const SkBitmap& src,
1441                               const SkImageFilter::Context& ctx,
1442                               SkBitmap* result, SkIPoint* offset) {
1443     ASSERT_SINGLE_OWNER
1444     // want explicitly our impl, so guard against a subclass of us overriding it
1445     if (!this->SkGpuDevice::canHandleImageFilter(filter)) {
1446         return false;
1447     }
1448 
1449     SkAutoLockPixels alp(src, !src.getTexture());
1450     if (!src.getTexture() && !src.readyToDraw()) {
1451         return false;
1452     }
1453 
1454     GrTexture* texture;
1455     // We assume here that the filter will not attempt to tile the src. Otherwise, this cache lookup
1456     // must be pushed upstack.
1457     AutoBitmapTexture abt(fContext, src, GrTextureParams::ClampNoFilter(), &texture);
1458     if (!texture) {
1459         return false;
1460     }
1461 
1462     return this->filterTexture(fContext, texture, src.width(), src.height(),
1463                                filter, ctx, result, offset);
1464 }
1465 
drawImage(const SkDraw & draw,const SkImage * image,SkScalar x,SkScalar y,const SkPaint & paint)1466 void SkGpuDevice::drawImage(const SkDraw& draw, const SkImage* image, SkScalar x, SkScalar y,
1467                             const SkPaint& paint) {
1468     ASSERT_SINGLE_OWNER
1469     SkMatrix viewMatrix = *draw.fMatrix;
1470     viewMatrix.preTranslate(x, y);
1471     if (as_IB(image)->peekTexture()) {
1472         CHECK_SHOULD_DRAW(draw);
1473         GrImageTextureAdjuster adjuster(as_IB(image));
1474         this->drawTextureProducer(&adjuster, nullptr, nullptr, SkCanvas::kFast_SrcRectConstraint,
1475                                   viewMatrix, fClip, paint);
1476         return;
1477     } else {
1478         SkBitmap bm;
1479         if (this->shouldTileImage(image, nullptr, SkCanvas::kFast_SrcRectConstraint,
1480                                   paint.getFilterQuality(), *draw.fMatrix)) {
1481             // only support tiling as bitmap at the moment, so force raster-version
1482             if (!as_IB(image)->getROPixels(&bm)) {
1483                 return;
1484             }
1485             this->drawBitmap(draw, bm, SkMatrix::MakeTrans(x, y), paint);
1486         } else if (SkImageCacherator* cacher = as_IB(image)->peekCacherator()) {
1487             CHECK_SHOULD_DRAW(draw);
1488             GrImageTextureMaker maker(fContext, cacher, image, SkImage::kAllow_CachingHint);
1489             this->drawTextureProducer(&maker, nullptr, nullptr, SkCanvas::kFast_SrcRectConstraint,
1490                                       viewMatrix, fClip, paint);
1491         } else if (as_IB(image)->getROPixels(&bm)) {
1492             this->drawBitmap(draw, bm, SkMatrix::MakeTrans(x, y), paint);
1493         }
1494     }
1495 }
1496 
drawImageRect(const SkDraw & draw,const SkImage * image,const SkRect * src,const SkRect & dst,const SkPaint & paint,SkCanvas::SrcRectConstraint constraint)1497 void SkGpuDevice::drawImageRect(const SkDraw& draw, const SkImage* image, const SkRect* src,
1498                                 const SkRect& dst, const SkPaint& paint,
1499                                 SkCanvas::SrcRectConstraint constraint) {
1500     ASSERT_SINGLE_OWNER
1501     if (as_IB(image)->peekTexture()) {
1502         CHECK_SHOULD_DRAW(draw);
1503         GrImageTextureAdjuster adjuster(as_IB(image));
1504         this->drawTextureProducer(&adjuster, src, &dst, constraint, *draw.fMatrix, fClip, paint);
1505         return;
1506     }
1507     SkBitmap bm;
1508     SkMatrix totalMatrix = *draw.fMatrix;
1509     totalMatrix.preScale(dst.width() / (src ? src->width() : image->width()),
1510                          dst.height() / (src ? src->height() : image->height()));
1511     if (this->shouldTileImage(image, src, constraint, paint.getFilterQuality(), totalMatrix)) {
1512         // only support tiling as bitmap at the moment, so force raster-version
1513         if (!as_IB(image)->getROPixels(&bm)) {
1514             return;
1515         }
1516         this->drawBitmapRect(draw, bm, src, dst, paint, constraint);
1517     } else if (SkImageCacherator* cacher = as_IB(image)->peekCacherator()) {
1518         CHECK_SHOULD_DRAW(draw);
1519         GrImageTextureMaker maker(fContext, cacher, image, SkImage::kAllow_CachingHint);
1520         this->drawTextureProducer(&maker, src, &dst, constraint, *draw.fMatrix, fClip, paint);
1521     } else if (as_IB(image)->getROPixels(&bm)) {
1522         this->drawBitmapRect(draw, bm, src, dst, paint, constraint);
1523     }
1524 }
1525 
drawProducerNine(const SkDraw & draw,GrTextureProducer * producer,const SkIRect & center,const SkRect & dst,const SkPaint & paint)1526 void SkGpuDevice::drawProducerNine(const SkDraw& draw, GrTextureProducer* producer,
1527                                    const SkIRect& center, const SkRect& dst, const SkPaint& paint) {
1528     GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawProducerNine", fContext);
1529 
1530     CHECK_FOR_ANNOTATION(paint);
1531     CHECK_SHOULD_DRAW(draw);
1532 
1533     bool useFallback = paint.getMaskFilter() || paint.isAntiAlias() ||
1534                        fRenderTarget->isUnifiedMultisampled();
1535     bool doBicubic;
1536     GrTextureParams::FilterMode textureFilterMode =
1537         GrSkFilterQualityToGrFilterMode(paint.getFilterQuality(), *draw.fMatrix, SkMatrix::I(),
1538                                         &doBicubic);
1539     if (useFallback || doBicubic || GrTextureParams::kNone_FilterMode != textureFilterMode) {
1540         SkNinePatchIter iter(producer->width(), producer->height(), center, dst);
1541 
1542         SkRect srcR, dstR;
1543         while (iter.next(&srcR, &dstR)) {
1544             this->drawTextureProducer(producer, &srcR, &dstR, SkCanvas::kStrict_SrcRectConstraint,
1545                                       *draw.fMatrix, fClip, paint);
1546         }
1547         return;
1548     }
1549 
1550     static const GrTextureParams::FilterMode kMode = GrTextureParams::kNone_FilterMode;
1551     SkAutoTUnref<const GrFragmentProcessor> fp(
1552         producer->createFragmentProcessor(SkMatrix::I(),
1553                                           SkRect::MakeIWH(producer->width(), producer->height()),
1554                                           GrTextureProducer::kNo_FilterConstraint, true,
1555                                           &kMode));
1556     GrPaint grPaint;
1557     if (!SkPaintToGrPaintWithTexture(this->context(), paint, *draw.fMatrix, fp,
1558                                      producer->isAlphaOnly(), &grPaint)) {
1559         return;
1560     }
1561 
1562     fDrawContext->drawImageNine(fClip, grPaint, *draw.fMatrix, producer->width(),
1563                                 producer->height(), center, dst);
1564 }
1565 
drawImageNine(const SkDraw & draw,const SkImage * image,const SkIRect & center,const SkRect & dst,const SkPaint & paint)1566 void SkGpuDevice::drawImageNine(const SkDraw& draw, const SkImage* image,
1567                                 const SkIRect& center, const SkRect& dst, const SkPaint& paint) {
1568     ASSERT_SINGLE_OWNER
1569     if (as_IB(image)->peekTexture()) {
1570         GrImageTextureAdjuster adjuster(as_IB(image));
1571         this->drawProducerNine(draw, &adjuster, center, dst, paint);
1572     } else {
1573         SkBitmap bm;
1574         if (SkImageCacherator* cacher = as_IB(image)->peekCacherator()) {
1575             GrImageTextureMaker maker(fContext, cacher, image, SkImage::kAllow_CachingHint);
1576             this->drawProducerNine(draw, &maker, center, dst, paint);
1577         } else if (as_IB(image)->getROPixels(&bm)) {
1578             this->drawBitmapNine(draw, bm, center, dst, paint);
1579         }
1580     }
1581 }
1582 
drawBitmapNine(const SkDraw & draw,const SkBitmap & bitmap,const SkIRect & center,const SkRect & dst,const SkPaint & paint)1583 void SkGpuDevice::drawBitmapNine(const SkDraw& draw, const SkBitmap& bitmap, const SkIRect& center,
1584                                  const SkRect& dst, const SkPaint& paint) {
1585     ASSERT_SINGLE_OWNER
1586     if (bitmap.getTexture()) {
1587         GrBitmapTextureAdjuster adjuster(&bitmap);
1588         this->drawProducerNine(draw, &adjuster, center, dst, paint);
1589     } else {
1590         GrBitmapTextureMaker maker(fContext, bitmap);
1591         this->drawProducerNine(draw, &maker, center, dst, paint);
1592     }
1593 }
1594 
1595 ///////////////////////////////////////////////////////////////////////////////
1596 
1597 // must be in SkCanvas::VertexMode order
1598 static const GrPrimitiveType gVertexMode2PrimitiveType[] = {
1599     kTriangles_GrPrimitiveType,
1600     kTriangleStrip_GrPrimitiveType,
1601     kTriangleFan_GrPrimitiveType,
1602 };
1603 
drawVertices(const SkDraw & draw,SkCanvas::VertexMode vmode,int vertexCount,const SkPoint vertices[],const SkPoint texs[],const SkColor colors[],SkXfermode * xmode,const uint16_t indices[],int indexCount,const SkPaint & paint)1604 void SkGpuDevice::drawVertices(const SkDraw& draw, SkCanvas::VertexMode vmode,
1605                               int vertexCount, const SkPoint vertices[],
1606                               const SkPoint texs[], const SkColor colors[],
1607                               SkXfermode* xmode,
1608                               const uint16_t indices[], int indexCount,
1609                               const SkPaint& paint) {
1610     ASSERT_SINGLE_OWNER
1611     CHECK_SHOULD_DRAW(draw);
1612     GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawVertices", fContext);
1613 
1614     // If both textures and vertex-colors are nullptr, strokes hairlines with the paint's color.
1615     if ((nullptr == texs || nullptr == paint.getShader()) && nullptr == colors) {
1616 
1617         texs = nullptr;
1618 
1619         SkPaint copy(paint);
1620         copy.setStyle(SkPaint::kStroke_Style);
1621         copy.setStrokeWidth(0);
1622 
1623         GrPaint grPaint;
1624         // we ignore the shader if texs is null.
1625         if (!SkPaintToGrPaintNoShader(this->context(), copy, &grPaint)) {
1626             return;
1627         }
1628 
1629         int triangleCount = 0;
1630         int n = (nullptr == indices) ? vertexCount : indexCount;
1631         switch (vmode) {
1632             case SkCanvas::kTriangles_VertexMode:
1633                 triangleCount = n / 3;
1634                 break;
1635             case SkCanvas::kTriangleStrip_VertexMode:
1636             case SkCanvas::kTriangleFan_VertexMode:
1637                 triangleCount = n - 2;
1638                 break;
1639         }
1640 
1641         VertState       state(vertexCount, indices, indexCount);
1642         VertState::Proc vertProc = state.chooseProc(vmode);
1643 
1644         //number of indices for lines per triangle with kLines
1645         indexCount = triangleCount * 6;
1646 
1647         SkAutoTDeleteArray<uint16_t> lineIndices(new uint16_t[indexCount]);
1648         int i = 0;
1649         while (vertProc(&state)) {
1650             lineIndices[i]     = state.f0;
1651             lineIndices[i + 1] = state.f1;
1652             lineIndices[i + 2] = state.f1;
1653             lineIndices[i + 3] = state.f2;
1654             lineIndices[i + 4] = state.f2;
1655             lineIndices[i + 5] = state.f0;
1656             i += 6;
1657         }
1658         fDrawContext->drawVertices(fClip,
1659                                    grPaint,
1660                                    *draw.fMatrix,
1661                                    kLines_GrPrimitiveType,
1662                                    vertexCount,
1663                                    vertices,
1664                                    texs,
1665                                    colors,
1666                                    lineIndices.get(),
1667                                    indexCount);
1668         return;
1669     }
1670 
1671     GrPrimitiveType primType = gVertexMode2PrimitiveType[vmode];
1672 
1673     SkAutoSTMalloc<128, GrColor> convertedColors(0);
1674     if (colors) {
1675         // need to convert byte order and from non-PM to PM. TODO: Keep unpremul until after
1676         // interpolation.
1677         convertedColors.reset(vertexCount);
1678         for (int i = 0; i < vertexCount; ++i) {
1679             convertedColors[i] = SkColorToPremulGrColor(colors[i]);
1680         }
1681         colors = convertedColors.get();
1682     }
1683     GrPaint grPaint;
1684     if (texs && paint.getShader()) {
1685         if (colors) {
1686             // When there are texs and colors the shader and colors are combined using xmode. A null
1687             // xmode is defined to mean modulate.
1688             SkXfermode::Mode colorMode;
1689             if (xmode) {
1690                 if (!xmode->asMode(&colorMode)) {
1691                     return;
1692                 }
1693             } else {
1694                 colorMode = SkXfermode::kModulate_Mode;
1695             }
1696             if (!SkPaintToGrPaintWithXfermode(this->context(), paint, *draw.fMatrix, colorMode,
1697                                               false, &grPaint)) {
1698                 return;
1699             }
1700         } else {
1701             // We have a shader, but no colors to blend it against.
1702             if (!SkPaintToGrPaint(this->context(), paint, *draw.fMatrix, &grPaint)) {
1703                 return;
1704             }
1705         }
1706     } else {
1707         if (colors) {
1708             // We have colors, but either have no shader or no texture coords (which implies that
1709             // we should ignore the shader).
1710             if (!SkPaintToGrPaintWithPrimitiveColor(this->context(), paint, &grPaint)) {
1711                 return;
1712             }
1713         } else {
1714             // No colors and no shaders. Just draw with the paint color.
1715             if (!SkPaintToGrPaintNoShader(this->context(), paint, &grPaint)) {
1716                 return;
1717             }
1718         }
1719     }
1720 
1721     fDrawContext->drawVertices(fClip,
1722                                grPaint,
1723                                *draw.fMatrix,
1724                                primType,
1725                                vertexCount,
1726                                vertices,
1727                                texs,
1728                                colors,
1729                                indices,
1730                                indexCount);
1731 }
1732 
1733 ///////////////////////////////////////////////////////////////////////////////
1734 
drawAtlas(const SkDraw & draw,const SkImage * atlas,const SkRSXform xform[],const SkRect texRect[],const SkColor colors[],int count,SkXfermode::Mode mode,const SkPaint & paint)1735 void SkGpuDevice::drawAtlas(const SkDraw& draw, const SkImage* atlas, const SkRSXform xform[],
1736                             const SkRect texRect[], const SkColor colors[], int count,
1737                             SkXfermode::Mode mode, const SkPaint& paint) {
1738     ASSERT_SINGLE_OWNER
1739     if (paint.isAntiAlias()) {
1740         this->INHERITED::drawAtlas(draw, atlas, xform, texRect, colors, count, mode, paint);
1741         return;
1742     }
1743 
1744     CHECK_SHOULD_DRAW(draw);
1745     GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawText", fContext);
1746 
1747     SkPaint p(paint);
1748     p.setShader(atlas->newShader(SkShader::kClamp_TileMode, SkShader::kClamp_TileMode))->unref();
1749 
1750     GrPaint grPaint;
1751     if (colors) {
1752         if (!SkPaintToGrPaintWithXfermode(this->context(), p, *draw.fMatrix, mode, true,
1753                                           &grPaint)) {
1754             return;
1755         }
1756     } else {
1757         if (!SkPaintToGrPaint(this->context(), p, *draw.fMatrix, &grPaint)) {
1758             return;
1759         }
1760     }
1761 
1762     SkDEBUGCODE(this->validate();)
1763     fDrawContext->drawAtlas(fClip, grPaint, *draw.fMatrix, count, xform, texRect, colors);
1764 }
1765 
1766 ///////////////////////////////////////////////////////////////////////////////
1767 
drawText(const SkDraw & draw,const void * text,size_t byteLength,SkScalar x,SkScalar y,const SkPaint & paint)1768 void SkGpuDevice::drawText(const SkDraw& draw, const void* text,
1769                            size_t byteLength, SkScalar x, SkScalar y,
1770                            const SkPaint& paint) {
1771     ASSERT_SINGLE_OWNER
1772     CHECK_SHOULD_DRAW(draw);
1773     GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawText", fContext);
1774 
1775     GrPaint grPaint;
1776     if (!SkPaintToGrPaint(this->context(), paint, *draw.fMatrix, &grPaint)) {
1777         return;
1778     }
1779 
1780     SkDEBUGCODE(this->validate();)
1781 
1782     fDrawContext->drawText(fClip, grPaint, paint, *draw.fMatrix,
1783                            (const char *)text, byteLength, x, y, draw.fClip->getBounds());
1784 }
1785 
drawPosText(const SkDraw & draw,const void * text,size_t byteLength,const SkScalar pos[],int scalarsPerPos,const SkPoint & offset,const SkPaint & paint)1786 void SkGpuDevice::drawPosText(const SkDraw& draw, const void* text, size_t byteLength,
1787                               const SkScalar pos[], int scalarsPerPos,
1788                               const SkPoint& offset, const SkPaint& paint) {
1789     ASSERT_SINGLE_OWNER
1790     GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawPosText", fContext);
1791     CHECK_SHOULD_DRAW(draw);
1792 
1793     GrPaint grPaint;
1794     if (!SkPaintToGrPaint(this->context(), paint, *draw.fMatrix, &grPaint)) {
1795         return;
1796     }
1797 
1798     SkDEBUGCODE(this->validate();)
1799 
1800     fDrawContext->drawPosText(fClip, grPaint, paint, *draw.fMatrix,
1801                               (const char *)text, byteLength, pos, scalarsPerPos, offset,
1802                               draw.fClip->getBounds());
1803 }
1804 
drawTextBlob(const SkDraw & draw,const SkTextBlob * blob,SkScalar x,SkScalar y,const SkPaint & paint,SkDrawFilter * drawFilter)1805 void SkGpuDevice::drawTextBlob(const SkDraw& draw, const SkTextBlob* blob, SkScalar x, SkScalar y,
1806                                const SkPaint& paint, SkDrawFilter* drawFilter) {
1807     ASSERT_SINGLE_OWNER
1808     GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawTextBlob", fContext);
1809     CHECK_SHOULD_DRAW(draw);
1810 
1811     SkDEBUGCODE(this->validate();)
1812 
1813     fDrawContext->drawTextBlob(fClip, paint, *draw.fMatrix,
1814                                blob, x, y, drawFilter, draw.fClip->getBounds());
1815 }
1816 
1817 ///////////////////////////////////////////////////////////////////////////////
1818 
onShouldDisableLCD(const SkPaint & paint) const1819 bool SkGpuDevice::onShouldDisableLCD(const SkPaint& paint) const {
1820     return GrTextUtils::ShouldDisableLCD(paint);
1821 }
1822 
flush()1823 void SkGpuDevice::flush() {
1824     ASSERT_SINGLE_OWNER
1825 
1826     fRenderTarget->prepareForExternalIO();
1827 }
1828 
1829 ///////////////////////////////////////////////////////////////////////////////
1830 
onCreateDevice(const CreateInfo & cinfo,const SkPaint *)1831 SkBaseDevice* SkGpuDevice::onCreateDevice(const CreateInfo& cinfo, const SkPaint*) {
1832     ASSERT_SINGLE_OWNER
1833     GrSurfaceDesc desc;
1834     desc.fConfig = fRenderTarget->config();
1835     desc.fFlags = kRenderTarget_GrSurfaceFlag;
1836     desc.fWidth = cinfo.fInfo.width();
1837     desc.fHeight = cinfo.fInfo.height();
1838     desc.fSampleCnt = fRenderTarget->desc().fSampleCnt;
1839 
1840     SkAutoTUnref<GrTexture> texture;
1841     // Skia's convention is to only clear a device if it is non-opaque.
1842     InitContents init = cinfo.fInfo.isOpaque() ? kUninit_InitContents : kClear_InitContents;
1843 
1844     // layers are never draw in repeat modes, so we can request an approx
1845     // match and ignore any padding.
1846     if (kNever_TileUsage == cinfo.fTileUsage) {
1847         texture.reset(fContext->textureProvider()->createApproxTexture(desc));
1848     } else {
1849         texture.reset(fContext->textureProvider()->createTexture(desc, SkBudgeted::kYes));
1850     }
1851 
1852     if (texture) {
1853         SkSurfaceProps props(this->surfaceProps().flags(), cinfo.fPixelGeometry);
1854         return SkGpuDevice::Create(
1855             texture->asRenderTarget(), cinfo.fInfo.width(), cinfo.fInfo.height(), &props, init);
1856     } else {
1857         SkErrorInternals::SetError( kInternalError_SkError,
1858                                     "---- failed to create gpu device texture [%d %d]\n",
1859                                     cinfo.fInfo.width(), cinfo.fInfo.height());
1860         return nullptr;
1861     }
1862 }
1863 
newSurface(const SkImageInfo & info,const SkSurfaceProps & props)1864 SkSurface* SkGpuDevice::newSurface(const SkImageInfo& info, const SkSurfaceProps& props) {
1865     ASSERT_SINGLE_OWNER
1866     // TODO: Change the signature of newSurface to take a budgeted parameter.
1867     static const SkBudgeted kBudgeted = SkBudgeted::kNo;
1868     return SkSurface::NewRenderTarget(fContext, kBudgeted, info, fRenderTarget->desc().fSampleCnt,
1869                                       &props);
1870 }
1871 
EXPERIMENTAL_drawPicture(SkCanvas * mainCanvas,const SkPicture * mainPicture,const SkMatrix * matrix,const SkPaint * paint)1872 bool SkGpuDevice::EXPERIMENTAL_drawPicture(SkCanvas* mainCanvas, const SkPicture* mainPicture,
1873                                            const SkMatrix* matrix, const SkPaint* paint) {
1874     ASSERT_SINGLE_OWNER
1875 #ifndef SK_IGNORE_GPU_LAYER_HOISTING
1876     // todo: should handle this natively
1877     if (paint) {
1878         return false;
1879     }
1880 
1881     const SkBigPicture::AccelData* data = nullptr;
1882     if (const SkBigPicture* bp = mainPicture->asSkBigPicture()) {
1883         data = bp->accelData();
1884     }
1885     if (!data) {
1886         return false;
1887     }
1888 
1889     const SkLayerInfo *gpuData = static_cast<const SkLayerInfo*>(data);
1890     if (0 == gpuData->numBlocks()) {
1891         return false;
1892     }
1893 
1894     SkTDArray<GrHoistedLayer> atlasedNeedRendering, atlasedRecycled;
1895 
1896     SkIRect iBounds;
1897     if (!mainCanvas->getClipDeviceBounds(&iBounds)) {
1898         return false;
1899     }
1900 
1901     SkRect clipBounds = SkRect::Make(iBounds);
1902 
1903     SkMatrix initialMatrix = mainCanvas->getTotalMatrix();
1904 
1905     GrLayerHoister::Begin(fContext);
1906 
1907     GrLayerHoister::FindLayersToAtlas(fContext, mainPicture,
1908                                       initialMatrix,
1909                                       clipBounds,
1910                                       &atlasedNeedRendering, &atlasedRecycled,
1911                                       fRenderTarget->numColorSamples());
1912 
1913     GrLayerHoister::DrawLayersToAtlas(fContext, atlasedNeedRendering);
1914 
1915     SkTDArray<GrHoistedLayer> needRendering, recycled;
1916 
1917     SkAutoCanvasMatrixPaint acmp(mainCanvas, matrix, paint, mainPicture->cullRect());
1918 
1919     GrLayerHoister::FindLayersToHoist(fContext, mainPicture,
1920                                       initialMatrix,
1921                                       clipBounds,
1922                                       &needRendering, &recycled,
1923                                       fRenderTarget->numColorSamples());
1924 
1925     GrLayerHoister::DrawLayers(fContext, needRendering);
1926 
1927     // Render the entire picture using new layers
1928     GrRecordReplaceDraw(mainPicture, mainCanvas, fContext->getLayerCache(),
1929                         initialMatrix, nullptr);
1930 
1931     GrLayerHoister::UnlockLayers(fContext, needRendering);
1932     GrLayerHoister::UnlockLayers(fContext, recycled);
1933     GrLayerHoister::UnlockLayers(fContext, atlasedNeedRendering);
1934     GrLayerHoister::UnlockLayers(fContext, atlasedRecycled);
1935     GrLayerHoister::End(fContext);
1936 
1937     return true;
1938 #else
1939     return false;
1940 #endif
1941 }
1942 
NewImageFilterCache()1943 SkImageFilter::Cache* SkGpuDevice::NewImageFilterCache() {
1944     return SkImageFilter::Cache::Create(kDefaultImageFilterCacheSize);
1945 }
1946 
getImageFilterCache()1947 SkImageFilter::Cache* SkGpuDevice::getImageFilterCache() {
1948     ASSERT_SINGLE_OWNER
1949     // We always return a transient cache, so it is freed after each
1950     // filter traversal.
1951     return SkGpuDevice::NewImageFilterCache();
1952 }
1953 
1954 #endif
1955